mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Merge pull request #99661 from kevindelgado/status-wiping
Server-Side Apply status wiping
This commit is contained in:
commit
b7d23d7111
@ -270,7 +270,6 @@ API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/ap
|
|||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionNames,Categories
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionNames,Categories
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionNames,ShortNames
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionNames,ShortNames
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionSpec,Versions
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionSpec,Versions
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionStatus,Conditions
|
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionStatus,StoredVersions
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionStatus,StoredVersions
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionVersion,AdditionalPrinterColumns
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,CustomResourceDefinitionVersion,AdditionalPrinterColumns
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSON,Raw
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSON,Raw
|
||||||
@ -291,7 +290,6 @@ API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/ap
|
|||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionNames,ShortNames
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionNames,ShortNames
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionSpec,AdditionalPrinterColumns
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionSpec,AdditionalPrinterColumns
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionSpec,Versions
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionSpec,Versions
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionStatus,Conditions
|
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionStatus,StoredVersions
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionStatus,StoredVersions
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionVersion,AdditionalPrinterColumns
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,CustomResourceDefinitionVersion,AdditionalPrinterColumns
|
||||||
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,JSON,Raw
|
API rule violation: list_type_missing,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1,JSON,Raw
|
||||||
|
12
api/openapi-spec/swagger.json
generated
12
api/openapi-spec/swagger.json
generated
@ -17256,7 +17256,11 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionCondition"
|
"$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceDefinitionCondition"
|
||||||
},
|
},
|
||||||
"type": "array"
|
"type": "array",
|
||||||
|
"x-kubernetes-list-map-keys": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"x-kubernetes-list-type": "map"
|
||||||
},
|
},
|
||||||
"storedVersions": {
|
"storedVersions": {
|
||||||
"description": "storedVersions lists all versions of CustomResources that were ever persisted. Tracking these versions allows a migration path for stored versions in etcd. The field is mutable so a migration controller can finish a migration to another version (ensuring no old objects are left in storage), and then remove the rest of the versions from this list. Versions may not be removed from `spec.versions` while they exist in this list.",
|
"description": "storedVersions lists all versions of CustomResources that were ever persisted. Tracking these versions allows a migration path for stored versions in etcd. The field is mutable so a migration controller can finish a migration to another version (ensuring no old objects are left in storage), and then remove the rest of the versions from this list. Versions may not be removed from `spec.versions` while they exist in this list.",
|
||||||
@ -17904,7 +17908,11 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionCondition"
|
"$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionCondition"
|
||||||
},
|
},
|
||||||
"type": "array"
|
"type": "array",
|
||||||
|
"x-kubernetes-list-map-keys": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"x-kubernetes-list-type": "map"
|
||||||
},
|
},
|
||||||
"storedVersions": {
|
"storedVersions": {
|
||||||
"description": "storedVersions lists all versions of CustomResources that were ever persisted. Tracking these versions allows a migration path for stored versions in etcd. The field is mutable so a migration controller can finish a migration to another version (ensuring no old objects are left in storage), and then remove the rest of the versions from this list. Versions may not be removed from `spec.versions` while they exist in this list.",
|
"description": "storedVersions lists all versions of CustomResources that were ever persisted. Tracking these versions allows a migration path for stored versions in etcd. The field is mutable so a migration controller can finish a migration to another version (ensuring no old objects are left in storage), and then remove the rest of the versions from this list. Versions may not be removed from `spec.versions` while they exist in this list.",
|
||||||
|
1
go.mod
1
go.mod
@ -137,6 +137,7 @@ require (
|
|||||||
k8s.io/sample-apiserver v0.0.0
|
k8s.io/sample-apiserver v0.0.0
|
||||||
k8s.io/system-validators v1.4.0
|
k8s.io/system-validators v1.4.0
|
||||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
|
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.0.3
|
||||||
sigs.k8s.io/yaml v1.2.0
|
sigs.k8s.io/yaml v1.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -130,6 +130,10 @@ EOF
|
|||||||
# Creates a node object with name 127.0.0.1. This is required because we do not
|
# Creates a node object with name 127.0.0.1. This is required because we do not
|
||||||
# run kubelet.
|
# run kubelet.
|
||||||
#
|
#
|
||||||
|
# An arbitrary annotation is needed to ensure field managers are saved on the
|
||||||
|
# object. Without it, we would be creating an empty object and because status
|
||||||
|
# and name get wiped, there were be no field managers tracking any fields.
|
||||||
|
#
|
||||||
# Exports:
|
# Exports:
|
||||||
# SUPPORTED_RESOURCES(Array of all resources supported by the apiserver).
|
# SUPPORTED_RESOURCES(Array of all resources supported by the apiserver).
|
||||||
function create_node() {
|
function create_node() {
|
||||||
@ -138,7 +142,10 @@ function create_node() {
|
|||||||
"kind": "Node",
|
"kind": "Node",
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "127.0.0.1"
|
"name": "127.0.0.1",
|
||||||
|
"annotations": {
|
||||||
|
"save-managers": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"capacity": {
|
"capacity": {
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
strategy "k8s.io/kubernetes/pkg/registry/apiserverinternal/storageversion"
|
strategy "k8s.io/kubernetes/pkg/registry/apiserverinternal/storageversion"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for storage version against etcd
|
// REST implements a RESTStorage for storage version against etcd
|
||||||
@ -49,6 +50,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: strategy.Strategy,
|
CreateStrategy: strategy.Strategy,
|
||||||
UpdateStrategy: strategy.Strategy,
|
UpdateStrategy: strategy.Strategy,
|
||||||
DeleteStrategy: strategy.Strategy,
|
DeleteStrategy: strategy.Strategy,
|
||||||
|
ResetFieldsStrategy: strategy.Strategy,
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
options := &generic.StoreOptions{RESTOptions: optsGetter}
|
options := &generic.StoreOptions{RESTOptions: optsGetter}
|
||||||
@ -57,6 +59,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
}
|
}
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = strategy.StatusStrategy
|
statusStore.UpdateStrategy = strategy.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = strategy.StatusStrategy
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,3 +84,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/apis/apiserverinternal"
|
"k8s.io/kubernetes/pkg/apis/apiserverinternal"
|
||||||
"k8s.io/kubernetes/pkg/apis/apiserverinternal/validation"
|
"k8s.io/kubernetes/pkg/apis/apiserverinternal/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// storageVersionStrategy implements verification logic for StorageVersion.
|
// storageVersionStrategy implements verification logic for StorageVersion.
|
||||||
@ -42,6 +43,18 @@ func (storageVersionStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (storageVersionStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"internal.apiserver.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of an StorageVersion before creation.
|
// PrepareForCreate clears the status of an StorageVersion before creation.
|
||||||
func (storageVersionStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (storageVersionStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
sv := obj.(*apiserverinternal.StorageVersion)
|
sv := obj.(*apiserverinternal.StorageVersion)
|
||||||
@ -90,6 +103,19 @@ type storageVersionStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = storageVersionStatusStrategy{Strategy}
|
var StatusStrategy = storageVersionStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (storageVersionStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"internal.apiserver.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (storageVersionStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (storageVersionStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newSV := obj.(*apiserverinternal.StorageVersion)
|
newSV := obj.(*apiserverinternal.StorageVersion)
|
||||||
oldSV := old.(*apiserverinternal.StorageVersion)
|
oldSV := old.(*apiserverinternal.StorageVersion)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/apps/daemonset"
|
"k8s.io/kubernetes/pkg/registry/apps/daemonset"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for DaemonSets
|
// REST implements a RESTStorage for DaemonSets
|
||||||
@ -47,6 +48,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: daemonset.Strategy,
|
CreateStrategy: daemonset.Strategy,
|
||||||
UpdateStrategy: daemonset.Strategy,
|
UpdateStrategy: daemonset.Strategy,
|
||||||
DeleteStrategy: daemonset.Strategy,
|
DeleteStrategy: daemonset.Strategy,
|
||||||
|
ResetFieldsStrategy: daemonset.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -57,6 +59,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = daemonset.StatusStrategy
|
statusStore.UpdateStrategy = daemonset.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = daemonset.StatusStrategy
|
||||||
|
|
||||||
return &REST{store, []string{"all"}}, &StatusREST{store: &statusStore}, nil
|
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.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// daemonSetStrategy implements verification logic for daemon sets.
|
// daemonSetStrategy implements verification logic for daemon sets.
|
||||||
@ -68,6 +69,18 @@ func (daemonSetStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
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.
|
// PrepareForCreate clears the status of a daemon set before creation.
|
||||||
func (daemonSetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (daemonSetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
daemonSet := obj.(*apps.DaemonSet)
|
daemonSet := obj.(*apps.DaemonSet)
|
||||||
@ -202,6 +215,16 @@ type daemonSetStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = daemonSetStatusStrategy{Strategy}
|
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) {
|
func (daemonSetStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newDaemonSet := obj.(*apps.DaemonSet)
|
newDaemonSet := obj.(*apps.DaemonSet)
|
||||||
oldDaemonSet := old.(*apps.DaemonSet)
|
oldDaemonSet := old.(*apps.DaemonSet)
|
||||||
|
@ -43,6 +43,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/apps/deployment"
|
"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.
|
// DeploymentStorage includes dummy storage for Deployments and for Scale subresource.
|
||||||
@ -84,6 +85,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Rollbac
|
|||||||
CreateStrategy: deployment.Strategy,
|
CreateStrategy: deployment.Strategy,
|
||||||
UpdateStrategy: deployment.Strategy,
|
UpdateStrategy: deployment.Strategy,
|
||||||
DeleteStrategy: deployment.Strategy,
|
DeleteStrategy: deployment.Strategy,
|
||||||
|
ResetFieldsStrategy: deployment.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -94,6 +96,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Rollbac
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = deployment.StatusStrategy
|
statusStore.UpdateStrategy = deployment.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = deployment.StatusStrategy
|
||||||
return &REST{store, []string{"all"}}, &StatusREST{store: &statusStore}, &RollbackREST{store: store}, nil
|
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)
|
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
|
// RollbackREST implements the REST endpoint for initiating the rollback of a deployment
|
||||||
type RollbackREST struct {
|
type RollbackREST struct {
|
||||||
store *genericregistry.Store
|
store *genericregistry.Store
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/pod"
|
"k8s.io/kubernetes/pkg/api/pod"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps"
|
"k8s.io/kubernetes/pkg/apis/apps"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// deploymentStrategy implements behavior for Deployments.
|
// deploymentStrategy implements behavior for Deployments.
|
||||||
@ -67,6 +68,18 @@ func (deploymentStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
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.
|
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
||||||
func (deploymentStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (deploymentStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
deployment := obj.(*apps.Deployment)
|
deployment := obj.(*apps.Deployment)
|
||||||
@ -147,6 +160,17 @@ type deploymentStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = deploymentStatusStrategy{Strategy}
|
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
|
// 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) {
|
func (deploymentStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newDeployment := obj.(*apps.Deployment)
|
newDeployment := obj.(*apps.Deployment)
|
||||||
|
@ -40,6 +40,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/apps/replicaset"
|
"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.
|
// ReplicaSetStorage includes dummy storage for ReplicaSets and for Scale subresource.
|
||||||
@ -80,6 +81,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: replicaset.Strategy,
|
CreateStrategy: replicaset.Strategy,
|
||||||
UpdateStrategy: replicaset.Strategy,
|
UpdateStrategy: replicaset.Strategy,
|
||||||
DeleteStrategy: replicaset.Strategy,
|
DeleteStrategy: replicaset.Strategy,
|
||||||
|
ResetFieldsStrategy: replicaset.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -90,6 +92,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = replicaset.StatusStrategy
|
statusStore.UpdateStrategy = replicaset.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = replicaset.StatusStrategy
|
||||||
|
|
||||||
return &REST{store, []string{"all"}}, &StatusREST{store: &statusStore}, nil
|
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)
|
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.
|
// ScaleREST implements a Scale for ReplicaSet.
|
||||||
type ScaleREST struct {
|
type ScaleREST struct {
|
||||||
store *genericregistry.Store
|
store *genericregistry.Store
|
||||||
|
@ -41,6 +41,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/pod"
|
"k8s.io/kubernetes/pkg/api/pod"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps"
|
"k8s.io/kubernetes/pkg/apis/apps"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rsStrategy implements verification logic for ReplicaSets.
|
// rsStrategy implements verification logic for ReplicaSets.
|
||||||
@ -73,6 +74,18 @@ func (rsStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
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.
|
// PrepareForCreate clears the status of a ReplicaSet before creation.
|
||||||
func (rsStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (rsStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
rs := obj.(*apps.ReplicaSet)
|
rs := obj.(*apps.ReplicaSet)
|
||||||
@ -189,6 +202,16 @@ type rsStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = rsStatusStrategy{Strategy}
|
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) {
|
func (rsStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newRS := obj.(*apps.ReplicaSet)
|
newRS := obj.(*apps.ReplicaSet)
|
||||||
oldRS := old.(*apps.ReplicaSet)
|
oldRS := old.(*apps.ReplicaSet)
|
||||||
|
@ -37,6 +37,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/apps/statefulset"
|
"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.
|
// StatefulSetStorage includes dummy storage for StatefulSets, and their Status and Scale subresource.
|
||||||
@ -75,6 +76,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: statefulset.Strategy,
|
CreateStrategy: statefulset.Strategy,
|
||||||
UpdateStrategy: statefulset.Strategy,
|
UpdateStrategy: statefulset.Strategy,
|
||||||
DeleteStrategy: statefulset.Strategy,
|
DeleteStrategy: statefulset.Strategy,
|
||||||
|
ResetFieldsStrategy: statefulset.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -85,6 +87,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = statefulset.StatusStrategy
|
statusStore.UpdateStrategy = statefulset.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = statefulset.StatusStrategy
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
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)
|
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
|
// Implement ShortNamesProvider
|
||||||
var _ rest.ShortNamesProvider = &REST{}
|
var _ rest.ShortNamesProvider = &REST{}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/pod"
|
"k8s.io/kubernetes/pkg/api/pod"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps"
|
"k8s.io/kubernetes/pkg/apis/apps"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// statefulSetStrategy implements verification logic for Replication StatefulSets.
|
// statefulSetStrategy implements verification logic for Replication StatefulSets.
|
||||||
@ -64,6 +65,18 @@ func (statefulSetStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
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.
|
// PrepareForCreate clears the status of an StatefulSet before creation.
|
||||||
func (statefulSetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (statefulSetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
statefulSet := obj.(*apps.StatefulSet)
|
statefulSet := obj.(*apps.StatefulSet)
|
||||||
@ -132,6 +145,16 @@ type statefulSetStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = statefulSetStatusStrategy{Strategy}
|
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
|
// 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) {
|
func (statefulSetStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newStatefulSet := obj.(*apps.StatefulSet)
|
newStatefulSet := obj.(*apps.StatefulSet)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/autoscaling/horizontalpodautoscaler"
|
"k8s.io/kubernetes/pkg/registry/autoscaling/horizontalpodautoscaler"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for pod disruption budgets against etcd
|
// REST implements a RESTStorage for pod disruption budgets against etcd
|
||||||
@ -46,6 +47,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: horizontalpodautoscaler.Strategy,
|
CreateStrategy: horizontalpodautoscaler.Strategy,
|
||||||
UpdateStrategy: horizontalpodautoscaler.Strategy,
|
UpdateStrategy: horizontalpodautoscaler.Strategy,
|
||||||
DeleteStrategy: horizontalpodautoscaler.Strategy,
|
DeleteStrategy: horizontalpodautoscaler.Strategy,
|
||||||
|
ResetFieldsStrategy: horizontalpodautoscaler.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -56,6 +58,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = horizontalpodautoscaler.StatusStrategy
|
statusStore.UpdateStrategy = horizontalpodautoscaler.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = horizontalpodautoscaler.StatusStrategy
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,3 +99,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling/validation"
|
"k8s.io/kubernetes/pkg/apis/autoscaling/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// autoscalerStrategy implements behavior for HorizontalPodAutoscalers
|
// autoscalerStrategy implements behavior for HorizontalPodAutoscalers
|
||||||
@ -44,6 +45,24 @@ func (autoscalerStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (autoscalerStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"autoscaling/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"autoscaling/v2beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"autoscaling/v2beta2": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
||||||
func (autoscalerStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (autoscalerStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
newHPA := obj.(*autoscaling.HorizontalPodAutoscaler)
|
newHPA := obj.(*autoscaling.HorizontalPodAutoscaler)
|
||||||
@ -115,6 +134,24 @@ type autoscalerStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = autoscalerStatusStrategy{Strategy}
|
var StatusStrategy = autoscalerStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (autoscalerStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"autoscaling/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
"autoscaling/v2beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
"autoscaling/v2beta2": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (autoscalerStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (autoscalerStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newAutoscaler := obj.(*autoscaling.HorizontalPodAutoscaler)
|
newAutoscaler := obj.(*autoscaling.HorizontalPodAutoscaler)
|
||||||
oldAutoscaler := old.(*autoscaling.HorizontalPodAutoscaler)
|
oldAutoscaler := old.(*autoscaling.HorizontalPodAutoscaler)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/batch/cronjob"
|
"k8s.io/kubernetes/pkg/registry/batch/cronjob"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for scheduled jobs against etcd
|
// REST implements a RESTStorage for scheduled jobs against etcd
|
||||||
@ -46,6 +47,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: cronjob.Strategy,
|
CreateStrategy: cronjob.Strategy,
|
||||||
UpdateStrategy: cronjob.Strategy,
|
UpdateStrategy: cronjob.Strategy,
|
||||||
DeleteStrategy: cronjob.Strategy,
|
DeleteStrategy: cronjob.Strategy,
|
||||||
|
ResetFieldsStrategy: cronjob.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -56,6 +58,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = cronjob.StatusStrategy
|
statusStore.UpdateStrategy = cronjob.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = cronjob.StatusStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
@ -94,3 +97,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/pod"
|
"k8s.io/kubernetes/pkg/api/pod"
|
||||||
"k8s.io/kubernetes/pkg/apis/batch"
|
"k8s.io/kubernetes/pkg/apis/batch"
|
||||||
"k8s.io/kubernetes/pkg/apis/batch/validation"
|
"k8s.io/kubernetes/pkg/apis/batch/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cronJobStrategy implements verification logic for Replication Controllers.
|
// cronJobStrategy implements verification logic for Replication Controllers.
|
||||||
@ -62,6 +63,21 @@ func (cronJobStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (cronJobStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"batch/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"batch/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of a scheduled job before creation.
|
// PrepareForCreate clears the status of a scheduled job before creation.
|
||||||
func (cronJobStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (cronJobStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
cronJob := obj.(*batch.CronJob)
|
cronJob := obj.(*batch.CronJob)
|
||||||
@ -115,6 +131,19 @@ type cronJobStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = cronJobStatusStrategy{Strategy}
|
var StatusStrategy = cronJobStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (cronJobStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"batch/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
"batch/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (cronJobStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (cronJobStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newJob := obj.(*batch.CronJob)
|
newJob := obj.(*batch.CronJob)
|
||||||
oldJob := old.(*batch.CronJob)
|
oldJob := old.(*batch.CronJob)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/batch/job"
|
"k8s.io/kubernetes/pkg/registry/batch/job"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// JobStorage includes dummy storage for Job.
|
// JobStorage includes dummy storage for Job.
|
||||||
@ -66,6 +67,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: job.Strategy,
|
CreateStrategy: job.Strategy,
|
||||||
UpdateStrategy: job.Strategy,
|
UpdateStrategy: job.Strategy,
|
||||||
DeleteStrategy: job.Strategy,
|
DeleteStrategy: job.Strategy,
|
||||||
|
ResetFieldsStrategy: job.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -76,6 +78,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = job.StatusStrategy
|
statusStore.UpdateStrategy = job.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = job.StatusStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
@ -109,3 +112,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -40,6 +40,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/batch/validation"
|
"k8s.io/kubernetes/pkg/apis/batch/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// jobStrategy implements verification logic for Replication Controllers.
|
// jobStrategy implements verification logic for Replication Controllers.
|
||||||
@ -72,6 +73,18 @@ func (jobStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (jobStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"batch/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of a job before creation.
|
// PrepareForCreate clears the status of a job before creation.
|
||||||
func (jobStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (jobStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
job := obj.(*batch.Job)
|
job := obj.(*batch.Job)
|
||||||
@ -210,6 +223,16 @@ type jobStatusStrategy struct {
|
|||||||
|
|
||||||
var StatusStrategy = jobStatusStrategy{Strategy}
|
var StatusStrategy = jobStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (jobStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"batch/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (jobStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (jobStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newJob := obj.(*batch.Job)
|
newJob := obj.(*batch.Job)
|
||||||
oldJob := old.(*batch.Job)
|
oldJob := old.(*batch.Job)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
csrregistry "k8s.io/kubernetes/pkg/registry/certificates/certificates"
|
csrregistry "k8s.io/kubernetes/pkg/registry/certificates/certificates"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for CertificateSigningRequest.
|
// REST implements a RESTStorage for CertificateSigningRequest.
|
||||||
@ -46,6 +47,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Approva
|
|||||||
CreateStrategy: csrregistry.Strategy,
|
CreateStrategy: csrregistry.Strategy,
|
||||||
UpdateStrategy: csrregistry.Strategy,
|
UpdateStrategy: csrregistry.Strategy,
|
||||||
DeleteStrategy: csrregistry.Strategy,
|
DeleteStrategy: csrregistry.Strategy,
|
||||||
|
ResetFieldsStrategy: csrregistry.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -59,9 +61,11 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Approva
|
|||||||
// dedicated strategies.
|
// dedicated strategies.
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = csrregistry.StatusStrategy
|
statusStore.UpdateStrategy = csrregistry.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = csrregistry.StatusStrategy
|
||||||
|
|
||||||
approvalStore := *store
|
approvalStore := *store
|
||||||
approvalStore.UpdateStrategy = csrregistry.ApprovalStrategy
|
approvalStore.UpdateStrategy = csrregistry.ApprovalStrategy
|
||||||
|
approvalStore.ResetFieldsStrategy = csrregistry.ApprovalStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, &ApprovalREST{store: &approvalStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, &ApprovalREST{store: &approvalStore}, nil
|
||||||
}
|
}
|
||||||
@ -96,6 +100,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
var _ = rest.Patcher(&StatusREST{})
|
var _ = rest.Patcher(&StatusREST{})
|
||||||
|
|
||||||
// ApprovalREST implements the REST endpoint for changing the approval state of a CSR.
|
// ApprovalREST implements the REST endpoint for changing the approval state of a CSR.
|
||||||
@ -120,4 +129,9 @@ func (r *ApprovalREST) Update(ctx context.Context, name string, objInfo rest.Upd
|
|||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields implements rest.ResetFieldsStrategy
|
||||||
|
func (r *ApprovalREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return r.store.GetResetFields()
|
||||||
|
}
|
||||||
|
|
||||||
var _ = rest.Patcher(&ApprovalREST{})
|
var _ = rest.Patcher(&ApprovalREST{})
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||||
"k8s.io/kubernetes/pkg/apis/certificates/validation"
|
"k8s.io/kubernetes/pkg/apis/certificates/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// csrStrategy implements behavior for CSRs
|
// csrStrategy implements behavior for CSRs
|
||||||
@ -50,6 +51,23 @@ func (csrStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (csrStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"certificates.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"certificates.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// AllowCreateOnUpdate is false for CSRs.
|
// AllowCreateOnUpdate is false for CSRs.
|
||||||
func (csrStrategy) AllowCreateOnUpdate() bool {
|
func (csrStrategy) AllowCreateOnUpdate() bool {
|
||||||
return false
|
return false
|
||||||
@ -125,6 +143,23 @@ type csrStatusStrategy struct {
|
|||||||
|
|
||||||
var StatusStrategy = csrStatusStrategy{Strategy}
|
var StatusStrategy = csrStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (csrStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"certificates.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("status", "conditions"),
|
||||||
|
),
|
||||||
|
"certificates.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("status", "conditions"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (csrStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (csrStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newCSR := obj.(*certificates.CertificateSigningRequest)
|
newCSR := obj.(*certificates.CertificateSigningRequest)
|
||||||
oldCSR := old.(*certificates.CertificateSigningRequest)
|
oldCSR := old.(*certificates.CertificateSigningRequest)
|
||||||
@ -220,6 +255,23 @@ type csrApprovalStrategy struct {
|
|||||||
|
|
||||||
var ApprovalStrategy = csrApprovalStrategy{Strategy}
|
var ApprovalStrategy = csrApprovalStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (csrApprovalStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"certificates.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("status", "certificate"),
|
||||||
|
),
|
||||||
|
"certificates.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("status", "certificate"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForUpdate prepares the new certificate signing request by limiting
|
// PrepareForUpdate prepares the new certificate signing request by limiting
|
||||||
// the data that is updated to only the conditions and populating condition timestamps
|
// the data that is updated to only the conditions and populating condition timestamps
|
||||||
func (csrApprovalStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (csrApprovalStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
@ -31,13 +32,12 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
storageerr "k8s.io/apiserver/pkg/storage/errors"
|
storageerr "k8s.io/apiserver/pkg/storage/errors"
|
||||||
"k8s.io/apiserver/pkg/util/dryrun"
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
|
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/namespace"
|
"k8s.io/kubernetes/pkg/registry/core/namespace"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rest implements a RESTStorage for namespaces
|
// rest implements a RESTStorage for namespaces
|
||||||
@ -67,6 +67,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Finaliz
|
|||||||
CreateStrategy: namespace.Strategy,
|
CreateStrategy: namespace.Strategy,
|
||||||
UpdateStrategy: namespace.Strategy,
|
UpdateStrategy: namespace.Strategy,
|
||||||
DeleteStrategy: namespace.Strategy,
|
DeleteStrategy: namespace.Strategy,
|
||||||
|
ResetFieldsStrategy: namespace.Strategy,
|
||||||
ReturnDeletedObject: true,
|
ReturnDeletedObject: true,
|
||||||
|
|
||||||
ShouldDeleteDuringUpdate: ShouldDeleteNamespaceDuringUpdate,
|
ShouldDeleteDuringUpdate: ShouldDeleteNamespaceDuringUpdate,
|
||||||
@ -80,9 +81,11 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Finaliz
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = namespace.StatusStrategy
|
statusStore.UpdateStrategy = namespace.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = namespace.StatusStrategy
|
||||||
|
|
||||||
finalizeStore := *store
|
finalizeStore := *store
|
||||||
finalizeStore.UpdateStrategy = namespace.FinalizeStrategy
|
finalizeStore.UpdateStrategy = namespace.FinalizeStrategy
|
||||||
|
finalizeStore.ResetFieldsStrategy = namespace.FinalizeStrategy
|
||||||
|
|
||||||
return &REST{store: store, status: &statusStore}, &StatusREST{store: &statusStore}, &FinalizeREST{store: &finalizeStore}, nil
|
return &REST{store: store, status: &statusStore}, &StatusREST{store: &statusStore}, &FinalizeREST{store: &finalizeStore}, nil
|
||||||
}
|
}
|
||||||
@ -291,6 +294,10 @@ func (r *REST) StorageVersion() runtime.GroupVersioner {
|
|||||||
return r.store.StorageVersion()
|
return r.store.StorageVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields implements rest.ResetFieldsStrategy
|
||||||
|
func (r *REST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return r.store.GetResetFields()
|
||||||
|
}
|
||||||
func (r *StatusREST) New() runtime.Object {
|
func (r *StatusREST) New() runtime.Object {
|
||||||
return r.store.New()
|
return r.store.New()
|
||||||
}
|
}
|
||||||
@ -307,6 +314,10 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
func (r *FinalizeREST) New() runtime.Object {
|
func (r *FinalizeREST) New() runtime.Object {
|
||||||
return r.store.New()
|
return r.store.New()
|
||||||
}
|
}
|
||||||
@ -317,3 +328,8 @@ func (r *FinalizeREST) Update(ctx context.Context, name string, objInfo rest.Upd
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields implements rest.ResetFieldsStrategy
|
||||||
|
func (r *FinalizeREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return r.store.GetResetFields()
|
||||||
|
}
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// namespaceStrategy implements behavior for Namespaces
|
// namespaceStrategy implements behavior for Namespaces
|
||||||
@ -50,6 +51,16 @@ func (namespaceStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (namespaceStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
||||||
func (namespaceStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (namespaceStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
// on create, status is active
|
// on create, status is active
|
||||||
@ -138,6 +149,16 @@ type namespaceStatusStrategy struct {
|
|||||||
|
|
||||||
var StatusStrategy = namespaceStatusStrategy{Strategy}
|
var StatusStrategy = namespaceStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (namespaceStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (namespaceStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (namespaceStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newNamespace := obj.(*api.Namespace)
|
newNamespace := obj.(*api.Namespace)
|
||||||
oldNamespace := old.(*api.Namespace)
|
oldNamespace := old.(*api.Namespace)
|
||||||
@ -158,6 +179,16 @@ func (namespaceFinalizeStrategy) ValidateUpdate(ctx context.Context, obj, old ru
|
|||||||
return validation.ValidateNamespaceFinalizeUpdate(obj.(*api.Namespace), old.(*api.Namespace))
|
return validation.ValidateNamespaceFinalizeUpdate(obj.(*api.Namespace), old.(*api.Namespace))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (namespaceFinalizeStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||||
func (namespaceFinalizeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (namespaceFinalizeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newNamespace := obj.(*api.Namespace)
|
newNamespace := obj.(*api.Namespace)
|
||||||
|
@ -37,6 +37,7 @@ import (
|
|||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/node"
|
"k8s.io/kubernetes/pkg/registry/core/node"
|
||||||
noderest "k8s.io/kubernetes/pkg/registry/core/node/rest"
|
noderest "k8s.io/kubernetes/pkg/registry/core/node/rest"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeStorage includes storage for nodes and all sub resources.
|
// NodeStorage includes storage for nodes and all sub resources.
|
||||||
@ -77,6 +78,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
// NewStorage returns a NodeStorage object that will work against nodes.
|
// NewStorage returns a NodeStorage object that will work against nodes.
|
||||||
func NewStorage(optsGetter generic.RESTOptionsGetter, kubeletClientConfig client.KubeletClientConfig, proxyTransport http.RoundTripper) (*NodeStorage, error) {
|
func NewStorage(optsGetter generic.RESTOptionsGetter, kubeletClientConfig client.KubeletClientConfig, proxyTransport http.RoundTripper) (*NodeStorage, error) {
|
||||||
store := &genericregistry.Store{
|
store := &genericregistry.Store{
|
||||||
@ -88,6 +94,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, kubeletClientConfig client
|
|||||||
CreateStrategy: node.Strategy,
|
CreateStrategy: node.Strategy,
|
||||||
UpdateStrategy: node.Strategy,
|
UpdateStrategy: node.Strategy,
|
||||||
DeleteStrategy: node.Strategy,
|
DeleteStrategy: node.Strategy,
|
||||||
|
ResetFieldsStrategy: node.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -102,6 +109,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, kubeletClientConfig client
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = node.StatusStrategy
|
statusStore.UpdateStrategy = node.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = node.StatusStrategy
|
||||||
|
|
||||||
// Set up REST handlers
|
// Set up REST handlers
|
||||||
nodeREST := &REST{Store: store, proxyTransport: proxyTransport}
|
nodeREST := &REST{Store: store, proxyTransport: proxyTransport}
|
||||||
|
@ -41,6 +41,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/client"
|
"k8s.io/kubernetes/pkg/kubelet/client"
|
||||||
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// nodeStrategy implements behavior for nodes
|
// nodeStrategy implements behavior for nodes
|
||||||
@ -58,6 +59,18 @@ func (nodeStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (nodeStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// AllowCreateOnUpdate is false for nodes.
|
// AllowCreateOnUpdate is false for nodes.
|
||||||
func (nodeStrategy) AllowCreateOnUpdate() bool {
|
func (nodeStrategy) AllowCreateOnUpdate() bool {
|
||||||
return false
|
return false
|
||||||
@ -147,6 +160,18 @@ type nodeStatusStrategy struct {
|
|||||||
|
|
||||||
var StatusStrategy = nodeStatusStrategy{Strategy}
|
var StatusStrategy = nodeStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (nodeStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (nodeStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (nodeStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newNode := obj.(*api.Node)
|
newNode := obj.(*api.Node)
|
||||||
oldNode := old.(*api.Node)
|
oldNode := old.(*api.Node)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/persistentvolume"
|
"k8s.io/kubernetes/pkg/registry/core/persistentvolume"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for persistent volumes.
|
// REST implements a RESTStorage for persistent volumes.
|
||||||
@ -48,6 +49,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
UpdateStrategy: persistentvolume.Strategy,
|
UpdateStrategy: persistentvolume.Strategy,
|
||||||
DeleteStrategy: persistentvolume.Strategy,
|
DeleteStrategy: persistentvolume.Strategy,
|
||||||
ReturnDeletedObject: true,
|
ReturnDeletedObject: true,
|
||||||
|
ResetFieldsStrategy: persistentvolume.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -58,6 +60,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = persistentvolume.StatusStrategy
|
statusStore.UpdateStrategy = persistentvolume.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = persistentvolume.StatusStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
@ -91,3 +94,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
volumevalidation "k8s.io/kubernetes/pkg/volume/validation"
|
volumevalidation "k8s.io/kubernetes/pkg/volume/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// persistentvolumeStrategy implements behavior for PersistentVolume objects
|
// persistentvolumeStrategy implements behavior for PersistentVolume objects
|
||||||
@ -48,6 +49,18 @@ func (persistentvolumeStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (persistentvolumeStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation.
|
// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation.
|
||||||
func (persistentvolumeStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (persistentvolumeStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
pv := obj.(*api.PersistentVolume)
|
pv := obj.(*api.PersistentVolume)
|
||||||
@ -96,6 +109,18 @@ type persistentvolumeStatusStrategy struct {
|
|||||||
|
|
||||||
var StatusStrategy = persistentvolumeStatusStrategy{Strategy}
|
var StatusStrategy = persistentvolumeStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (persistentvolumeStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForUpdate sets the Spec field which is not allowed to be changed when updating a PV's Status
|
// PrepareForUpdate sets the Spec field which is not allowed to be changed when updating a PV's Status
|
||||||
func (persistentvolumeStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (persistentvolumeStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newPv := obj.(*api.PersistentVolume)
|
newPv := obj.(*api.PersistentVolume)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/persistentvolumeclaim"
|
"k8s.io/kubernetes/pkg/registry/core/persistentvolumeclaim"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for persistent volume claims.
|
// REST implements a RESTStorage for persistent volume claims.
|
||||||
@ -48,6 +49,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
UpdateStrategy: persistentvolumeclaim.Strategy,
|
UpdateStrategy: persistentvolumeclaim.Strategy,
|
||||||
DeleteStrategy: persistentvolumeclaim.Strategy,
|
DeleteStrategy: persistentvolumeclaim.Strategy,
|
||||||
ReturnDeletedObject: true,
|
ReturnDeletedObject: true,
|
||||||
|
ResetFieldsStrategy: persistentvolumeclaim.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -58,6 +60,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = persistentvolumeclaim.StatusStrategy
|
statusStore.UpdateStrategy = persistentvolumeclaim.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = persistentvolumeclaim.StatusStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
@ -91,3 +94,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// persistentvolumeclaimStrategy implements behavior for PersistentVolumeClaim objects
|
// persistentvolumeclaimStrategy implements behavior for PersistentVolumeClaim objects
|
||||||
@ -49,6 +50,18 @@ func (persistentvolumeclaimStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (persistentvolumeclaimStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the Status field which is not allowed to be set by end users on creation.
|
// PrepareForCreate clears the Status field which is not allowed to be set by end users on creation.
|
||||||
func (persistentvolumeclaimStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (persistentvolumeclaimStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
pvc := obj.(*api.PersistentVolumeClaim)
|
pvc := obj.(*api.PersistentVolumeClaim)
|
||||||
@ -94,6 +107,18 @@ type persistentvolumeclaimStatusStrategy struct {
|
|||||||
|
|
||||||
var StatusStrategy = persistentvolumeclaimStatusStrategy{Strategy}
|
var StatusStrategy = persistentvolumeclaimStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (persistentvolumeclaimStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForUpdate sets the Spec field which is not allowed to be changed when updating a PV's Status
|
// PrepareForUpdate sets the Spec field which is not allowed to be changed when updating a PV's Status
|
||||||
func (persistentvolumeclaimStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (persistentvolumeclaimStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newPv := obj.(*api.PersistentVolumeClaim)
|
newPv := obj.(*api.PersistentVolumeClaim)
|
||||||
|
@ -44,6 +44,7 @@ import (
|
|||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
registrypod "k8s.io/kubernetes/pkg/registry/core/pod"
|
registrypod "k8s.io/kubernetes/pkg/registry/core/pod"
|
||||||
podrest "k8s.io/kubernetes/pkg/registry/core/pod/rest"
|
podrest "k8s.io/kubernetes/pkg/registry/core/pod/rest"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PodStorage includes storage for pods and all sub resources
|
// PodStorage includes storage for pods and all sub resources
|
||||||
@ -79,6 +80,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, k client.ConnectionInfoGet
|
|||||||
CreateStrategy: registrypod.Strategy,
|
CreateStrategy: registrypod.Strategy,
|
||||||
UpdateStrategy: registrypod.Strategy,
|
UpdateStrategy: registrypod.Strategy,
|
||||||
DeleteStrategy: registrypod.Strategy,
|
DeleteStrategy: registrypod.Strategy,
|
||||||
|
ResetFieldsStrategy: registrypod.Strategy,
|
||||||
ReturnDeletedObject: true,
|
ReturnDeletedObject: true,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
@ -95,6 +97,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, k client.ConnectionInfoGet
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = registrypod.StatusStrategy
|
statusStore.UpdateStrategy = registrypod.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = registrypod.StatusStrategy
|
||||||
ephemeralContainersStore := *store
|
ephemeralContainersStore := *store
|
||||||
ephemeralContainersStore.UpdateStrategy = registrypod.EphemeralContainersStrategy
|
ephemeralContainersStore.UpdateStrategy = registrypod.EphemeralContainersStrategy
|
||||||
|
|
||||||
@ -278,6 +281,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
// EphemeralContainersREST implements the REST endpoint for adding EphemeralContainers
|
// EphemeralContainersREST implements the REST endpoint for adding EphemeralContainers
|
||||||
type EphemeralContainersREST struct {
|
type EphemeralContainersREST struct {
|
||||||
store *genericregistry.Store
|
store *genericregistry.Store
|
||||||
|
@ -48,6 +48,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/client"
|
"k8s.io/kubernetes/pkg/kubelet/client"
|
||||||
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// podStrategy implements behavior for Pods
|
// podStrategy implements behavior for Pods
|
||||||
@ -65,6 +66,18 @@ func (podStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (podStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
||||||
func (podStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (podStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
pod := obj.(*api.Pod)
|
pod := obj.(*api.Pod)
|
||||||
@ -154,6 +167,18 @@ type podStatusStrategy struct {
|
|||||||
// StatusStrategy wraps and exports the used podStrategy for the storage package.
|
// StatusStrategy wraps and exports the used podStrategy for the storage package.
|
||||||
var StatusStrategy = podStatusStrategy{Strategy}
|
var StatusStrategy = podStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (podStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("metadata", "deletionTimestamp"),
|
||||||
|
fieldpath.MakePathOrDie("metadata", "ownerReferences"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (podStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (podStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newPod := obj.(*api.Pod)
|
newPod := obj.(*api.Pod)
|
||||||
oldPod := old.(*api.Pod)
|
oldPod := old.(*api.Pod)
|
||||||
|
@ -39,6 +39,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/replicationcontroller"
|
"k8s.io/kubernetes/pkg/registry/core/replicationcontroller"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ControllerStorage includes dummy storage for Replication Controllers and for Scale subresource.
|
// ControllerStorage includes dummy storage for Replication Controllers and for Scale subresource.
|
||||||
@ -76,6 +77,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: replicationcontroller.Strategy,
|
CreateStrategy: replicationcontroller.Strategy,
|
||||||
UpdateStrategy: replicationcontroller.Strategy,
|
UpdateStrategy: replicationcontroller.Strategy,
|
||||||
DeleteStrategy: replicationcontroller.Strategy,
|
DeleteStrategy: replicationcontroller.Strategy,
|
||||||
|
ResetFieldsStrategy: replicationcontroller.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -86,6 +88,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = replicationcontroller.StatusStrategy
|
statusStore.UpdateStrategy = replicationcontroller.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = replicationcontroller.StatusStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
@ -127,6 +130,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
type ScaleREST struct {
|
type ScaleREST struct {
|
||||||
store *genericregistry.Store
|
store *genericregistry.Store
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rcStrategy implements verification logic for Replication Controllers.
|
// rcStrategy implements verification logic for Replication Controllers.
|
||||||
@ -73,6 +74,18 @@ func (rcStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (rcStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of a replication controller before creation.
|
// PrepareForCreate clears the status of a replication controller before creation.
|
||||||
func (rcStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (rcStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
controller := obj.(*api.ReplicationController)
|
controller := obj.(*api.ReplicationController)
|
||||||
@ -192,6 +205,16 @@ type rcStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = rcStatusStrategy{Strategy}
|
var StatusStrategy = rcStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (rcStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (rcStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (rcStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newRc := obj.(*api.ReplicationController)
|
newRc := obj.(*api.ReplicationController)
|
||||||
oldRc := old.(*api.ReplicationController)
|
oldRc := old.(*api.ReplicationController)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/resourcequota"
|
"k8s.io/kubernetes/pkg/registry/core/resourcequota"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for resource quotas.
|
// REST implements a RESTStorage for resource quotas.
|
||||||
@ -46,6 +47,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: resourcequota.Strategy,
|
CreateStrategy: resourcequota.Strategy,
|
||||||
UpdateStrategy: resourcequota.Strategy,
|
UpdateStrategy: resourcequota.Strategy,
|
||||||
DeleteStrategy: resourcequota.Strategy,
|
DeleteStrategy: resourcequota.Strategy,
|
||||||
|
ResetFieldsStrategy: resourcequota.Strategy,
|
||||||
ReturnDeletedObject: true,
|
ReturnDeletedObject: true,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
@ -57,6 +59,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = resourcequota.StatusStrategy
|
statusStore.UpdateStrategy = resourcequota.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = resourcequota.StatusStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
@ -90,3 +93,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// resourcequotaStrategy implements behavior for ResourceQuota objects
|
// resourcequotaStrategy implements behavior for ResourceQuota objects
|
||||||
@ -44,6 +45,18 @@ func (resourcequotaStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (resourcequotaStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
||||||
func (resourcequotaStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (resourcequotaStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
resourcequota := obj.(*api.ResourceQuota)
|
resourcequota := obj.(*api.ResourceQuota)
|
||||||
@ -91,6 +104,18 @@ type resourcequotaStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = resourcequotaStatusStrategy{Strategy}
|
var StatusStrategy = resourcequotaStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (resourcequotaStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (resourcequotaStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (resourcequotaStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newResourcequota := obj.(*api.ResourceQuota)
|
newResourcequota := obj.(*api.ResourceQuota)
|
||||||
oldResourcequota := old.(*api.ResourceQuota)
|
oldResourcequota := old.(*api.ResourceQuota)
|
||||||
|
@ -36,18 +36,17 @@ import (
|
|||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/apiserver/pkg/util/dryrun"
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
apiservice "k8s.io/kubernetes/pkg/api/service"
|
apiservice "k8s.io/kubernetes/pkg/api/service"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
registry "k8s.io/kubernetes/pkg/registry/core/service"
|
registry "k8s.io/kubernetes/pkg/registry/core/service"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/service/portallocator"
|
"k8s.io/kubernetes/pkg/registry/core/service/portallocator"
|
||||||
netutil "k8s.io/utils/net"
|
netutil "k8s.io/utils/net"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST adapts a service registry into apiserver's RESTStorage model.
|
// REST adapts a service registry into apiserver's RESTStorage model.
|
||||||
@ -80,6 +79,7 @@ type ServiceStorage interface {
|
|||||||
rest.GracefulDeleter
|
rest.GracefulDeleter
|
||||||
rest.Watcher
|
rest.Watcher
|
||||||
rest.StorageVersionProvider
|
rest.StorageVersionProvider
|
||||||
|
rest.ResetFieldsStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
type EndpointsStorage interface {
|
type EndpointsStorage interface {
|
||||||
@ -514,6 +514,11 @@ func (rs *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObj
|
|||||||
return out, created, err
|
return out, created, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields implements rest.ResetFieldsStrategy
|
||||||
|
func (rs *REST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return rs.services.GetResetFields()
|
||||||
|
}
|
||||||
|
|
||||||
// Implement Redirector.
|
// Implement Redirector.
|
||||||
var _ = rest.Redirector(&REST{})
|
var _ = rest.Redirector(&REST{})
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/service/portallocator"
|
"k8s.io/kubernetes/pkg/registry/core/service/portallocator"
|
||||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
|
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
@ -167,6 +168,11 @@ func (s *serviceStorage) StorageVersion() runtime.GroupVersioner {
|
|||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields implements rest.ResetFieldsStrategy
|
||||||
|
func (s *serviceStorage) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewTestREST(t *testing.T, endpoints *api.EndpointsList, ipFamilies []api.IPFamily) (*REST, *serviceStorage, *etcd3testing.EtcdTestServer) {
|
func NewTestREST(t *testing.T, endpoints *api.EndpointsList, ipFamilies []api.IPFamily) (*REST, *serviceStorage, *etcd3testing.EtcdTestServer) {
|
||||||
return NewTestRESTWithPods(t, endpoints, nil, ipFamilies)
|
return NewTestRESTWithPods(t, endpoints, nil, ipFamilies)
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/registry/core/service"
|
"k8s.io/kubernetes/pkg/registry/core/service"
|
||||||
registry "k8s.io/kubernetes/pkg/registry/core/service"
|
registry "k8s.io/kubernetes/pkg/registry/core/service"
|
||||||
svcreg "k8s.io/kubernetes/pkg/registry/core/service"
|
svcreg "k8s.io/kubernetes/pkg/registry/core/service"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
|
|
||||||
netutil "k8s.io/utils/net"
|
netutil "k8s.io/utils/net"
|
||||||
)
|
)
|
||||||
@ -57,6 +58,7 @@ func NewGenericREST(optsGetter generic.RESTOptionsGetter, serviceCIDR net.IPNet,
|
|||||||
CreateStrategy: strategy,
|
CreateStrategy: strategy,
|
||||||
UpdateStrategy: strategy,
|
UpdateStrategy: strategy,
|
||||||
DeleteStrategy: strategy,
|
DeleteStrategy: strategy,
|
||||||
|
ResetFieldsStrategy: strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -66,7 +68,9 @@ func NewGenericREST(optsGetter generic.RESTOptionsGetter, serviceCIDR net.IPNet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = service.NewServiceStatusStrategy(strategy)
|
statusStrategy := service.NewServiceStatusStrategy(strategy)
|
||||||
|
statusStore.UpdateStrategy = statusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = statusStrategy
|
||||||
|
|
||||||
ipv4 := api.IPv4Protocol
|
ipv4 := api.IPv4Protocol
|
||||||
ipv6 := api.IPv6Protocol
|
ipv6 := api.IPv6Protocol
|
||||||
@ -125,6 +129,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
// defaultOnRead sets interlinked fields that were not previously set on read.
|
// defaultOnRead sets interlinked fields that were not previously set on read.
|
||||||
// We can't do this in the normal defaulting path because that same logic
|
// We can't do this in the normal defaulting path because that same logic
|
||||||
// applies on Get, Create, and Update, but we need to distinguish between them.
|
// applies on Get, Create, and Update, but we need to distinguish between them.
|
||||||
@ -212,7 +221,6 @@ func (r *GenericREST) defaultOnReadService(service *api.Service) {
|
|||||||
service.Spec.IPFamilyPolicy = &singleStack
|
service.Spec.IPFamilyPolicy = &singleStack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// headful
|
// headful
|
||||||
// make sure a slice exists to receive the families
|
// make sure a slice exists to receive the families
|
||||||
|
@ -32,10 +32,12 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
netutil "k8s.io/utils/net"
|
netutil "k8s.io/utils/net"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Strategy interface {
|
type Strategy interface {
|
||||||
rest.RESTCreateUpdateStrategy
|
rest.RESTCreateUpdateStrategy
|
||||||
|
rest.ResetFieldsStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
// svcStrategy implements behavior for Services
|
// svcStrategy implements behavior for Services
|
||||||
@ -90,6 +92,18 @@ func (svcStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (svcStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate sets contextual defaults and clears fields that are not allowed to be set by end users on creation.
|
// PrepareForCreate sets contextual defaults and clears fields that are not allowed to be set by end users on creation.
|
||||||
func (strategy svcStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (strategy svcStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
service := obj.(*api.Service)
|
service := obj.(*api.Service)
|
||||||
@ -263,6 +277,18 @@ func NewServiceStatusStrategy(strategy Strategy) Strategy {
|
|||||||
return serviceStatusStrategy{strategy}
|
return serviceStatusStrategy{strategy}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (serviceStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
||||||
func (serviceStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (serviceStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newService := obj.(*api.Service)
|
newService := obj.(*api.Service)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/flowcontrol/flowschema"
|
"k8s.io/kubernetes/pkg/registry/flowcontrol/flowschema"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FlowSchemaStorage implements storage for flow schema.
|
// FlowSchemaStorage implements storage for flow schema.
|
||||||
@ -52,6 +53,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: flowschema.Strategy,
|
CreateStrategy: flowschema.Strategy,
|
||||||
UpdateStrategy: flowschema.Strategy,
|
UpdateStrategy: flowschema.Strategy,
|
||||||
DeleteStrategy: flowschema.Strategy,
|
DeleteStrategy: flowschema.Strategy,
|
||||||
|
ResetFieldsStrategy: flowschema.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -64,6 +66,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
statusStore.CreateStrategy = nil
|
statusStore.CreateStrategy = nil
|
||||||
statusStore.UpdateStrategy = flowschema.StatusStrategy
|
statusStore.UpdateStrategy = flowschema.StatusStrategy
|
||||||
statusStore.DeleteStrategy = nil
|
statusStore.DeleteStrategy = nil
|
||||||
|
statusStore.ResetFieldsStrategy = flowschema.StatusStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
@ -89,3 +92,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/apis/flowcontrol"
|
"k8s.io/kubernetes/pkg/apis/flowcontrol"
|
||||||
"k8s.io/kubernetes/pkg/apis/flowcontrol/validation"
|
"k8s.io/kubernetes/pkg/apis/flowcontrol/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// flowSchemaStrategy implements verification logic for FlowSchema.
|
// flowSchemaStrategy implements verification logic for FlowSchema.
|
||||||
@ -42,6 +43,21 @@ func (flowSchemaStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (flowSchemaStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"flowcontrol.apiserver.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"flowcontrol.apiserver.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of a flow-schema before creation.
|
// PrepareForCreate clears the status of a flow-schema before creation.
|
||||||
func (flowSchemaStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (flowSchemaStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
fl := obj.(*flowcontrol.FlowSchema)
|
fl := obj.(*flowcontrol.FlowSchema)
|
||||||
@ -91,6 +107,23 @@ type flowSchemaStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic that applies when updating flow-schema objects' status.
|
// StatusStrategy is the default logic that applies when updating flow-schema objects' status.
|
||||||
var StatusStrategy = flowSchemaStatusStrategy{Strategy}
|
var StatusStrategy = flowSchemaStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (flowSchemaStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"flowcontrol.apiserver.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
"flowcontrol.apiserver.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (flowSchemaStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (flowSchemaStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newFlowSchema := obj.(*flowcontrol.FlowSchema)
|
newFlowSchema := obj.(*flowcontrol.FlowSchema)
|
||||||
oldFlowSchema := old.(*flowcontrol.FlowSchema)
|
oldFlowSchema := old.(*flowcontrol.FlowSchema)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/flowcontrol/prioritylevelconfiguration"
|
"k8s.io/kubernetes/pkg/registry/flowcontrol/prioritylevelconfiguration"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PriorityLevelConfigurationStorage implements storage for priority level configuration.
|
// PriorityLevelConfigurationStorage implements storage for priority level configuration.
|
||||||
@ -52,6 +53,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: prioritylevelconfiguration.Strategy,
|
CreateStrategy: prioritylevelconfiguration.Strategy,
|
||||||
UpdateStrategy: prioritylevelconfiguration.Strategy,
|
UpdateStrategy: prioritylevelconfiguration.Strategy,
|
||||||
DeleteStrategy: prioritylevelconfiguration.Strategy,
|
DeleteStrategy: prioritylevelconfiguration.Strategy,
|
||||||
|
ResetFieldsStrategy: prioritylevelconfiguration.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -64,6 +66,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
statusStore.CreateStrategy = nil
|
statusStore.CreateStrategy = nil
|
||||||
statusStore.UpdateStrategy = prioritylevelconfiguration.StatusStrategy
|
statusStore.UpdateStrategy = prioritylevelconfiguration.StatusStrategy
|
||||||
statusStore.DeleteStrategy = nil
|
statusStore.DeleteStrategy = nil
|
||||||
|
statusStore.ResetFieldsStrategy = prioritylevelconfiguration.StatusStrategy
|
||||||
|
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
@ -89,3 +92,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/apis/flowcontrol"
|
"k8s.io/kubernetes/pkg/apis/flowcontrol"
|
||||||
"k8s.io/kubernetes/pkg/apis/flowcontrol/validation"
|
"k8s.io/kubernetes/pkg/apis/flowcontrol/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// priorityLevelConfigurationStrategy implements verification logic for priority level configurations.
|
// priorityLevelConfigurationStrategy implements verification logic for priority level configurations.
|
||||||
@ -42,6 +43,21 @@ func (priorityLevelConfigurationStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (priorityLevelConfigurationStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"flowcontrol.apiserver.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"flowcontrol.apiserver.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of a priority-level-configuration before creation.
|
// PrepareForCreate clears the status of a priority-level-configuration before creation.
|
||||||
func (priorityLevelConfigurationStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (priorityLevelConfigurationStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
pl := obj.(*flowcontrol.PriorityLevelConfiguration)
|
pl := obj.(*flowcontrol.PriorityLevelConfiguration)
|
||||||
@ -91,6 +107,23 @@ type priorityLevelConfigurationStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic that applies when updating priority level configuration objects' status.
|
// StatusStrategy is the default logic that applies when updating priority level configuration objects' status.
|
||||||
var StatusStrategy = priorityLevelConfigurationStatusStrategy{Strategy}
|
var StatusStrategy = priorityLevelConfigurationStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (priorityLevelConfigurationStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"flowcontrol.apiserver.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
),
|
||||||
|
"flowcontrol.apiserver.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (priorityLevelConfigurationStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (priorityLevelConfigurationStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newPriorityLevelConfiguration := obj.(*flowcontrol.PriorityLevelConfiguration)
|
newPriorityLevelConfiguration := obj.(*flowcontrol.PriorityLevelConfiguration)
|
||||||
oldPriorityLevelConfiguration := old.(*flowcontrol.PriorityLevelConfiguration)
|
oldPriorityLevelConfiguration := old.(*flowcontrol.PriorityLevelConfiguration)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/networking/ingress"
|
"k8s.io/kubernetes/pkg/registry/networking/ingress"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for replication controllers
|
// REST implements a RESTStorage for replication controllers
|
||||||
@ -46,6 +47,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: ingress.Strategy,
|
CreateStrategy: ingress.Strategy,
|
||||||
UpdateStrategy: ingress.Strategy,
|
UpdateStrategy: ingress.Strategy,
|
||||||
DeleteStrategy: ingress.Strategy,
|
DeleteStrategy: ingress.Strategy,
|
||||||
|
ResetFieldsStrategy: ingress.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -56,6 +58,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = ingress.StatusStrategy
|
statusStore.UpdateStrategy = ingress.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = ingress.StatusStrategy
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,3 +91,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ package ingress
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@ -27,6 +28,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/apis/networking"
|
"k8s.io/kubernetes/pkg/apis/networking"
|
||||||
"k8s.io/kubernetes/pkg/apis/networking/validation"
|
"k8s.io/kubernetes/pkg/apis/networking/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ingressStrategy implements verification logic for Replication Ingress.
|
// ingressStrategy implements verification logic for Replication Ingress.
|
||||||
@ -43,6 +45,24 @@ func (ingressStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (ingressStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"extensions/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"networking.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"networking.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of an Ingress before creation.
|
// PrepareForCreate clears the status of an Ingress before creation.
|
||||||
func (ingressStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (ingressStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
ingress := obj.(*networking.Ingress)
|
ingress := obj.(*networking.Ingress)
|
||||||
@ -108,6 +128,24 @@ type ingressStatusStrategy struct {
|
|||||||
// StatusStrategy implements logic used to validate and prepare for updates of the status subresource
|
// StatusStrategy implements logic used to validate and prepare for updates of the status subresource
|
||||||
var StatusStrategy = ingressStatusStrategy{Strategy}
|
var StatusStrategy = ingressStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (ingressStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"extensions/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
"networking.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
"networking.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
||||||
func (ingressStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (ingressStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newIngress := obj.(*networking.Ingress)
|
newIngress := obj.(*networking.Ingress)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/policy/poddisruptionbudget"
|
"k8s.io/kubernetes/pkg/registry/policy/poddisruptionbudget"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for pod disruption budgets against etcd.
|
// REST implements a RESTStorage for pod disruption budgets against etcd.
|
||||||
@ -46,6 +47,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
CreateStrategy: poddisruptionbudget.Strategy,
|
CreateStrategy: poddisruptionbudget.Strategy,
|
||||||
UpdateStrategy: poddisruptionbudget.Strategy,
|
UpdateStrategy: poddisruptionbudget.Strategy,
|
||||||
DeleteStrategy: poddisruptionbudget.Strategy,
|
DeleteStrategy: poddisruptionbudget.Strategy,
|
||||||
|
ResetFieldsStrategy: poddisruptionbudget.Strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
@ -56,6 +58,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = poddisruptionbudget.StatusStrategy
|
statusStore.UpdateStrategy = poddisruptionbudget.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = poddisruptionbudget.StatusStrategy
|
||||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,3 +88,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/apis/policy"
|
"k8s.io/kubernetes/pkg/apis/policy"
|
||||||
"k8s.io/kubernetes/pkg/apis/policy/validation"
|
"k8s.io/kubernetes/pkg/apis/policy/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// podDisruptionBudgetStrategy implements verification logic for PodDisruptionBudgets.
|
// podDisruptionBudgetStrategy implements verification logic for PodDisruptionBudgets.
|
||||||
@ -44,6 +45,21 @@ func (podDisruptionBudgetStrategy) NamespaceScoped() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (podDisruptionBudgetStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"policy/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"policy/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of an PodDisruptionBudget before creation.
|
// PrepareForCreate clears the status of an PodDisruptionBudget before creation.
|
||||||
func (podDisruptionBudgetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (podDisruptionBudgetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
podDisruptionBudget := obj.(*policy.PodDisruptionBudget)
|
podDisruptionBudget := obj.(*policy.PodDisruptionBudget)
|
||||||
@ -101,6 +117,21 @@ type podDisruptionBudgetStatusStrategy struct {
|
|||||||
// StatusStrategy is the default logic invoked when updating object status.
|
// StatusStrategy is the default logic invoked when updating object status.
|
||||||
var StatusStrategy = podDisruptionBudgetStatusStrategy{Strategy}
|
var StatusStrategy = podDisruptionBudgetStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (podDisruptionBudgetStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"policy/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
"policy/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
||||||
func (podDisruptionBudgetStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (podDisruptionBudgetStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newPodDisruptionBudget := obj.(*policy.PodDisruptionBudget)
|
newPodDisruptionBudget := obj.(*policy.PodDisruptionBudget)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/storage/volumeattachment"
|
"k8s.io/kubernetes/pkg/registry/storage/volumeattachment"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VolumeAttachmentStorage includes storage for VolumeAttachments and all subresources
|
// VolumeAttachmentStorage includes storage for VolumeAttachments and all subresources
|
||||||
@ -52,6 +53,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter) (*VolumeAttachmentStorage,
|
|||||||
CreateStrategy: volumeattachment.Strategy,
|
CreateStrategy: volumeattachment.Strategy,
|
||||||
UpdateStrategy: volumeattachment.Strategy,
|
UpdateStrategy: volumeattachment.Strategy,
|
||||||
DeleteStrategy: volumeattachment.Strategy,
|
DeleteStrategy: volumeattachment.Strategy,
|
||||||
|
ResetFieldsStrategy: volumeattachment.Strategy,
|
||||||
ReturnDeletedObject: true,
|
ReturnDeletedObject: true,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
@ -63,6 +65,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter) (*VolumeAttachmentStorage,
|
|||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = volumeattachment.StatusStrategy
|
statusStore.UpdateStrategy = volumeattachment.StatusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = volumeattachment.StatusStrategy
|
||||||
|
|
||||||
return &VolumeAttachmentStorage{
|
return &VolumeAttachmentStorage{
|
||||||
VolumeAttachment: &REST{store},
|
VolumeAttachment: &REST{store},
|
||||||
@ -93,3 +96,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/storage"
|
"k8s.io/kubernetes/pkg/apis/storage"
|
||||||
"k8s.io/kubernetes/pkg/apis/storage/validation"
|
"k8s.io/kubernetes/pkg/apis/storage/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// volumeAttachmentStrategy implements behavior for VolumeAttachment objects
|
// volumeAttachmentStrategy implements behavior for VolumeAttachment objects
|
||||||
@ -47,6 +48,18 @@ func (volumeAttachmentStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (volumeAttachmentStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"storage.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation.
|
// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation.
|
||||||
func (volumeAttachmentStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (volumeAttachmentStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
var groupVersion schema.GroupVersion
|
var groupVersion schema.GroupVersion
|
||||||
@ -143,6 +156,19 @@ type volumeAttachmentStatusStrategy struct {
|
|||||||
// VolumeAttachmentStatus subresource via the REST API.
|
// VolumeAttachmentStatus subresource via the REST API.
|
||||||
var StatusStrategy = volumeAttachmentStatusStrategy{Strategy}
|
var StatusStrategy = volumeAttachmentStatusStrategy{Strategy}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (volumeAttachmentStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"storage.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a VolumeAttachment
|
// PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a VolumeAttachment
|
||||||
func (volumeAttachmentStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (volumeAttachmentStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newVolumeAttachment := obj.(*storage.VolumeAttachment)
|
newVolumeAttachment := obj.(*storage.VolumeAttachment)
|
||||||
|
@ -27,6 +27,7 @@ require (
|
|||||||
k8s.io/klog/v2 v2.5.0
|
k8s.io/klog/v2 v2.5.0
|
||||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7
|
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7
|
||||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
|
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.0.3
|
||||||
sigs.k8s.io/yaml v1.2.0
|
sigs.k8s.io/yaml v1.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -326,6 +326,8 @@ type CustomResourceDefinitionCondition struct {
|
|||||||
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
|
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
|
||||||
type CustomResourceDefinitionStatus struct {
|
type CustomResourceDefinitionStatus struct {
|
||||||
// Conditions indicate state for particular aspects of a CustomResourceDefinition
|
// Conditions indicate state for particular aspects of a CustomResourceDefinition
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
Conditions []CustomResourceDefinitionCondition
|
Conditions []CustomResourceDefinitionCondition
|
||||||
|
|
||||||
// AcceptedNames are the names that are actually being used to serve discovery
|
// AcceptedNames are the names that are actually being used to serve discovery
|
||||||
|
@ -234,6 +234,8 @@ message CustomResourceDefinitionSpec {
|
|||||||
message CustomResourceDefinitionStatus {
|
message CustomResourceDefinitionStatus {
|
||||||
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
||||||
// +optional
|
// +optional
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
repeated CustomResourceDefinitionCondition conditions = 1;
|
repeated CustomResourceDefinitionCondition conditions = 1;
|
||||||
|
|
||||||
// acceptedNames are the names that are actually being used to serve discovery.
|
// acceptedNames are the names that are actually being used to serve discovery.
|
||||||
|
@ -329,6 +329,8 @@ type CustomResourceDefinitionCondition struct {
|
|||||||
type CustomResourceDefinitionStatus struct {
|
type CustomResourceDefinitionStatus struct {
|
||||||
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
||||||
// +optional
|
// +optional
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
Conditions []CustomResourceDefinitionCondition `json:"conditions" protobuf:"bytes,1,opt,name=conditions"`
|
Conditions []CustomResourceDefinitionCondition `json:"conditions" protobuf:"bytes,1,opt,name=conditions"`
|
||||||
|
|
||||||
// acceptedNames are the names that are actually being used to serve discovery.
|
// acceptedNames are the names that are actually being used to serve discovery.
|
||||||
|
@ -280,6 +280,8 @@ message CustomResourceDefinitionSpec {
|
|||||||
message CustomResourceDefinitionStatus {
|
message CustomResourceDefinitionStatus {
|
||||||
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
||||||
// +optional
|
// +optional
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
repeated CustomResourceDefinitionCondition conditions = 1;
|
repeated CustomResourceDefinitionCondition conditions = 1;
|
||||||
|
|
||||||
// acceptedNames are the names that are actually being used to serve discovery.
|
// acceptedNames are the names that are actually being used to serve discovery.
|
||||||
|
@ -361,6 +361,8 @@ type CustomResourceDefinitionCondition struct {
|
|||||||
type CustomResourceDefinitionStatus struct {
|
type CustomResourceDefinitionStatus struct {
|
||||||
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
||||||
// +optional
|
// +optional
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
Conditions []CustomResourceDefinitionCondition `json:"conditions" protobuf:"bytes,1,opt,name=conditions"`
|
Conditions []CustomResourceDefinitionCondition `json:"conditions" protobuf:"bytes,1,opt,name=conditions"`
|
||||||
|
|
||||||
// acceptedNames are the names that are actually being used to serve discovery.
|
// acceptedNames are the names that are actually being used to serve discovery.
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
goopenapispec "github.com/go-openapi/spec"
|
goopenapispec "github.com/go-openapi/spec"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
|
|
||||||
apiextensionshelpers "k8s.io/apiextensions-apiserver/pkg/apihelpers"
|
apiextensionshelpers "k8s.io/apiextensions-apiserver/pkg/apihelpers"
|
||||||
apiextensionsinternal "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
apiextensionsinternal "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||||
@ -865,14 +866,12 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
|
|||||||
MaxRequestBodyBytes: r.maxRequestBodyBytes,
|
MaxRequestBodyBytes: r.maxRequestBodyBytes,
|
||||||
}
|
}
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
||||||
|
resetFields := storages[v.Name].CustomResource.GetResetFields()
|
||||||
reqScope := *requestScopes[v.Name]
|
reqScope := *requestScopes[v.Name]
|
||||||
reqScope.FieldManager, err = fieldmanager.NewDefaultCRDFieldManager(
|
reqScope, err = scopeWithFieldManager(
|
||||||
typeConverter,
|
typeConverter,
|
||||||
reqScope.Convertor,
|
reqScope,
|
||||||
reqScope.Defaulter,
|
resetFields,
|
||||||
reqScope.Creater,
|
|
||||||
reqScope.Kind,
|
|
||||||
reqScope.HubGroupVersion,
|
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -901,20 +900,6 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
|
|||||||
// override status subresource values
|
// override status subresource values
|
||||||
// shallow copy
|
// shallow copy
|
||||||
statusScope := *requestScopes[v.Name]
|
statusScope := *requestScopes[v.Name]
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
|
||||||
statusScope.FieldManager, err = fieldmanager.NewDefaultCRDFieldManager(
|
|
||||||
typeConverter,
|
|
||||||
statusScope.Convertor,
|
|
||||||
statusScope.Defaulter,
|
|
||||||
statusScope.Creater,
|
|
||||||
statusScope.Kind,
|
|
||||||
statusScope.HubGroupVersion,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statusScope.Subresource = "status"
|
statusScope.Subresource = "status"
|
||||||
statusScope.Namer = handlers.ContextBasedNaming{
|
statusScope.Namer = handlers.ContextBasedNaming{
|
||||||
SelfLinker: meta.NewAccessor(),
|
SelfLinker: meta.NewAccessor(),
|
||||||
@ -922,6 +907,20 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
|
|||||||
SelfLinkPathPrefix: selfLinkPrefix,
|
SelfLinkPathPrefix: selfLinkPrefix,
|
||||||
SelfLinkPathSuffix: "/status",
|
SelfLinkPathSuffix: "/status",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) && subresources != nil && subresources.Status != nil {
|
||||||
|
resetFields := storages[v.Name].Status.GetResetFields()
|
||||||
|
statusScope, err = scopeWithFieldManager(
|
||||||
|
typeConverter,
|
||||||
|
statusScope,
|
||||||
|
resetFields,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
statusScopes[v.Name] = &statusScope
|
statusScopes[v.Name] = &statusScope
|
||||||
|
|
||||||
if v.Deprecated {
|
if v.Deprecated {
|
||||||
@ -959,6 +958,24 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func scopeWithFieldManager(typeConverter fieldmanager.TypeConverter, reqScope handlers.RequestScope, resetFields map[fieldpath.APIVersion]*fieldpath.Set, ignoreManagedFieldsFromRequestObject bool) (handlers.RequestScope, error) {
|
||||||
|
fieldManager, err := fieldmanager.NewDefaultCRDFieldManager(
|
||||||
|
typeConverter,
|
||||||
|
reqScope.Convertor,
|
||||||
|
reqScope.Defaulter,
|
||||||
|
reqScope.Creater,
|
||||||
|
reqScope.Kind,
|
||||||
|
reqScope.HubGroupVersion,
|
||||||
|
ignoreManagedFieldsFromRequestObject,
|
||||||
|
resetFields,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return handlers.RequestScope{}, err
|
||||||
|
}
|
||||||
|
reqScope.FieldManager = fieldManager
|
||||||
|
return reqScope, nil
|
||||||
|
}
|
||||||
|
|
||||||
func defaultDeprecationWarning(deprecatedVersion string, crd apiextensionsv1.CustomResourceDefinitionSpec) string {
|
func defaultDeprecationWarning(deprecatedVersion string, crd apiextensionsv1.CustomResourceDefinitionSpec) string {
|
||||||
msg := fmt.Sprintf("%s/%s %s is deprecated", crd.Group, deprecatedVersion, crd.Names.Kind)
|
msg := fmt.Sprintf("%s/%s %s is deprecated", crd.Group, deprecatedVersion, crd.Names.Kind)
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CustomResourceStorage includes dummy storage for CustomResources, and their Status and Scale subresources.
|
// CustomResourceStorage includes dummy storage for CustomResources, and their Status and Scale subresources.
|
||||||
@ -95,6 +96,7 @@ func newREST(resource schema.GroupResource, kind, listKind schema.GroupVersionKi
|
|||||||
CreateStrategy: strategy,
|
CreateStrategy: strategy,
|
||||||
UpdateStrategy: strategy,
|
UpdateStrategy: strategy,
|
||||||
DeleteStrategy: strategy,
|
DeleteStrategy: strategy,
|
||||||
|
ResetFieldsStrategy: strategy,
|
||||||
|
|
||||||
TableConvertor: tableConvertor,
|
TableConvertor: tableConvertor,
|
||||||
}
|
}
|
||||||
@ -104,7 +106,9 @@ func newREST(resource schema.GroupResource, kind, listKind schema.GroupVersionKi
|
|||||||
}
|
}
|
||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
statusStore.UpdateStrategy = NewStatusStrategy(strategy)
|
statusStrategy := NewStatusStrategy(strategy)
|
||||||
|
statusStore.UpdateStrategy = statusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = statusStrategy
|
||||||
return &REST{store, categories}, &StatusREST{store: &statusStore}
|
return &REST{store, categories}, &StatusREST{store: &statusStore}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +203,11 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
type ScaleREST struct {
|
type ScaleREST struct {
|
||||||
store *genericregistry.Store
|
store *genericregistry.Store
|
||||||
specReplicasPath string
|
specReplicasPath string
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type statusStrategy struct {
|
type statusStrategy struct {
|
||||||
@ -32,6 +33,26 @@ func NewStatusStrategy(strategy customResourceStrategy) statusStrategy {
|
|||||||
return statusStrategy{strategy}
|
return statusStrategy{strategy}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (a statusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
fieldpath.APIVersion(a.customResourceStrategy.kind.GroupVersion().String()): fieldpath.NewSet(
|
||||||
|
// Note that if there are other top level fields unique to CRDs,
|
||||||
|
// those will also get removed by the apiserver prior to persisting,
|
||||||
|
// but wont be added to the resetFields set.
|
||||||
|
|
||||||
|
// This isn't an issue now, but if it becomes an issue in the future
|
||||||
|
// we might need a mechanism that is the inverse of resetFields where
|
||||||
|
// you specify only the fields to be kept rather than the fields to be wiped
|
||||||
|
// that way you could wipe everything but the status in this case.
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (a statusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (a statusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
// update is only allowed to set status
|
// update is only allowed to set status
|
||||||
newCustomResourceObject := obj.(*unstructured.Unstructured)
|
newCustomResourceObject := obj.(*unstructured.Unstructured)
|
||||||
|
@ -36,6 +36,7 @@ import (
|
|||||||
structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
||||||
structurallisttype "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/listtype"
|
structurallisttype "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/listtype"
|
||||||
schemaobjectmeta "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta"
|
schemaobjectmeta "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// customResourceStrategy implements behavior for CustomResources.
|
// customResourceStrategy implements behavior for CustomResources.
|
||||||
@ -48,6 +49,7 @@ type customResourceStrategy struct {
|
|||||||
structuralSchemas map[string]*structuralschema.Structural
|
structuralSchemas map[string]*structuralschema.Structural
|
||||||
status *apiextensions.CustomResourceSubresourceStatus
|
status *apiextensions.CustomResourceSubresourceStatus
|
||||||
scale *apiextensions.CustomResourceSubresourceScale
|
scale *apiextensions.CustomResourceSubresourceScale
|
||||||
|
kind schema.GroupVersionKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.GroupVersionKind, schemaValidator, statusSchemaValidator *validate.SchemaValidator, structuralSchemas map[string]*structuralschema.Structural, status *apiextensions.CustomResourceSubresourceStatus, scale *apiextensions.CustomResourceSubresourceScale) customResourceStrategy {
|
func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.GroupVersionKind, schemaValidator, statusSchemaValidator *validate.SchemaValidator, structuralSchemas map[string]*structuralschema.Structural, status *apiextensions.CustomResourceSubresourceStatus, scale *apiextensions.CustomResourceSubresourceScale) customResourceStrategy {
|
||||||
@ -64,6 +66,7 @@ func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.Gr
|
|||||||
statusSchemaValidator: statusSchemaValidator,
|
statusSchemaValidator: statusSchemaValidator,
|
||||||
},
|
},
|
||||||
structuralSchemas: structuralSchemas,
|
structuralSchemas: structuralSchemas,
|
||||||
|
kind: kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +74,20 @@ func (a customResourceStrategy) NamespaceScoped() bool {
|
|||||||
return a.namespaceScoped
|
return a.namespaceScoped
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (a customResourceStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{}
|
||||||
|
|
||||||
|
if a.status != nil {
|
||||||
|
fields[fieldpath.APIVersion(a.kind.GroupVersion().String())] = fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of a CustomResource before creation.
|
// PrepareForCreate clears the status of a CustomResource before creation.
|
||||||
func (a customResourceStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (a customResourceStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
if a.status != nil {
|
if a.status != nil {
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
storageerr "k8s.io/apiserver/pkg/storage/errors"
|
storageerr "k8s.io/apiserver/pkg/storage/errors"
|
||||||
"k8s.io/apiserver/pkg/util/dryrun"
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rest implements a RESTStorage for API services against etcd
|
// rest implements a RESTStorage for API services against etcd
|
||||||
@ -50,6 +51,7 @@ func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) (*RES
|
|||||||
CreateStrategy: strategy,
|
CreateStrategy: strategy,
|
||||||
UpdateStrategy: strategy,
|
UpdateStrategy: strategy,
|
||||||
DeleteStrategy: strategy,
|
DeleteStrategy: strategy,
|
||||||
|
ResetFieldsStrategy: strategy,
|
||||||
|
|
||||||
// TODO: define table converter that exposes more than name/creation timestamp
|
// TODO: define table converter that exposes more than name/creation timestamp
|
||||||
TableConvertor: rest.NewDefaultTableConvertor(apiextensions.Resource("customresourcedefinitions")),
|
TableConvertor: rest.NewDefaultTableConvertor(apiextensions.Resource("customresourcedefinitions")),
|
||||||
@ -177,7 +179,9 @@ func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST {
|
|||||||
statusStore := *rest.Store
|
statusStore := *rest.Store
|
||||||
statusStore.CreateStrategy = nil
|
statusStore.CreateStrategy = nil
|
||||||
statusStore.DeleteStrategy = nil
|
statusStore.DeleteStrategy = nil
|
||||||
statusStore.UpdateStrategy = NewStatusStrategy(scheme)
|
statusStrategy := NewStatusStrategy(scheme)
|
||||||
|
statusStore.UpdateStrategy = statusStrategy
|
||||||
|
statusStore.ResetFieldsStrategy = statusStrategy
|
||||||
return &StatusREST{store: &statusStore}
|
return &StatusREST{store: &statusStore}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,3 +206,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation"
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation"
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"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"
|
||||||
@ -32,6 +33,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
"k8s.io/apiserver/pkg/storage/names"
|
"k8s.io/apiserver/pkg/storage/names"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// strategy implements behavior for CustomResources.
|
// strategy implements behavior for CustomResources.
|
||||||
@ -48,6 +50,21 @@ func (strategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (strategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"apiextensions.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"apiextensions.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareForCreate clears the status of a CustomResourceDefinition before creation.
|
// PrepareForCreate clears the status of a CustomResourceDefinition before creation.
|
||||||
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
crd := obj.(*apiextensions.CustomResourceDefinition)
|
crd := obj.(*apiextensions.CustomResourceDefinition)
|
||||||
@ -140,18 +157,30 @@ func (statusStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields returns the set of fields that get reset by the strategy
|
||||||
|
// and should not be modified by the user.
|
||||||
|
func (statusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"apiextensions.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
"apiextensions.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (statusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (statusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
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.
|
// Status updates are for only for updating status, not objectmeta.
|
||||||
// TODO: Update after ResetObjectMetaForStatus is added to meta/v1.
|
metav1.ResetObjectMetaForStatus(&newObj.ObjectMeta, &newObj.ObjectMeta)
|
||||||
newObj.Labels = oldObj.Labels
|
|
||||||
newObj.Annotations = oldObj.Annotations
|
|
||||||
newObj.OwnerReferences = oldObj.OwnerReferences
|
|
||||||
newObj.Generation = oldObj.Generation
|
|
||||||
newObj.SelfLink = oldObj.SelfLink
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (statusStrategy) AllowCreateOnUpdate() bool {
|
func (statusStrategy) AllowCreateOnUpdate() bool {
|
||||||
|
@ -78,8 +78,8 @@ func NewFieldManager(f Manager, ignoreManagedFieldsFromRequestObject bool) *Fiel
|
|||||||
|
|
||||||
// NewDefaultFieldManager creates a new FieldManager that merges apply requests
|
// NewDefaultFieldManager creates a new FieldManager that merges apply requests
|
||||||
// and update managed fields for other types of requests.
|
// and update managed fields for other types of requests.
|
||||||
func NewDefaultFieldManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, ignoreManagedFieldsFromRequestObject bool) (*FieldManager, error) {
|
func NewDefaultFieldManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, ignoreManagedFieldsFromRequestObject bool, resetFields map[fieldpath.APIVersion]*fieldpath.Set) (*FieldManager, error) {
|
||||||
f, err := NewStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub)
|
f, err := NewStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub, resetFields)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create field manager: %v", err)
|
return nil, fmt.Errorf("failed to create field manager: %v", err)
|
||||||
}
|
}
|
||||||
@ -89,8 +89,8 @@ func NewDefaultFieldManager(typeConverter TypeConverter, objectConverter runtime
|
|||||||
// NewDefaultCRDFieldManager creates a new FieldManager specifically for
|
// NewDefaultCRDFieldManager creates a new FieldManager specifically for
|
||||||
// CRDs. This allows for the possibility of fields which are not defined
|
// CRDs. This allows for the possibility of fields which are not defined
|
||||||
// in models, as well as having no models defined at all.
|
// in models, as well as having no models defined at all.
|
||||||
func NewDefaultCRDFieldManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, ignoreManagedFieldsFromRequestObject bool) (_ *FieldManager, err error) {
|
func NewDefaultCRDFieldManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, ignoreManagedFieldsFromRequestObject bool, resetFields map[fieldpath.APIVersion]*fieldpath.Set) (_ *FieldManager, err error) {
|
||||||
f, err := NewCRDStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub)
|
f, err := NewCRDStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub, resetFields)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create field manager: %v", err)
|
return nil, fmt.Errorf("failed to create field manager: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,7 @@ func NewTestFieldManager(gvk schema.GroupVersionKind, ignoreManagedFieldsFromReq
|
|||||||
&fakeObjectDefaulter{},
|
&fakeObjectDefaulter{},
|
||||||
gvk.GroupVersion(),
|
gvk.GroupVersion(),
|
||||||
gvk.GroupVersion(),
|
gvk.GroupVersion(),
|
||||||
|
nil,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -41,7 +41,7 @@ var _ Manager = &structuredMergeManager{}
|
|||||||
|
|
||||||
// NewStructuredMergeManager creates a new Manager that merges apply requests
|
// NewStructuredMergeManager creates a new Manager that merges apply requests
|
||||||
// and update managed fields for other types of requests.
|
// and update managed fields for other types of requests.
|
||||||
func NewStructuredMergeManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion) (Manager, error) {
|
func NewStructuredMergeManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion, resetFields map[fieldpath.APIVersion]*fieldpath.Set) (Manager, error) {
|
||||||
return &structuredMergeManager{
|
return &structuredMergeManager{
|
||||||
typeConverter: typeConverter,
|
typeConverter: typeConverter,
|
||||||
objectConverter: objectConverter,
|
objectConverter: objectConverter,
|
||||||
@ -50,6 +50,7 @@ func NewStructuredMergeManager(typeConverter TypeConverter, objectConverter runt
|
|||||||
hubVersion: hub,
|
hubVersion: hub,
|
||||||
updater: merge.Updater{
|
updater: merge.Updater{
|
||||||
Converter: newVersionConverter(typeConverter, objectConverter, hub), // This is the converter provided to SMD from k8s
|
Converter: newVersionConverter(typeConverter, objectConverter, hub), // This is the converter provided to SMD from k8s
|
||||||
|
IgnoredFields: resetFields,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -57,7 +58,7 @@ func NewStructuredMergeManager(typeConverter TypeConverter, objectConverter runt
|
|||||||
// NewCRDStructuredMergeManager creates a new Manager specifically for
|
// NewCRDStructuredMergeManager creates a new Manager specifically for
|
||||||
// CRDs. This allows for the possibility of fields which are not defined
|
// CRDs. This allows for the possibility of fields which are not defined
|
||||||
// in models, as well as having no models defined at all.
|
// in models, as well as having no models defined at all.
|
||||||
func NewCRDStructuredMergeManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion) (_ Manager, err error) {
|
func NewCRDStructuredMergeManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion, resetFields map[fieldpath.APIVersion]*fieldpath.Set) (_ Manager, err error) {
|
||||||
return &structuredMergeManager{
|
return &structuredMergeManager{
|
||||||
typeConverter: typeConverter,
|
typeConverter: typeConverter,
|
||||||
objectConverter: objectConverter,
|
objectConverter: objectConverter,
|
||||||
@ -66,6 +67,7 @@ func NewCRDStructuredMergeManager(typeConverter TypeConverter, objectConverter r
|
|||||||
hubVersion: hub,
|
hubVersion: hub,
|
||||||
updater: merge.Updater{
|
updater: merge.Updater{
|
||||||
Converter: newCRDVersionConverter(typeConverter, objectConverter, hub),
|
Converter: newCRDVersionConverter(typeConverter, objectConverter, hub),
|
||||||
|
IgnoredFields: resetFields,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/storageversion"
|
"k8s.io/apiserver/pkg/storageversion"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
versioninfo "k8s.io/component-base/version"
|
versioninfo "k8s.io/component-base/version"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -258,6 +259,13 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
isCreater = true
|
isCreater = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var resetFields map[fieldpath.APIVersion]*fieldpath.Set
|
||||||
|
if a.group.OpenAPIModels != nil && utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
||||||
|
if resetFieldsStrategy, isResetFieldsStrategy := storage.(rest.ResetFieldsStrategy); isResetFieldsStrategy {
|
||||||
|
resetFields = resetFieldsStrategy.GetResetFields()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var versionedList interface{}
|
var versionedList interface{}
|
||||||
if isLister {
|
if isLister {
|
||||||
list := lister.NewList()
|
list := lister.NewList()
|
||||||
@ -597,6 +605,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
fqKindToRegister,
|
fqKindToRegister,
|
||||||
reqScope.HubGroupVersion,
|
reqScope.HubGroupVersion,
|
||||||
isSubresource,
|
isSubresource,
|
||||||
|
resetFields,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to create field manager: %v", err)
|
return nil, nil, fmt.Errorf("failed to create field manager: %v", err)
|
||||||
|
@ -45,6 +45,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/storage/etcd3/metrics"
|
"k8s.io/apiserver/pkg/storage/etcd3/metrics"
|
||||||
"k8s.io/apiserver/pkg/util/dryrun"
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
@ -201,6 +202,10 @@ type Store struct {
|
|||||||
// of items into tabular output. If unset, the default will be used.
|
// of items into tabular output. If unset, the default will be used.
|
||||||
TableConvertor rest.TableConvertor
|
TableConvertor rest.TableConvertor
|
||||||
|
|
||||||
|
// ResetFieldsStrategy provides the fields reset by the strategy that
|
||||||
|
// should not be modified by the user.
|
||||||
|
ResetFieldsStrategy rest.ResetFieldsStrategy
|
||||||
|
|
||||||
// Storage is the interface for the underlying storage for the
|
// Storage is the interface for the underlying storage for the
|
||||||
// resource. It is wrapped into a "DryRunnableStorage" that will
|
// resource. It is wrapped into a "DryRunnableStorage" that will
|
||||||
// either pass-through or simply dry-run.
|
// either pass-through or simply dry-run.
|
||||||
@ -1445,6 +1450,14 @@ func (e *Store) StorageVersion() runtime.GroupVersioner {
|
|||||||
return e.StorageVersioner
|
return e.StorageVersioner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResetFields implements rest.ResetFieldsStrategy
|
||||||
|
func (e *Store) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
if e.ResetFieldsStrategy == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e.ResetFieldsStrategy.GetResetFields()
|
||||||
|
}
|
||||||
|
|
||||||
// validateIndexers will check the prefix of indexers.
|
// validateIndexers will check the prefix of indexers.
|
||||||
func validateIndexers(indexers *cache.Indexers) error {
|
func validateIndexers(indexers *cache.Indexers) error {
|
||||||
if indexers == nil {
|
if indexers == nil {
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
//TODO:
|
//TODO:
|
||||||
@ -339,3 +340,23 @@ type StorageVersionProvider interface {
|
|||||||
// list of kinds the object might belong to.
|
// list of kinds the object might belong to.
|
||||||
StorageVersion() runtime.GroupVersioner
|
StorageVersion() runtime.GroupVersioner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResetFieldsStrategy is an optional interface that a storage object can
|
||||||
|
// implement if it wishes to provide the fields reset by its strategies.
|
||||||
|
type ResetFieldsStrategy interface {
|
||||||
|
GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateUpdateResetFieldsStrategy is a union of RESTCreateUpdateStrategy
|
||||||
|
// and ResetFieldsStrategy.
|
||||||
|
type CreateUpdateResetFieldsStrategy interface {
|
||||||
|
RESTCreateUpdateStrategy
|
||||||
|
ResetFieldsStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResetFieldsStrategy is a union of RESTUpdateStrategy
|
||||||
|
// and ResetFieldsStrategy.
|
||||||
|
type UpdateResetFieldsStrategy interface {
|
||||||
|
RESTUpdateStrategy
|
||||||
|
ResetFieldsStrategy
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ require (
|
|||||||
k8s.io/klog/v2 v2.5.0
|
k8s.io/klog/v2 v2.5.0
|
||||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7
|
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7
|
||||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
|
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.0.3
|
||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/kube-aggregator/pkg/apis/apiregistration"
|
"k8s.io/kube-aggregator/pkg/apis/apiregistration"
|
||||||
"k8s.io/kube-aggregator/pkg/registry/apiservice"
|
"k8s.io/kube-aggregator/pkg/registry/apiservice"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for API services against etcd
|
// REST implements a RESTStorage for API services against etcd
|
||||||
@ -48,6 +49,7 @@ func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST
|
|||||||
CreateStrategy: strategy,
|
CreateStrategy: strategy,
|
||||||
UpdateStrategy: strategy,
|
UpdateStrategy: strategy,
|
||||||
DeleteStrategy: strategy,
|
DeleteStrategy: strategy,
|
||||||
|
ResetFieldsStrategy: strategy,
|
||||||
|
|
||||||
// TODO: define table converter that exposes more than name/creation timestamp
|
// TODO: define table converter that exposes more than name/creation timestamp
|
||||||
TableConvertor: rest.NewDefaultTableConvertor(apiregistration.Resource("apiservices")),
|
TableConvertor: rest.NewDefaultTableConvertor(apiregistration.Resource("apiservices")),
|
||||||
@ -126,10 +128,12 @@ func getCondition(conditions []apiregistration.APIServiceCondition, conditionTyp
|
|||||||
// NewStatusREST makes a RESTStorage for status that has more limited options.
|
// NewStatusREST makes a RESTStorage for status that has more limited options.
|
||||||
// It is based on the original REST so that we can share the same underlying store
|
// It is based on the original REST so that we can share the same underlying store
|
||||||
func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST {
|
func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST {
|
||||||
|
strategy := apiservice.NewStatusStrategy(scheme)
|
||||||
statusStore := *rest.Store
|
statusStore := *rest.Store
|
||||||
statusStore.CreateStrategy = nil
|
statusStore.CreateStrategy = nil
|
||||||
statusStore.DeleteStrategy = nil
|
statusStore.DeleteStrategy = nil
|
||||||
statusStore.UpdateStrategy = apiservice.NewStatusStrategy(scheme)
|
statusStore.UpdateStrategy = strategy
|
||||||
|
statusStore.ResetFieldsStrategy = strategy
|
||||||
return &StatusREST{store: &statusStore}
|
return &StatusREST{store: &statusStore}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,3 +160,8 @@ func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
// subresources should never allow create on update.
|
// subresources should never allow create on update.
|
||||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
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()
|
||||||
|
}
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kube-aggregator/pkg/apis/apiregistration"
|
"k8s.io/kube-aggregator/pkg/apis/apiregistration"
|
||||||
"k8s.io/kube-aggregator/pkg/apis/apiregistration/validation"
|
"k8s.io/kube-aggregator/pkg/apis/apiregistration/validation"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type apiServerStrategy struct {
|
type apiServerStrategy struct {
|
||||||
@ -40,9 +41,10 @@ type apiServerStrategy struct {
|
|||||||
|
|
||||||
// apiServerStrategy must implement rest.RESTCreateUpdateStrategy
|
// apiServerStrategy must implement rest.RESTCreateUpdateStrategy
|
||||||
var _ rest.RESTCreateUpdateStrategy = apiServerStrategy{}
|
var _ rest.RESTCreateUpdateStrategy = apiServerStrategy{}
|
||||||
|
var Strategy = apiServerStrategy{}
|
||||||
|
|
||||||
// NewStrategy creates a new apiServerStrategy.
|
// NewStrategy creates a new apiServerStrategy.
|
||||||
func NewStrategy(typer runtime.ObjectTyper) rest.RESTCreateUpdateStrategy {
|
func NewStrategy(typer runtime.ObjectTyper) rest.CreateUpdateResetFieldsStrategy {
|
||||||
return apiServerStrategy{typer, names.SimpleNameGenerator}
|
return apiServerStrategy{typer, names.SimpleNameGenerator}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +52,19 @@ func (apiServerStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (apiServerStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"apiregistration.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
"apiregistration.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("status"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (apiServerStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (apiServerStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
apiservice := obj.(*apiregistration.APIService)
|
apiservice := obj.(*apiregistration.APIService)
|
||||||
apiservice.Status = apiregistration.APIServiceStatus{}
|
apiservice.Status = apiregistration.APIServiceStatus{}
|
||||||
@ -91,7 +106,7 @@ type apiServerStatusStrategy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewStatusStrategy creates a new apiServerStatusStrategy.
|
// NewStatusStrategy creates a new apiServerStatusStrategy.
|
||||||
func NewStatusStrategy(typer runtime.ObjectTyper) rest.RESTUpdateStrategy {
|
func NewStatusStrategy(typer runtime.ObjectTyper) rest.UpdateResetFieldsStrategy {
|
||||||
return apiServerStatusStrategy{typer, names.SimpleNameGenerator}
|
return apiServerStatusStrategy{typer, names.SimpleNameGenerator}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +114,21 @@ func (apiServerStatusStrategy) NamespaceScoped() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (apiServerStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||||
|
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||||
|
"apiregistration.k8s.io/v1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
),
|
||||||
|
"apiregistration.k8s.io/v1beta1": fieldpath.NewSet(
|
||||||
|
fieldpath.MakePathOrDie("spec"),
|
||||||
|
fieldpath.MakePathOrDie("metadata"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
func (apiServerStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (apiServerStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
newAPIService := obj.(*apiregistration.APIService)
|
newAPIService := obj.(*apiregistration.APIService)
|
||||||
oldAPIService := old.(*apiregistration.APIService)
|
oldAPIService := old.(*apiregistration.APIService)
|
||||||
|
298
test/integration/apiserver/apply/reset_fields_test.go
Normal file
298
test/integration/apiserver/apply/reset_fields_test.go
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package apiserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
genericfeatures "k8s.io/apiserver/pkg/features"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
||||||
|
"k8s.io/kubernetes/test/integration/etcd"
|
||||||
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
|
"k8s.io/kubernetes/test/utils/image"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// namespace used for all tests, do not change this
|
||||||
|
const resetFieldsNamespace = "reset-fields-namespace"
|
||||||
|
|
||||||
|
// resetFieldsStatusData contains statuses for all the resources in the
|
||||||
|
// statusData list with slightly different data to create a field manager
|
||||||
|
// conflict.
|
||||||
|
var resetFieldsStatusData = map[schema.GroupVersionResource]string{
|
||||||
|
gvr("", "v1", "persistentvolumes"): `{"status": {"message": "hello2"}}`,
|
||||||
|
gvr("", "v1", "resourcequotas"): `{"status": {"used": {"cpu": "25M"}}}`,
|
||||||
|
gvr("", "v1", "services"): `{"status": {"loadBalancer": {"ingress": [{"ip": "127.0.0.2"}]}}}`,
|
||||||
|
gvr("extensions", "v1beta1", "ingresses"): `{"status": {"loadBalancer": {"ingress": [{"ip": "127.0.0.2"}]}}}`,
|
||||||
|
gvr("networking.k8s.io", "v1beta1", "ingresses"): `{"status": {"loadBalancer": {"ingress": [{"ip": "127.0.0.2"}]}}}`,
|
||||||
|
gvr("networking.k8s.io", "v1", "ingresses"): `{"status": {"loadBalancer": {"ingress": [{"ip": "127.0.0.2"}]}}}`,
|
||||||
|
gvr("autoscaling", "v1", "horizontalpodautoscalers"): `{"status": {"currentReplicas": 25}}`,
|
||||||
|
gvr("batch", "v1", "cronjobs"): `{"status": {"lastScheduleTime": "2020-01-01T00:00:00Z"}}`,
|
||||||
|
gvr("batch", "v1beta1", "cronjobs"): `{"status": {"lastScheduleTime": "2020-01-01T00:00:00Z"}}`,
|
||||||
|
gvr("storage.k8s.io", "v1", "volumeattachments"): `{"status": {"attached": false}}`,
|
||||||
|
gvr("policy", "v1", "poddisruptionbudgets"): `{"status": {"currentHealthy": 25}}`,
|
||||||
|
gvr("policy", "v1beta1", "poddisruptionbudgets"): `{"status": {"currentHealthy": 25}}`,
|
||||||
|
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{"status": {"commonEncodingVersion":"v1","storageVersions":[{"apiServerID":"1","decodableVersions":["v1","v2"],"encodingVersion":"v1"}],"conditions":[{"type":"AllEncodingVersionsEqual","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"allEncodingVersionsEqual","message":"all encoding versions are set to v1"}]}}`,
|
||||||
|
}
|
||||||
|
|
||||||
|
// resetFieldsStatusDefault conflicts with statusDefault
|
||||||
|
const resetFieldsStatusDefault = `{"status": {"conditions": [{"type": "MyStatus", "status":"False"}]}}`
|
||||||
|
|
||||||
|
var resetFieldsSkippedResources = map[string]struct{}{
|
||||||
|
// TODO: flowschemas is flaking,
|
||||||
|
// possible bug in the flowschemas controller.
|
||||||
|
"flowschemas": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// noConflicts is the set of reources for which
|
||||||
|
// a conflict cannot occur.
|
||||||
|
var noConflicts = map[string]struct{}{
|
||||||
|
// both spec and status get wiped for CSRs,
|
||||||
|
// nothing is expected to be managed for it, skip it
|
||||||
|
"certificatesigningrequests": {},
|
||||||
|
// storageVersions are skipped because their spec is empty
|
||||||
|
// and thus they can never have a conflict.
|
||||||
|
"storageversions": {},
|
||||||
|
// namespaces only have a spec.finalizers field which is also skipped,
|
||||||
|
// thus it will never have a conflict.
|
||||||
|
"namespaces": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
var image2 = image.GetE2EImage(image.Etcd)
|
||||||
|
|
||||||
|
// resetFieldsSpecData contains conflicting data with the objects in
|
||||||
|
// etcd.GetEtcdStorageDataForNamespace()
|
||||||
|
// It contains the minimal changes needed to conflict with all the fields
|
||||||
|
// added to resetFields by the strategy of each resource.
|
||||||
|
// In most cases, just one field on the spec is changed, but
|
||||||
|
// some also wipe metadata or other fields.
|
||||||
|
var resetFieldsSpecData = map[schema.GroupVersionResource]string{
|
||||||
|
gvr("", "v1", "resourcequotas"): `{"spec": {"hard": {"cpu": "25M"}}}`,
|
||||||
|
gvr("", "v1", "namespaces"): `{"spec": {"finalizers": ["kubernetes2"]}}`,
|
||||||
|
gvr("", "v1", "nodes"): `{"spec": {"unschedulable": false}}`,
|
||||||
|
gvr("", "v1", "persistentvolumes"): `{"spec": {"capacity": {"storage": "23M"}}}`,
|
||||||
|
gvr("", "v1", "persistentvolumeclaims"): `{"spec": {"resources": {"limits": {"storage": "21M"}}}}`,
|
||||||
|
gvr("", "v1", "pods"): `{"metadata": {"deletionTimestamp": "2020-01-01T00:00:00Z", "ownerReferences":[]}, "spec": {"containers": [{"image": "` + image2 + `", "name": "container7"}]}}`,
|
||||||
|
gvr("", "v1", "replicationcontrollers"): `{"spec": {"selector": {"new": "stuff2"}}}`,
|
||||||
|
gvr("", "v1", "resourcequotas"): `{"spec": {"hard": {"cpu": "25M"}}}`,
|
||||||
|
gvr("", "v1", "services"): `{"spec": {"externalName": "service2name"}}`,
|
||||||
|
gvr("apps", "v1", "daemonsets"): `{"spec": {"template": {"spec": {"containers": [{"image": "` + image2 + `", "name": "container6"}]}}}}`,
|
||||||
|
gvr("apps", "v1", "deployments"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"template": {"spec": {"containers": [{"image": "` + image2 + `", "name": "container6"}]}}}}`,
|
||||||
|
gvr("apps", "v1", "replicasets"): `{"spec": {"template": {"spec": {"containers": [{"image": "` + image2 + `", "name": "container4"}]}}}}`,
|
||||||
|
gvr("apps", "v1", "statefulsets"): `{"spec": {"selector": {"matchLabels": {"a2": "b2"}}}}`,
|
||||||
|
gvr("autoscaling", "v1", "horizontalpodautoscalers"): `{"spec": {"maxReplicas": 23}}`,
|
||||||
|
gvr("autoscaling", "v2beta1", "horizontalpodautoscalers"): `{"spec": {"maxReplicas": 23}}`,
|
||||||
|
gvr("autoscaling", "v2beta2", "horizontalpodautoscalers"): `{"spec": {"maxReplicas": 23}}`,
|
||||||
|
gvr("batch", "v1", "jobs"): `{"spec": {"template": {"spec": {"containers": [{"image": "` + image2 + `", "name": "container1"}]}}}}`,
|
||||||
|
gvr("batch", "v1", "cronjobs"): `{"spec": {"jobTemplate": {"spec": {"template": {"spec": {"containers": [{"image": "` + image2 + `", "name": "container0"}]}}}}}}`,
|
||||||
|
gvr("batch", "v1beta1", "cronjobs"): `{"spec": {"jobTemplate": {"spec": {"template": {"spec": {"containers": [{"image": "` + image2 + `", "name": "container0"}]}}}}}}`,
|
||||||
|
gvr("certificates.k8s.io", "v1", "certificatesigningrequests"): `{}`,
|
||||||
|
gvr("certificates.k8s.io", "v1beta1", "certificatesigningrequests"): `{}`,
|
||||||
|
gvr("flowcontrol.apiserver.k8s.io", "v1alpha1", "flowschemas"): `{"metadata": {"labels":{"a":"c"}}, "spec": {"priorityLevelConfiguration": {"name": "name2"}}}`,
|
||||||
|
gvr("flowcontrol.apiserver.k8s.io", "v1beta1", "flowschemas"): `{"metadata": {"labels":{"a":"c"}}, "spec": {"priorityLevelConfiguration": {"name": "name2"}}}`,
|
||||||
|
gvr("flowcontrol.apiserver.k8s.io", "v1alpha1", "prioritylevelconfigurations"): `{"metadata": {"labels":{"a":"c"}}, "spec": {"limited": {"assuredConcurrencyShares": 23}}}`,
|
||||||
|
gvr("flowcontrol.apiserver.k8s.io", "v1beta1", "prioritylevelconfigurations"): `{"metadata": {"labels":{"a":"c"}}, "spec": {"limited": {"assuredConcurrencyShares": 23}}}`,
|
||||||
|
gvr("extensions", "v1beta1", "ingresses"): `{"spec": {"backend": {"serviceName": "service2"}}}`,
|
||||||
|
gvr("networking.k8s.io", "v1beta1", "ingresses"): `{"spec": {"backend": {"serviceName": "service2"}}}`,
|
||||||
|
gvr("networking.k8s.io", "v1", "ingresses"): `{"spec": {"defaultBackend": {"service": {"name": "service2"}}}}`,
|
||||||
|
gvr("policy", "v1", "poddisruptionbudgets"): `{"spec": {"selector": {"matchLabels": {"anokkey2": "anokvalue"}}}}`,
|
||||||
|
gvr("policy", "v1beta1", "poddisruptionbudgets"): `{"spec": {"selector": {"matchLabels": {"anokkey2": "anokvalue"}}}}`,
|
||||||
|
gvr("storage.k8s.io", "v1alpha1", "volumeattachments"): `{"metadata": {"name": "vaName2"}, "spec": {"nodeName": "localhost2"}}`,
|
||||||
|
gvr("storage.k8s.io", "v1", "volumeattachments"): `{"metadata": {"name": "vaName2"}, "spec": {"nodeName": "localhost2"}}`,
|
||||||
|
gvr("apiextensions.k8s.io", "v1", "customresourcedefinitions"): `{"metadata": {"labels":{"a":"c"}}, "spec": {"group": "webconsole22.operator.openshift.io"}}`,
|
||||||
|
gvr("apiextensions.k8s.io", "v1beta1", "customresourcedefinitions"): `{"metadata": {"labels":{"a":"c"}}, "spec": {"group": "webconsole22.operator.openshift.io"}}`,
|
||||||
|
gvr("awesome.bears.com", "v1", "pandas"): `{"spec": {"replicas": 102}}`,
|
||||||
|
gvr("awesome.bears.com", "v3", "pandas"): `{"spec": {"replicas": 302}}`,
|
||||||
|
gvr("apiregistration.k8s.io", "v1beta1", "apiservices"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"group": "foo2.com"}}`,
|
||||||
|
gvr("apiregistration.k8s.io", "v1", "apiservices"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"group": "foo2.com"}}`,
|
||||||
|
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{}`,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestResetFields makes sure that fieldManager does not own fields reset by the storage strategy.
|
||||||
|
// It takes 2 objects obj1 and obj2 that differ by one field in the spec and one field in the status.
|
||||||
|
// It applies obj1 to the spec endpoint and obj2 to the status endpoint, the lack of conflicts
|
||||||
|
// confirms that the fieldmanager1 is wiped of the status and fieldmanager2 is wiped of the spec.
|
||||||
|
// We then attempt to apply obj2 to the spec endpoint which fails with an expected conflict.
|
||||||
|
func TestApplyResetFields(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
|
||||||
|
server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), []string{"--disable-admission-plugins", "ServiceAccount,TaintNodesByCondition"}, framework.SharedEtcd())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer server.TearDownFn()
|
||||||
|
|
||||||
|
client, err := kubernetes.NewForConfig(server.ClientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
dynamicClient, err := dynamic.NewForConfig(server.ClientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create CRDs so we can make sure that custom resources do not get lost
|
||||||
|
etcd.CreateTestCRDs(t, apiextensionsclientset.NewForConfigOrDie(server.ClientConfig), false, etcd.GetCustomResourceDefinitionData()...)
|
||||||
|
|
||||||
|
if _, err := client.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: resetFieldsNamespace}}, metav1.CreateOptions{}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
createData := etcd.GetEtcdStorageDataForNamespace(resetFieldsNamespace)
|
||||||
|
// gather resources to test
|
||||||
|
_, resourceLists, err := client.Discovery().ServerGroupsAndResources()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to get ServerGroupsAndResources with error: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, resourceList := range resourceLists {
|
||||||
|
for _, resource := range resourceList.APIResources {
|
||||||
|
if !strings.HasSuffix(resource.Name, "/status") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mapping, err := createMapping(resourceList.GroupVersion, resource)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Run(mapping.Resource.String(), func(t *testing.T) {
|
||||||
|
if _, ok := resetFieldsSkippedResources[mapping.Resource.Resource]; ok {
|
||||||
|
t.Skip()
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace := resetFieldsNamespace
|
||||||
|
if mapping.Scope == meta.RESTScopeRoot {
|
||||||
|
namespace = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// assemble first object
|
||||||
|
status, ok := statusData[mapping.Resource]
|
||||||
|
if !ok {
|
||||||
|
status = statusDefault
|
||||||
|
}
|
||||||
|
|
||||||
|
resource, ok := createData[mapping.Resource]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("no test data for %s. Please add a test for your new type to etcd.GetEtcdStorageData() or getResetFieldsEtcdStorageData()", mapping.Resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
obj1 := unstructured.Unstructured{}
|
||||||
|
if err := json.Unmarshal([]byte(resource.Stub), &obj1.Object); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(status), &obj1.Object); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := obj1.GetName()
|
||||||
|
obj1.SetAPIVersion(mapping.GroupVersionKind.GroupVersion().String())
|
||||||
|
obj1.SetKind(mapping.GroupVersionKind.Kind)
|
||||||
|
obj1.SetName(name)
|
||||||
|
obj1YAML, err := yaml.Marshal(obj1.Object)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply the spec of the first object
|
||||||
|
_, err = dynamicClient.
|
||||||
|
Resource(mapping.Resource).
|
||||||
|
Namespace(namespace).
|
||||||
|
Patch(context.TODO(), name, types.ApplyPatchType, obj1YAML, metav1.PatchOptions{FieldManager: "fieldmanager1"}, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to apply obj1: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create second object
|
||||||
|
obj2 := &unstructured.Unstructured{}
|
||||||
|
obj1.DeepCopyInto(obj2)
|
||||||
|
if err := json.Unmarshal([]byte(resetFieldsSpecData[mapping.Resource]), &obj2.Object); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
status2, ok := resetFieldsStatusData[mapping.Resource]
|
||||||
|
if !ok {
|
||||||
|
status2 = resetFieldsStatusDefault
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(status2), &obj2.Object); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.DeepEqual(obj1, obj2) {
|
||||||
|
t.Fatalf("obj1 and obj2 should not be equal %v", obj2)
|
||||||
|
}
|
||||||
|
|
||||||
|
obj2YAML, err := yaml.Marshal(obj2.Object)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply the status of the second object
|
||||||
|
// this won't conflict if resetfields are set correctly
|
||||||
|
// and will conflict if they are not
|
||||||
|
_, err = dynamicClient.
|
||||||
|
Resource(mapping.Resource).
|
||||||
|
Namespace(namespace).
|
||||||
|
Patch(context.TODO(), name, types.ApplyPatchType, obj2YAML, metav1.PatchOptions{FieldManager: "fieldmanager2"}, "status")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to apply obj2: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip checking for conflicts on resources
|
||||||
|
// that will never have conflicts
|
||||||
|
if _, ok = noConflicts[mapping.Resource.Resource]; !ok {
|
||||||
|
// reapply second object to the spec endpoint
|
||||||
|
// that should fail with a conflict
|
||||||
|
_, err = dynamicClient.
|
||||||
|
Resource(mapping.Resource).
|
||||||
|
Namespace(namespace).
|
||||||
|
Patch(context.TODO(), name, types.ApplyPatchType, obj2YAML, metav1.PatchOptions{FieldManager: "fieldmanager2"}, "")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "conflict") {
|
||||||
|
t.Fatalf("expected conflict, got error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reapply first object to the status endpoint
|
||||||
|
// that should fail with a conflict
|
||||||
|
_, err = dynamicClient.
|
||||||
|
Resource(mapping.Resource).
|
||||||
|
Namespace(namespace).
|
||||||
|
Patch(context.TODO(), name, types.ApplyPatchType, obj1YAML, metav1.PatchOptions{FieldManager: "fieldmanager1"}, "status")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "conflict") {
|
||||||
|
t.Fatalf("expected conflict, got error %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
rsc := dynamicClient.Resource(mapping.Resource).Namespace(namespace)
|
||||||
|
if err := rsc.Delete(context.TODO(), name, *metav1.NewDeleteOptions(0)); err != nil {
|
||||||
|
t.Fatalf("deleting final object failed: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -56,8 +56,6 @@ var statusData = map[schema.GroupVersionResource]string{
|
|||||||
gvr("storage.k8s.io", "v1", "volumeattachments"): `{"status": {"attached": true}}`,
|
gvr("storage.k8s.io", "v1", "volumeattachments"): `{"status": {"attached": true}}`,
|
||||||
gvr("policy", "v1", "poddisruptionbudgets"): `{"status": {"currentHealthy": 5}}`,
|
gvr("policy", "v1", "poddisruptionbudgets"): `{"status": {"currentHealthy": 5}}`,
|
||||||
gvr("policy", "v1beta1", "poddisruptionbudgets"): `{"status": {"currentHealthy": 5}}`,
|
gvr("policy", "v1beta1", "poddisruptionbudgets"): `{"status": {"currentHealthy": 5}}`,
|
||||||
gvr("certificates.k8s.io", "v1beta1", "certificatesigningrequests"): `{"status": {"conditions": [{"type": "MyStatus"}]}}`,
|
|
||||||
gvr("certificates.k8s.io", "v1", "certificatesigningrequests"): `{"status": {"conditions": [{"type": "MyStatus", "status": "True"}]}}`,
|
|
||||||
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{"status": {"commonEncodingVersion":"v1","storageVersions":[{"apiServerID":"1","decodableVersions":["v1","v2"],"encodingVersion":"v1"}],"conditions":[{"type":"AllEncodingVersionsEqual","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"allEncodingVersionsEqual","message":"all encoding versions are set to v1"}]}}`,
|
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{"status": {"commonEncodingVersion":"v1","storageVersions":[{"apiServerID":"1","decodableVersions":["v1","v2"],"encodingVersion":"v1"}],"conditions":[{"type":"AllEncodingVersionsEqual","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"allEncodingVersionsEqual","message":"all encoding versions are set to v1"}]}}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +131,12 @@ func TestApplyStatus(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Run(mapping.Resource.String(), func(t *testing.T) {
|
t.Run(mapping.Resource.String(), func(t *testing.T) {
|
||||||
|
// both spec and status get wiped for CSRs,
|
||||||
|
// nothing is expected to be managed for it, skip it
|
||||||
|
if mapping.Resource.Resource == "certificatesigningrequests" {
|
||||||
|
t.Skip()
|
||||||
|
}
|
||||||
|
|
||||||
status, ok := statusData[mapping.Resource]
|
status, ok := statusData[mapping.Resource]
|
||||||
if !ok {
|
if !ok {
|
||||||
status = statusDefault
|
status = statusDefault
|
||||||
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -2710,6 +2710,7 @@ sigs.k8s.io/kustomize/kyaml/yaml/merge3
|
|||||||
sigs.k8s.io/kustomize/kyaml/yaml/schema
|
sigs.k8s.io/kustomize/kyaml/yaml/schema
|
||||||
sigs.k8s.io/kustomize/kyaml/yaml/walk
|
sigs.k8s.io/kustomize/kyaml/yaml/walk
|
||||||
# sigs.k8s.io/structured-merge-diff/v4 v4.0.3 => sigs.k8s.io/structured-merge-diff/v4 v4.0.3
|
# sigs.k8s.io/structured-merge-diff/v4 v4.0.3 => sigs.k8s.io/structured-merge-diff/v4 v4.0.3
|
||||||
|
## explicit
|
||||||
# sigs.k8s.io/structured-merge-diff/v4 => sigs.k8s.io/structured-merge-diff/v4 v4.0.3
|
# sigs.k8s.io/structured-merge-diff/v4 => sigs.k8s.io/structured-merge-diff/v4 v4.0.3
|
||||||
sigs.k8s.io/structured-merge-diff/v4/fieldpath
|
sigs.k8s.io/structured-merge-diff/v4/fieldpath
|
||||||
sigs.k8s.io/structured-merge-diff/v4/merge
|
sigs.k8s.io/structured-merge-diff/v4/merge
|
||||||
|
Loading…
Reference in New Issue
Block a user