mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-21 18:11:22 +00:00
Server-Side Apply: Status Wiping/Reset Fields
Adds and implements ResetFieldsProvder interface in order to ensure that the fieldmanager no longer owns fields that get reset before the object is persisted. Co-authored-by: Kevin Wiesmueller <kwiesmul@redhat.com> Co-authored-by: Kevin Delgado <kevindelgado@google.com>
This commit is contained in:
@@ -29,6 +29,7 @@ import (
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/apps/daemonset"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// REST implements a RESTStorage for DaemonSets
|
||||
@@ -44,9 +45,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
||||
NewListFunc: func() runtime.Object { return &apps.DaemonSetList{} },
|
||||
DefaultQualifiedResource: apps.Resource("daemonsets"),
|
||||
|
||||
CreateStrategy: daemonset.Strategy,
|
||||
UpdateStrategy: daemonset.Strategy,
|
||||
DeleteStrategy: daemonset.Strategy,
|
||||
CreateStrategy: daemonset.Strategy,
|
||||
UpdateStrategy: daemonset.Strategy,
|
||||
DeleteStrategy: daemonset.Strategy,
|
||||
ResetFieldsStrategy: daemonset.Strategy,
|
||||
|
||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||
}
|
||||
@@ -57,6 +59,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
||||
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = daemonset.StatusStrategy
|
||||
statusStore.ResetFieldsStrategy = daemonset.StatusStrategy
|
||||
|
||||
return &REST{store, []string{"all"}}, &StatusREST{store: &statusStore}, nil
|
||||
}
|
||||
@@ -103,3 +106,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
||||
// subresources should never allow create on update.
|
||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
||||
}
|
||||
|
||||
// GetResetFields implements rest.ResetFieldsStrategy
|
||||
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return r.store.GetResetFields()
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// daemonSetStrategy implements verification logic for daemon sets.
|
||||
@@ -68,6 +69,18 @@ func (daemonSetStrategy) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (daemonSetStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"apps/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("status"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// PrepareForCreate clears the status of a daemon set before creation.
|
||||
func (daemonSetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
daemonSet := obj.(*apps.DaemonSet)
|
||||
@@ -202,6 +215,16 @@ type daemonSetStatusStrategy struct {
|
||||
// StatusStrategy is the default logic invoked when updating object status.
|
||||
var StatusStrategy = daemonSetStatusStrategy{Strategy}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (daemonSetStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"apps/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (daemonSetStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
newDaemonSet := obj.(*apps.DaemonSet)
|
||||
oldDaemonSet := old.(*apps.DaemonSet)
|
||||
|
@@ -43,6 +43,7 @@ import (
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/apps/deployment"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// DeploymentStorage includes dummy storage for Deployments and for Scale subresource.
|
||||
@@ -81,9 +82,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Rollbac
|
||||
NewListFunc: func() runtime.Object { return &apps.DeploymentList{} },
|
||||
DefaultQualifiedResource: apps.Resource("deployments"),
|
||||
|
||||
CreateStrategy: deployment.Strategy,
|
||||
UpdateStrategy: deployment.Strategy,
|
||||
DeleteStrategy: deployment.Strategy,
|
||||
CreateStrategy: deployment.Strategy,
|
||||
UpdateStrategy: deployment.Strategy,
|
||||
DeleteStrategy: deployment.Strategy,
|
||||
ResetFieldsStrategy: deployment.Strategy,
|
||||
|
||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||
}
|
||||
@@ -94,6 +96,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Rollbac
|
||||
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = deployment.StatusStrategy
|
||||
statusStore.ResetFieldsStrategy = deployment.StatusStrategy
|
||||
return &REST{store, []string{"all"}}, &StatusREST{store: &statusStore}, &RollbackREST{store: store}, nil
|
||||
}
|
||||
|
||||
@@ -141,6 +144,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
||||
}
|
||||
|
||||
// GetResetFields implements rest.ResetFieldsStrategy
|
||||
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return r.store.GetResetFields()
|
||||
}
|
||||
|
||||
// RollbackREST implements the REST endpoint for initiating the rollback of a deployment
|
||||
type RollbackREST struct {
|
||||
store *genericregistry.Store
|
||||
|
@@ -34,6 +34,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/pod"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// deploymentStrategy implements behavior for Deployments.
|
||||
@@ -67,6 +68,18 @@ func (deploymentStrategy) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (deploymentStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"apps/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("status"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
||||
func (deploymentStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
deployment := obj.(*apps.Deployment)
|
||||
@@ -147,6 +160,17 @@ type deploymentStatusStrategy struct {
|
||||
// StatusStrategy is the default logic invoked when updating object status.
|
||||
var StatusStrategy = deploymentStatusStrategy{Strategy}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (deploymentStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"apps/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
fieldpath.MakePathOrDie("metadata", "labels"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
||||
func (deploymentStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
newDeployment := obj.(*apps.Deployment)
|
||||
|
@@ -40,6 +40,7 @@ import (
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/apps/replicaset"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// ReplicaSetStorage includes dummy storage for ReplicaSets and for Scale subresource.
|
||||
@@ -77,9 +78,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
||||
PredicateFunc: replicaset.MatchReplicaSet,
|
||||
DefaultQualifiedResource: apps.Resource("replicasets"),
|
||||
|
||||
CreateStrategy: replicaset.Strategy,
|
||||
UpdateStrategy: replicaset.Strategy,
|
||||
DeleteStrategy: replicaset.Strategy,
|
||||
CreateStrategy: replicaset.Strategy,
|
||||
UpdateStrategy: replicaset.Strategy,
|
||||
DeleteStrategy: replicaset.Strategy,
|
||||
ResetFieldsStrategy: replicaset.Strategy,
|
||||
|
||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||
}
|
||||
@@ -90,6 +92,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
||||
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = replicaset.StatusStrategy
|
||||
statusStore.ResetFieldsStrategy = replicaset.StatusStrategy
|
||||
|
||||
return &REST{store, []string{"all"}}, &StatusREST{store: &statusStore}, nil
|
||||
}
|
||||
@@ -138,6 +141,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
||||
}
|
||||
|
||||
// GetResetFields implements rest.ResetFieldsStrategy
|
||||
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return r.store.GetResetFields()
|
||||
}
|
||||
|
||||
// ScaleREST implements a Scale for ReplicaSet.
|
||||
type ScaleREST struct {
|
||||
store *genericregistry.Store
|
||||
|
@@ -41,6 +41,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/pod"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// rsStrategy implements verification logic for ReplicaSets.
|
||||
@@ -73,6 +74,18 @@ func (rsStrategy) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (rsStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"apps/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("status"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// PrepareForCreate clears the status of a ReplicaSet before creation.
|
||||
func (rsStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
rs := obj.(*apps.ReplicaSet)
|
||||
@@ -189,6 +202,16 @@ type rsStatusStrategy struct {
|
||||
// StatusStrategy is the default logic invoked when updating object status.
|
||||
var StatusStrategy = rsStatusStrategy{Strategy}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (rsStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"apps/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (rsStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
newRS := obj.(*apps.ReplicaSet)
|
||||
oldRS := old.(*apps.ReplicaSet)
|
||||
|
@@ -37,6 +37,7 @@ import (
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/apps/statefulset"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// StatefulSetStorage includes dummy storage for StatefulSets, and their Status and Scale subresource.
|
||||
@@ -72,9 +73,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
||||
NewListFunc: func() runtime.Object { return &apps.StatefulSetList{} },
|
||||
DefaultQualifiedResource: apps.Resource("statefulsets"),
|
||||
|
||||
CreateStrategy: statefulset.Strategy,
|
||||
UpdateStrategy: statefulset.Strategy,
|
||||
DeleteStrategy: statefulset.Strategy,
|
||||
CreateStrategy: statefulset.Strategy,
|
||||
UpdateStrategy: statefulset.Strategy,
|
||||
DeleteStrategy: statefulset.Strategy,
|
||||
ResetFieldsStrategy: statefulset.Strategy,
|
||||
|
||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||
}
|
||||
@@ -85,6 +87,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
||||
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = statefulset.StatusStrategy
|
||||
statusStore.ResetFieldsStrategy = statefulset.StatusStrategy
|
||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||
}
|
||||
|
||||
@@ -118,6 +121,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
||||
}
|
||||
|
||||
// GetResetFields implements rest.ResetFieldsStrategy
|
||||
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return r.store.GetResetFields()
|
||||
}
|
||||
|
||||
// Implement ShortNamesProvider
|
||||
var _ rest.ShortNamesProvider = &REST{}
|
||||
|
||||
|
@@ -32,6 +32,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/pod"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// statefulSetStrategy implements verification logic for Replication StatefulSets.
|
||||
@@ -64,6 +65,18 @@ func (statefulSetStrategy) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (statefulSetStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"apps/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("status"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// PrepareForCreate clears the status of an StatefulSet before creation.
|
||||
func (statefulSetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
statefulSet := obj.(*apps.StatefulSet)
|
||||
@@ -132,6 +145,16 @@ type statefulSetStatusStrategy struct {
|
||||
// StatusStrategy is the default logic invoked when updating object status.
|
||||
var StatusStrategy = statefulSetStatusStrategy{Strategy}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (statefulSetStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"apps/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
||||
func (statefulSetStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
newStatefulSet := obj.(*apps.StatefulSet)
|
||||
|
Reference in New Issue
Block a user