diff --git a/pkg/registry/networking/rest/storage_settings.go b/pkg/registry/networking/rest/storage_settings.go index 59482432c11..a5c63821cc8 100644 --- a/pkg/registry/networking/rest/storage_settings.go +++ b/pkg/registry/networking/rest/storage_settings.go @@ -29,6 +29,7 @@ import ( ingressclassstore "k8s.io/kubernetes/pkg/registry/networking/ingressclass/storage" ipaddressstore "k8s.io/kubernetes/pkg/registry/networking/ipaddress/storage" networkpolicystore "k8s.io/kubernetes/pkg/registry/networking/networkpolicy/storage" + servicecidrstore "k8s.io/kubernetes/pkg/registry/networking/servicecidr/storage" ) type RESTStorageProvider struct{} @@ -98,6 +99,17 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource serverstora } storage[resource] = ipAddressStorage } + + // servicecidrs + if resource := "servicecidrs"; apiResourceConfigSource.ResourceEnabled(networkingapiv1alpha1.SchemeGroupVersion.WithResource(resource)) { + serviceCIDRStorage, serviceCIDRStatusStorage, err := servicecidrstore.NewREST(restOptionsGetter) + if err != nil { + return storage, err + } + storage[resource] = serviceCIDRStorage + storage[resource+"/status"] = serviceCIDRStatusStorage + } + return storage, nil } diff --git a/pkg/registry/networking/servicecidr/doc.go b/pkg/registry/networking/servicecidr/doc.go new file mode 100644 index 00000000000..806463623bf --- /dev/null +++ b/pkg/registry/networking/servicecidr/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2022 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 servicecidr // import "k8s.io/kubernetes/pkg/registry/networking/servicecidr" diff --git a/pkg/registry/networking/servicecidr/storage/storage.go b/pkg/registry/networking/servicecidr/storage/storage.go new file mode 100644 index 00000000000..8d7c7f257da --- /dev/null +++ b/pkg/registry/networking/servicecidr/storage/storage.go @@ -0,0 +1,101 @@ +/* +Copyright 2023 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 storage + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/kubernetes/pkg/apis/networking" + "k8s.io/kubernetes/pkg/printers" + printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" + printerstorage "k8s.io/kubernetes/pkg/printers/storage" + "k8s.io/kubernetes/pkg/registry/networking/servicecidr" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" +) + +// REST implements a RESTStorage for IPRange against etcd +type REST struct { + *genericregistry.Store +} + +// NewREST returns a RESTStorage object that will work against service CIDRs. +func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) { + store := &genericregistry.Store{ + NewFunc: func() runtime.Object { return &networking.ServiceCIDR{} }, + NewListFunc: func() runtime.Object { return &networking.ServiceCIDRList{} }, + DefaultQualifiedResource: networking.Resource("servicecidrs"), + SingularQualifiedResource: networking.Resource("servicecidr"), + + CreateStrategy: servicecidr.Strategy, + UpdateStrategy: servicecidr.Strategy, + DeleteStrategy: servicecidr.Strategy, + ResetFieldsStrategy: servicecidr.Strategy, + + TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)}, + } + options := &generic.StoreOptions{RESTOptions: optsGetter} + if err := store.CompleteWithOptions(options); err != nil { + return nil, nil, err + } + + statusStore := *store + statusStore.UpdateStrategy = servicecidr.StatusStrategy + statusStore.ResetFieldsStrategy = servicecidr.StatusStrategy + return &REST{store}, &StatusREST{store: &statusStore}, nil +} + +// StatusREST implements the REST endpoint for changing the status of an ingress +type StatusREST struct { + store *genericregistry.Store +} + +// New creates an instance of the StatusREST object +func (r *StatusREST) New() runtime.Object { + return &networking.ServiceCIDR{} +} + +// Destroy cleans up resources on shutdown. +func (r *StatusREST) Destroy() { + // Given that underlying store is shared with REST, + // we don't destroy it here explicitly. +} + +// Get retrieves the object from the storage. It is required to support Patch. +func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return r.store.Get(ctx, name, options) +} + +// Update alters the status subset of an object. +func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { + // We are explicitly setting forceAllowCreate to false in the call to the underlying storage because + // subresources should never allow create on update. + return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options) +} + +func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { + return r.store.ConvertToTable(ctx, object, tableOptions) +} + +// GetResetFields implements rest.ResetFieldsStrategy +func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return r.store.GetResetFields() +} diff --git a/pkg/registry/networking/servicecidr/strategy.go b/pkg/registry/networking/servicecidr/strategy.go new file mode 100644 index 00000000000..229e8ef25c4 --- /dev/null +++ b/pkg/registry/networking/servicecidr/strategy.go @@ -0,0 +1,151 @@ +/* +Copyright 2023 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 servicecidr + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/apis/networking" + "k8s.io/kubernetes/pkg/apis/networking/validation" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" +) + +// serviceCIDRStrategy implements verification logic for ServiceCIDR allocators. +type serviceCIDRStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +// Strategy is the default logic that applies when creating and updating Replication ServiceCIDR objects. +var Strategy = serviceCIDRStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} + +// Strategy should implement rest.RESTCreateStrategy +var _ rest.RESTCreateStrategy = Strategy + +// Strategy should implement rest.RESTUpdateStrategy +var _ rest.RESTUpdateStrategy = Strategy + +// NamespaceScoped returns false because all ServiceCIDRes is cluster scoped. +func (serviceCIDRStrategy) NamespaceScoped() bool { + return false +} + +// GetResetFields returns the set of fields that get reset by the strategy +// and should not be modified by the user. +func (serviceCIDRStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + fields := map[fieldpath.APIVersion]*fieldpath.Set{ + "networking/v1alpha1": fieldpath.NewSet( + fieldpath.MakePathOrDie("status"), + ), + } + return fields +} + +// PrepareForCreate clears the status of an ServiceCIDR before creation. +func (serviceCIDRStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { + _ = obj.(*networking.ServiceCIDR) + +} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update. +func (serviceCIDRStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newServiceCIDR := obj.(*networking.ServiceCIDR) + oldServiceCIDR := old.(*networking.ServiceCIDR) + + _, _ = newServiceCIDR, oldServiceCIDR +} + +// Validate validates a new ServiceCIDR. +func (serviceCIDRStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { + cidrConfig := obj.(*networking.ServiceCIDR) + err := validation.ValidateServiceCIDR(cidrConfig) + return err +} + +// Canonicalize normalizes the object after validation. +func (serviceCIDRStrategy) Canonicalize(obj runtime.Object) { +} + +// AllowCreateOnUpdate is false for ServiceCIDR; this means POST is needed to create one. +func (serviceCIDRStrategy) AllowCreateOnUpdate() bool { + return false +} + +// WarningsOnCreate returns warnings for the creation of the given object. +func (serviceCIDRStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { + return nil +} + +// ValidateUpdate is the default update validation for an end user. +func (serviceCIDRStrategy) ValidateUpdate(ctx context.Context, new, old runtime.Object) field.ErrorList { + newServiceCIDR := new.(*networking.ServiceCIDR) + oldServiceCIDR := old.(*networking.ServiceCIDR) + errList := validation.ValidateServiceCIDR(newServiceCIDR) + errList = append(errList, validation.ValidateServiceCIDRUpdate(newServiceCIDR, oldServiceCIDR)...) + return errList +} + +// AllowUnconditionalUpdate is the default update policy for ServiceCIDR objects. +func (serviceCIDRStrategy) AllowUnconditionalUpdate() bool { + return true +} + +// WarningsOnUpdate returns warnings for the given update. +func (serviceCIDRStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { + return nil +} + +type serviceCIDRStatusStrategy struct { + serviceCIDRStrategy +} + +// StatusStrategy implements logic used to validate and prepare for updates of the status subresource +var StatusStrategy = serviceCIDRStatusStrategy{Strategy} + +// GetResetFields returns the set of fields that get reset by the strategy +// and should not be modified by the user. +func (serviceCIDRStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + fields := map[fieldpath.APIVersion]*fieldpath.Set{ + "networking/v1alpha1": fieldpath.NewSet( + fieldpath.MakePathOrDie("spec"), + ), + } + return fields +} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status +func (serviceCIDRStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newServiceCIDR := obj.(*networking.ServiceCIDR) + oldServiceCIDR := old.(*networking.ServiceCIDR) + // status changes are not allowed to update spec + newServiceCIDR.Spec = oldServiceCIDR.Spec +} + +// ValidateUpdate is the default update validation for an end user updating status +func (serviceCIDRStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + return validation.ValidateServiceCIDRStatusUpdate(obj.(*networking.ServiceCIDR), old.(*networking.ServiceCIDR)) +} + +// WarningsOnUpdate returns warnings for the given update. +func (serviceCIDRStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { + return nil +} diff --git a/pkg/registry/networking/servicecidr/strategy_test.go b/pkg/registry/networking/servicecidr/strategy_test.go new file mode 100644 index 00000000000..dcdd3a767d9 --- /dev/null +++ b/pkg/registry/networking/servicecidr/strategy_test.go @@ -0,0 +1,17 @@ +/* +Copyright 2023 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 servicecidr