mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 09:49:50 +00:00
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.
This commit is contained in:
parent
baa6b2ff20
commit
5c354615e0
@ -24,13 +24,13 @@ import (
|
|||||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
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 {
|
type REST struct {
|
||||||
*genericregistry.Store
|
*genericregistry.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewREST returns a RESTStorage object that will work against API services.
|
// 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{
|
store := &genericregistry.Store{
|
||||||
Copier: copier,
|
Copier: copier,
|
||||||
NewFunc: func() runtime.Object { return &unstructured.Unstructured{} },
|
NewFunc: func() runtime.Object { return &unstructured.Unstructured{} },
|
||||||
|
@ -32,7 +32,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/storage/names"
|
"k8s.io/apiserver/pkg/storage/names"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CustomResourceDefinitionStorageStrategy struct {
|
type customResourceDefinitionStorageStrategy struct {
|
||||||
runtime.ObjectTyper
|
runtime.ObjectTyper
|
||||||
names.NameGenerator
|
names.NameGenerator
|
||||||
|
|
||||||
@ -40,8 +40,8 @@ type CustomResourceDefinitionStorageStrategy struct {
|
|||||||
validator customResourceValidator
|
validator customResourceValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.GroupVersionKind) CustomResourceDefinitionStorageStrategy {
|
func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.GroupVersionKind) customResourceDefinitionStorageStrategy {
|
||||||
return CustomResourceDefinitionStorageStrategy{
|
return customResourceDefinitionStorageStrategy{
|
||||||
ObjectTyper: typer,
|
ObjectTyper: typer,
|
||||||
NameGenerator: names.SimpleNameGenerator,
|
NameGenerator: names.SimpleNameGenerator,
|
||||||
namespaceScoped: namespaceScoped,
|
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
|
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)
|
return a.validator.Validate(ctx, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (CustomResourceDefinitionStorageStrategy) AllowCreateOnUpdate() bool {
|
func (customResourceDefinitionStorageStrategy) AllowCreateOnUpdate() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (CustomResourceDefinitionStorageStrategy) AllowUnconditionalUpdate() bool {
|
func (customResourceDefinitionStorageStrategy) AllowUnconditionalUpdate() bool {
|
||||||
return false
|
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)
|
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)
|
accessor, err := meta.Accessor(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, false, err
|
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{
|
return storage.SelectionPredicate{
|
||||||
Label: label,
|
Label: label,
|
||||||
Field: field,
|
Field: field,
|
||||||
|
@ -14,6 +14,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
"//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/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/api/errors:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||||
|
@ -19,6 +19,7 @@ package customresourcedefinition
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
"k8s.io/apimachinery/pkg/fields"
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -46,9 +47,27 @@ func (strategy) NamespaceScoped() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) {
|
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) {
|
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 {
|
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)
|
newObj := obj.(*apiextensions.CustomResourceDefinition)
|
||||||
oldObj := old.(*apiextensions.CustomResourceDefinition)
|
oldObj := old.(*apiextensions.CustomResourceDefinition)
|
||||||
newObj.Spec = oldObj.Spec
|
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.Labels = oldObj.Labels
|
||||||
newObj.Annotations = oldObj.Annotations
|
newObj.Annotations = oldObj.Annotations
|
||||||
newObj.OwnerReferences = oldObj.OwnerReferences
|
newObj.OwnerReferences = oldObj.OwnerReferences
|
||||||
|
newObj.Generation = oldObj.Generation
|
||||||
|
newObj.SelfLink = oldObj.SelfLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func (statusStrategy) AllowCreateOnUpdate() bool {
|
func (statusStrategy) AllowCreateOnUpdate() bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user