Skip to content

Commit cc49b34

Browse files
author
Kubernetes Submit Queue
authored
Merge pull request kubernetes#53586 from sttts/sttts-storage-shutdown
Automatic merge from submit-queue (batch tested with PRs 53249, 53586). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. apiextensions-apiserver: stop cacher on CRD update Potentially fixes kubernetes#53485
2 parents fd57b1c + 333f49f commit cc49b34

File tree

3 files changed

+45
-13
lines changed

3 files changed

+45
-13
lines changed

staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ go_library(
3333
"//vendor/k8s.io/apiextensions-apiserver/pkg/controller/status:go_default_library",
3434
"//vendor/k8s.io/apiextensions-apiserver/pkg/registry/customresource:go_default_library",
3535
"//vendor/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition:go_default_library",
36+
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
3637
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
3738
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
3839
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",

staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/go-openapi/validate"
3131
"github.com/golang/glog"
3232

33+
apiequality "k8s.io/apimachinery/pkg/api/equality"
3334
apierrors "k8s.io/apimachinery/pkg/api/errors"
3435
"k8s.io/apimachinery/pkg/api/meta"
3536
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -79,6 +80,11 @@ type crdHandler struct {
7980

8081
// crdInfo stores enough information to serve the storage for the custom resource
8182
type crdInfo struct {
83+
// spec and acceptedNames are used to compare against if a change is made on a CRD. We only update
84+
// the storage if one of these changes.
85+
spec *apiextensions.CustomResourceDefinitionSpec
86+
acceptedNames *apiextensions.CustomResourceDefinitionNames
87+
8288
storage *customresource.REST
8389
requestScope handlers.RequestScope
8490
}
@@ -108,6 +114,9 @@ func NewCustomResourceDefinitionHandler(
108114

109115
crdInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
110116
UpdateFunc: ret.updateCustomResourceDefinition,
117+
DeleteFunc: func(obj interface{}) {
118+
ret.removeDeadStorage()
119+
},
111120
})
112121

113122
ret.customStorage.Store(crdStorageMap{})
@@ -245,7 +254,7 @@ func (r *crdHandler) removeDeadStorage() {
245254
return
246255
}
247256

248-
for uid := range storageMap {
257+
for uid, s := range storageMap {
249258
found := false
250259
for _, crd := range allCustomResourceDefinitions {
251260
if crd.UID == uid {
@@ -254,6 +263,8 @@ func (r *crdHandler) removeDeadStorage() {
254263
}
255264
}
256265
if !found {
266+
glog.V(4).Infof("Removing dead CRD storage for %v", s.requestScope.Resource)
267+
s.storage.DestroyFunc()
257268
delete(storageMap, uid)
258269
}
259270
}
@@ -301,7 +312,7 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
301312
parameterScheme.AddGeneratedDeepCopyFuncs(metav1.GetGeneratedDeepCopyFuncs()...)
302313
parameterCodec := runtime.NewParameterCodec(parameterScheme)
303314

304-
kind := schema.GroupVersionKind{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Spec.Names.Kind}
315+
kind := schema.GroupVersionKind{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Status.AcceptedNames.Kind}
305316
typer := unstructuredObjectTyper{
306317
delegate: parameterScheme,
307318
unstructuredTyper: discovery.NewUnstructuredObjectTyper(nil),
@@ -319,8 +330,8 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
319330
validator := validate.NewSchemaValidator(openapiSchema, nil, "", strfmt.Default)
320331

321332
storage := customresource.NewREST(
322-
schema.GroupResource{Group: crd.Spec.Group, Resource: crd.Spec.Names.Plural},
323-
schema.GroupVersionKind{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Spec.Names.ListKind},
333+
schema.GroupResource{Group: crd.Spec.Group, Resource: crd.Status.AcceptedNames.Plural},
334+
schema.GroupVersionKind{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Status.AcceptedNames.ListKind},
324335
customresource.NewStrategy(
325336
typer,
326337
crd.Spec.Scope == apiextensions.NamespaceScoped,
@@ -367,14 +378,17 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
367378
Typer: typer,
368379
UnsafeConvertor: unstructured.UnstructuredObjectConverter{},
369380

370-
Resource: schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural},
381+
Resource: schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Status.AcceptedNames.Plural},
371382
Kind: kind,
372383
Subresource: "",
373384

374385
MetaGroupVersion: metav1.SchemeGroupVersion,
375386
}
376387

377388
ret = &crdInfo{
389+
spec: &crd.Spec,
390+
acceptedNames: &crd.Status.AcceptedNames,
391+
378392
storage: storage,
379393
requestScope: requestScope,
380394
}
@@ -410,23 +424,36 @@ func (c crdObjectConverter) ConvertFieldLabel(version, kind, label, value string
410424
}
411425
}
412426

413-
func (c *crdHandler) updateCustomResourceDefinition(oldObj, _ interface{}) {
427+
func (c *crdHandler) updateCustomResourceDefinition(oldObj, newObj interface{}) {
414428
oldCRD := oldObj.(*apiextensions.CustomResourceDefinition)
415-
glog.V(4).Infof("Updating customresourcedefinition %s", oldCRD.Name)
429+
newCRD := newObj.(*apiextensions.CustomResourceDefinition)
416430

417431
c.customStorageLock.Lock()
418432
defer c.customStorageLock.Unlock()
419-
420433
storageMap := c.customStorage.Load().(crdStorageMap)
434+
435+
oldInfo, found := storageMap[newCRD.UID]
436+
if !found {
437+
return
438+
}
439+
if apiequality.Semantic.DeepEqual(&newCRD.Spec, oldInfo.spec) && apiequality.Semantic.DeepEqual(&newCRD.Status.AcceptedNames, oldInfo.acceptedNames) {
440+
glog.V(6).Infof("Ignoring customresourcedefinition %s update because neither spec, nor accepted names changed", oldCRD.Name)
441+
return
442+
}
443+
444+
glog.V(4).Infof("Updating customresourcedefinition %s", oldCRD.Name)
421445
storageMap2 := make(crdStorageMap, len(storageMap))
422446

423447
// Copy because we cannot write to storageMap without a race
424448
// as it is used without locking elsewhere
425449
for k, v := range storageMap {
450+
if k == oldCRD.UID {
451+
v.storage.DestroyFunc()
452+
continue
453+
}
426454
storageMap2[k] = v
427455
}
428456

429-
delete(storageMap2, oldCRD.UID)
430457
c.customStorage.Store(storageMap2)
431458
}
432459

staging/src/k8s.io/apiextensions-apiserver/test/integration/validation_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"testing"
2222
"time"
2323

24+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2425
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2526
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2627
"k8s.io/apimachinery/pkg/util/wait"
@@ -379,15 +380,18 @@ func TestCRValidationOnCRDUpdate(t *testing.T) {
379380

380381
// update the CRD to a less stricter schema
381382
gottenCRD.Spec.Validation.OpenAPIV3Schema.Required = []string{"alpha", "beta"}
382-
383-
updatedCRD, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(gottenCRD)
384-
if err != nil {
383+
if _, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(gottenCRD); err != nil {
385384
t.Fatal(err)
386385
}
387386

388387
// CR is now accepted
389388
err = wait.Poll(500*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
390-
_, err = instantiateCustomResource(t, newNoxuValidationInstance(ns, "foo"), noxuResourceClient, updatedCRD)
389+
_, err := noxuResourceClient.Create(newNoxuValidationInstance(ns, "foo"))
390+
if statusError, isStatus := err.(*apierrors.StatusError); isStatus {
391+
if strings.Contains(statusError.Error(), "is invalid") {
392+
return false, nil
393+
}
394+
}
391395
if err != nil {
392396
return false, err
393397
}

0 commit comments

Comments
 (0)