Merge pull request #132049 from googs1025/fix/data_race_patch
fix: data race for patchResource func Kubernetes-commit: 0a51ae22542b6e78fec51a573d95a922592f8273
This commit is contained in:
commit
3637a3a5aa
2
go.mod
2
go.mod
|
|
@ -124,3 +124,5 @@ require (
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace k8s.io/client-go => k8s.io/client-go v0.0.0-20250702155524-6980728f27f4
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -301,8 +301,8 @@ k8s.io/api v0.0.0-20250702170451-bfa25161ab14 h1:ru1qVDjtx6BP62PQjJ+Wl9raUn0a8nj
|
||||||
k8s.io/api v0.0.0-20250702170451-bfa25161ab14/go.mod h1:K0G717YoOyRoxuW09o2hgVeUK6NK3vcAzQBtcQRnL9o=
|
k8s.io/api v0.0.0-20250702170451-bfa25161ab14/go.mod h1:K0G717YoOyRoxuW09o2hgVeUK6NK3vcAzQBtcQRnL9o=
|
||||||
k8s.io/apimachinery v0.0.0-20250702170156-7548d4da2f38 h1:8O5idX0pTbbeSayup4l3BUsPhHYxITx/6XFc149kAJw=
|
k8s.io/apimachinery v0.0.0-20250702170156-7548d4da2f38 h1:8O5idX0pTbbeSayup4l3BUsPhHYxITx/6XFc149kAJw=
|
||||||
k8s.io/apimachinery v0.0.0-20250702170156-7548d4da2f38/go.mod h1:RkaUIZxsmnceX2hEfn44FGiTXiv/8cUWaqjCh1kDzZg=
|
k8s.io/apimachinery v0.0.0-20250702170156-7548d4da2f38/go.mod h1:RkaUIZxsmnceX2hEfn44FGiTXiv/8cUWaqjCh1kDzZg=
|
||||||
k8s.io/client-go v0.0.0-20250702170847-0746d1b7322b h1:XzzMTQNm3JMz6dh3c5oJbRfPO5Np0+SQcI8Q+ADq7Sg=
|
k8s.io/client-go v0.0.0-20250702155524-6980728f27f4 h1:YvA2fLi5nrfeeQdq9A0Cp8bTUqXU8ltCTjKNHgNTwDQ=
|
||||||
k8s.io/client-go v0.0.0-20250702170847-0746d1b7322b/go.mod h1:jmp8BGXr3fP6+ho7p/Bf+Of4YND9LrF1B1a+zlgpS0k=
|
k8s.io/client-go v0.0.0-20250702155524-6980728f27f4/go.mod h1:jmp8BGXr3fP6+ho7p/Bf+Of4YND9LrF1B1a+zlgpS0k=
|
||||||
k8s.io/component-base v0.0.0-20250702172159-a7fbca963794 h1:cLqIWi8ntbwsZPPskQ7OpluDkZFQkFdeKrkiv4HSuwk=
|
k8s.io/component-base v0.0.0-20250702172159-a7fbca963794 h1:cLqIWi8ntbwsZPPskQ7OpluDkZFQkFdeKrkiv4HSuwk=
|
||||||
k8s.io/component-base v0.0.0-20250702172159-a7fbca963794/go.mod h1:pQj4ARJ2y3YY/TinuQWxpU0A7bWNZxKbMusfiSHV3mA=
|
k8s.io/component-base v0.0.0-20250702172159-a7fbca963794/go.mod h1:pQj4ARJ2y3YY/TinuQWxpU0A7bWNZxKbMusfiSHV3mA=
|
||||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
|
|
|
||||||
|
|
@ -726,6 +726,14 @@ func (p *patcher) patchResource(ctx context.Context, scope *RequestScope) (runti
|
||||||
}
|
}
|
||||||
return result, err
|
return result, err
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// In case of a timeout error, the goroutine handling the request is still running.
|
||||||
|
// https://github.com/kubernetes/kubernetes/blob/d2c12afa4593e50a187075157d38748292b02733/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/finisher/finisher.go#L127-L146
|
||||||
|
// We cannot reliably read the variable (data race!) and have to assume that
|
||||||
|
// the object was not created.
|
||||||
|
if errors.IsTimeout(err) {
|
||||||
|
return result, false, err
|
||||||
|
}
|
||||||
return result, wasCreated, err
|
return result, wasCreated, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -323,6 +323,25 @@ func TestPatchCustomResource(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testTimeoutPatcher struct {
|
||||||
|
t *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *testTimeoutPatcher) New() runtime.Object {
|
||||||
|
return &example.Pod{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *testTimeoutPatcher) Update(ctx context.Context, _ string, _ rest.UpdatedObjectInfo, _ rest.ValidateObjectFunc, _ rest.ValidateObjectUpdateFunc, _ bool, _ *metav1.UpdateOptions) (runtime.Object, bool, error) {
|
||||||
|
// Block until the context is canceled to simulate a timeout scenario.
|
||||||
|
<-ctx.Done()
|
||||||
|
return nil, false, ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *testTimeoutPatcher) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||||
|
p.t.Fatal("unexpected call to testPatcher.Get")
|
||||||
|
return nil, errors.New("unexpected call to testPatcher.Get")
|
||||||
|
}
|
||||||
|
|
||||||
type testPatcher struct {
|
type testPatcher struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
|
|
||||||
|
|
@ -432,6 +451,9 @@ type patchTestCase struct {
|
||||||
expectedError string
|
expectedError string
|
||||||
// if set, indicates the number of times patching was expected to be attempted
|
// if set, indicates the number of times patching was expected to be attempted
|
||||||
expectedTries int
|
expectedTries int
|
||||||
|
|
||||||
|
// isTimeout for this test case
|
||||||
|
isTimeout bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *patchTestCase) Run(t *testing.T) {
|
func (tc *patchTestCase) Run(t *testing.T) {
|
||||||
|
|
@ -564,8 +586,16 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
||||||
FieldManager: "test-manager",
|
FieldManager: "test-manager",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
var timeout time.Duration
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
if tc.isTimeout {
|
||||||
|
// Simulate timeout by using a zero-duration timeout and the timeout patcher
|
||||||
|
// replace testPatcher with the timeout simulator
|
||||||
|
timeout = 0
|
||||||
|
p.restPatcher = &testTimeoutPatcher{t: t}
|
||||||
|
} else {
|
||||||
|
timeout = time.Second
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
resultObj, _, err := p.patchResource(ctx, &RequestScope{
|
resultObj, _, err := p.patchResource(ctx, &RequestScope{
|
||||||
FieldManager: fieldmanager,
|
FieldManager: fieldmanager,
|
||||||
})
|
})
|
||||||
|
|
@ -679,6 +709,20 @@ func TestPatchResourceNumberConversion(t *testing.T) {
|
||||||
tc.Run(t)
|
tc.Run(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPatchResourceTimeout(t *testing.T) {
|
||||||
|
tc := &patchTestCase{
|
||||||
|
name: "TestPatchResourceTimeout",
|
||||||
|
startingPod: &example.Pod{},
|
||||||
|
changedPod: &example.Pod{},
|
||||||
|
updatePod: &example.Pod{},
|
||||||
|
expectedPod: nil,
|
||||||
|
isTimeout: true,
|
||||||
|
expectedError: "Timeout: request did not complete within requested timeout - context deadline exceeded",
|
||||||
|
}
|
||||||
|
|
||||||
|
tc.Run(t)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPatchResourceWithVersionConflict(t *testing.T) {
|
func TestPatchResourceWithVersionConflict(t *testing.T) {
|
||||||
namespace := "bar"
|
namespace := "bar"
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue