From 5c354615e08e7711c1be03ac7ef6e43178f2e80f Mon Sep 17 00:00:00 2001 From: Nikhita Raghunath Date: Wed, 16 Aug 2017 17:54:48 +0530 Subject: [PATCH] update CRD strategy for status updates 1. Clear the status of the CRD and set the Generation before creation. 2. While updating the CRD: - ignore changes on status. - increase Generation if spec changes. 3. Don't update objectmeta when status is updated. - however, update finalizers. Without this, deletion will timeout. --- .../pkg/registry/customresource/etcd.go | 4 +-- .../pkg/registry/customresource/strategy.go | 26 +++++++++---------- .../registry/customresourcedefinition/BUILD | 1 + .../customresourcedefinition/strategy.go | 24 +++++++++++++++++ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd.go index 6abd528354bb3..5f953b1c699a5 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd.go @@ -24,13 +24,13 @@ import ( genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" ) -// rest implements a RESTStorage for API services against etcd +// REST implements a RESTStorage for API services against etcd type REST struct { *genericregistry.Store } // NewREST returns a RESTStorage object that will work against API services. -func NewREST(resource schema.GroupResource, listKind schema.GroupVersionKind, copier runtime.ObjectCopier, strategy CustomResourceDefinitionStorageStrategy, optsGetter generic.RESTOptionsGetter) *REST { +func NewREST(resource schema.GroupResource, listKind schema.GroupVersionKind, copier runtime.ObjectCopier, strategy customResourceDefinitionStorageStrategy, optsGetter generic.RESTOptionsGetter) *REST { store := &genericregistry.Store{ Copier: copier, NewFunc: func() runtime.Object { return &unstructured.Unstructured{} }, diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/strategy.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/strategy.go index 8ebc90c179970..6b97d07531a78 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/strategy.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/strategy.go @@ -32,7 +32,7 @@ import ( "k8s.io/apiserver/pkg/storage/names" ) -type CustomResourceDefinitionStorageStrategy struct { +type customResourceDefinitionStorageStrategy struct { runtime.ObjectTyper names.NameGenerator @@ -40,8 +40,8 @@ type CustomResourceDefinitionStorageStrategy struct { validator customResourceValidator } -func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.GroupVersionKind) CustomResourceDefinitionStorageStrategy { - return CustomResourceDefinitionStorageStrategy{ +func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.GroupVersionKind) customResourceDefinitionStorageStrategy { + return customResourceDefinitionStorageStrategy{ ObjectTyper: typer, NameGenerator: names.SimpleNameGenerator, namespaceScoped: namespaceScoped, @@ -52,36 +52,36 @@ func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.Gr } } -func (a CustomResourceDefinitionStorageStrategy) NamespaceScoped() bool { +func (a customResourceDefinitionStorageStrategy) NamespaceScoped() bool { return a.namespaceScoped } -func (CustomResourceDefinitionStorageStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { +func (customResourceDefinitionStorageStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { } -func (CustomResourceDefinitionStorageStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { +func (customResourceDefinitionStorageStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { } -func (a CustomResourceDefinitionStorageStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList { +func (a customResourceDefinitionStorageStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList { return a.validator.Validate(ctx, obj) } -func (CustomResourceDefinitionStorageStrategy) AllowCreateOnUpdate() bool { +func (customResourceDefinitionStorageStrategy) AllowCreateOnUpdate() bool { return false } -func (CustomResourceDefinitionStorageStrategy) AllowUnconditionalUpdate() bool { +func (customResourceDefinitionStorageStrategy) AllowUnconditionalUpdate() bool { return false } -func (CustomResourceDefinitionStorageStrategy) Canonicalize(obj runtime.Object) { +func (customResourceDefinitionStorageStrategy) Canonicalize(obj runtime.Object) { } -func (a CustomResourceDefinitionStorageStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList { +func (a customResourceDefinitionStorageStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList { return a.validator.ValidateUpdate(ctx, obj, old) } -func (a CustomResourceDefinitionStorageStrategy) GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) { +func (a customResourceDefinitionStorageStrategy) GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) { accessor, err := meta.Accessor(obj) if err != nil { return nil, nil, false, err @@ -102,7 +102,7 @@ func objectMetaFieldsSet(objectMeta metav1.Object, namespaceScoped bool) fields. } } -func (a CustomResourceDefinitionStorageStrategy) MatchCustomResourceDefinitionStorage(label labels.Selector, field fields.Selector) storage.SelectionPredicate { +func (a customResourceDefinitionStorageStrategy) MatchCustomResourceDefinitionStorage(label labels.Selector, field fields.Selector) storage.SelectionPredicate { return storage.SelectionPredicate{ Label: label, Field: field, diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/BUILD b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/BUILD index ff0bd54d2e08f..42e88f9887f27 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/BUILD +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/BUILD @@ -14,6 +14,7 @@ go_library( deps = [ "//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/strategy.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/strategy.go index de6e34a74cf8a..b6314b0c5c8a3 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/strategy.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/strategy.go @@ -19,6 +19,7 @@ package customresourcedefinition import ( "fmt" + apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -46,9 +47,27 @@ func (strategy) NamespaceScoped() bool { } func (strategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { + crd := obj.(*apiextensions.CustomResourceDefinition) + crd.Status = apiextensions.CustomResourceDefinitionStatus{} + crd.Generation = 1 } func (strategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { + newCRD := obj.(*apiextensions.CustomResourceDefinition) + oldCRD := old.(*apiextensions.CustomResourceDefinition) + newCRD.Status = oldCRD.Status + + // Any changes to the spec increment the generation number, any changes to the + // status should reflect the generation number of the corresponding object. We push + // the burden of managing the status onto the clients because we can't (in general) + // know here what version of spec the writer of the status has seen. It may seem like + // we can at first -- since obj contains spec -- but in the future we will probably make + // status its own object, and even if we don't, writes may be the result of a + // read-update-write loop, so the contents of spec may not actually be the spec that + // the controller has *seen*. + if !apiequality.Semantic.DeepEqual(oldCRD.Spec, newCRD.Spec) { + newCRD.Generation = oldCRD.Generation + 1 + } } func (strategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList { @@ -87,9 +106,14 @@ func (statusStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old r newObj := obj.(*apiextensions.CustomResourceDefinition) oldObj := old.(*apiextensions.CustomResourceDefinition) newObj.Spec = oldObj.Spec + + // Status updates are for only for updating status, not objectmeta. + // TODO: Update after ResetObjectMetaForStatus is added to meta/v1. newObj.Labels = oldObj.Labels newObj.Annotations = oldObj.Annotations newObj.OwnerReferences = oldObj.OwnerReferences + newObj.Generation = oldObj.Generation + newObj.SelfLink = oldObj.SelfLink } func (statusStrategy) AllowCreateOnUpdate() bool {