From 262799f91f251a1d37e81fcae9f5fdf029ef77fa Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Tue, 23 May 2017 19:07:40 -0700 Subject: [PATCH] serve the api in kube-apiserver --- .../admissionregistration/install/install.go | 5 + pkg/master/import_known_versions.go | 1 + pkg/master/master.go | 12 +- .../externaladmissionhookconfiguration/doc.go | 17 +++ .../storage/storage.go | 56 ++++++++ .../strategy.go | 120 ++++++++++++++++++ .../initializerconfiguration/doc.go | 17 +++ .../storage/storage.go | 56 ++++++++ .../initializerconfiguration/strategy.go | 120 ++++++++++++++++++ .../rest/storage_apiserver.go | 59 +++++++++ .../etcd/etcd_storage_path_test.go | 10 ++ 11 files changed, 469 insertions(+), 4 deletions(-) create mode 100644 pkg/registry/admissionregistration/externaladmissionhookconfiguration/doc.go create mode 100644 pkg/registry/admissionregistration/externaladmissionhookconfiguration/storage/storage.go create mode 100644 pkg/registry/admissionregistration/externaladmissionhookconfiguration/strategy.go create mode 100644 pkg/registry/admissionregistration/initializerconfiguration/doc.go create mode 100644 pkg/registry/admissionregistration/initializerconfiguration/storage/storage.go create mode 100644 pkg/registry/admissionregistration/initializerconfiguration/strategy.go create mode 100644 pkg/registry/admissionregistration/rest/storage_apiserver.go diff --git a/pkg/apis/admissionregistration/install/install.go b/pkg/apis/admissionregistration/install/install.go index 113c8c6dec..28bc44c28a 100644 --- a/pkg/apis/admissionregistration/install/install.go +++ b/pkg/apis/admissionregistration/install/install.go @@ -21,10 +21,15 @@ import ( "k8s.io/apimachinery/pkg/apimachinery/registered" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/admissionregistration" "k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1" ) +func init() { + Install(api.GroupFactoryRegistry, api.Registry, api.Scheme) +} + // Install registers the API group and adds types to a scheme func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) { if err := announced.NewGroupMetaFactory( diff --git a/pkg/master/import_known_versions.go b/pkg/master/import_known_versions.go index 30a4420b96..355b0f0beb 100644 --- a/pkg/master/import_known_versions.go +++ b/pkg/master/import_known_versions.go @@ -22,6 +22,7 @@ import ( "k8s.io/kubernetes/pkg/api" _ "k8s.io/kubernetes/pkg/api/install" + _ "k8s.io/kubernetes/pkg/apis/admissionregistration/install" _ "k8s.io/kubernetes/pkg/apis/apps/install" _ "k8s.io/kubernetes/pkg/apis/authentication/install" _ "k8s.io/kubernetes/pkg/apis/authorization/install" diff --git a/pkg/master/master.go b/pkg/master/master.go index 26d114ca29..b3a53040ee 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -34,6 +34,7 @@ import ( "k8s.io/kubernetes/cmd/kube-apiserver/app/options" "k8s.io/kubernetes/pkg/api" apiv1 "k8s.io/kubernetes/pkg/api/v1" + admissionregistrationv1alpha1 "k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1" appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1" authenticationv1 "k8s.io/kubernetes/pkg/apis/authentication/v1" authenticationv1beta1 "k8s.io/kubernetes/pkg/apis/authentication/v1beta1" @@ -44,9 +45,9 @@ import ( certificatesapiv1beta1 "k8s.io/kubernetes/pkg/apis/certificates/v1beta1" extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" policyapiv1beta1 "k8s.io/kubernetes/pkg/apis/policy/v1beta1" - rbacapi "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" - settingsapi "k8s.io/kubernetes/pkg/apis/settings/v1alpha1" + settingv1alpha1 "k8s.io/kubernetes/pkg/apis/settings/v1alpha1" storageapiv1 "k8s.io/kubernetes/pkg/apis/storage/v1" storageapiv1beta1 "k8s.io/kubernetes/pkg/apis/storage/v1beta1" corev1client "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1" @@ -61,6 +62,7 @@ import ( "github.com/prometheus/client_golang/prometheus" // RESTStorage installers + admissionregistrationrest "k8s.io/kubernetes/pkg/registry/admissionregistration/rest" appsrest "k8s.io/kubernetes/pkg/registry/apps/rest" authenticationrest "k8s.io/kubernetes/pkg/registry/authentication/rest" authorizationrest "k8s.io/kubernetes/pkg/registry/authorization/rest" @@ -258,6 +260,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) // keep apps after extensions so legacy clients resolve the extensions versions of shared resource names. // See https://github.com/kubernetes/kubernetes/issues/42392 appsrest.RESTStorageProvider{}, + admissionregistrationrest.RESTStorageProvider{}, } m.InstallAPIs(c.Config.APIResourceConfigSource, c.Config.GenericConfig.RESTOptionsGetter, restStorageProviders...) @@ -371,6 +374,7 @@ func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig { ret := serverstorage.NewResourceConfig() ret.EnableVersions( apiv1.SchemeGroupVersion, + admissionregistrationv1alpha1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, authenticationv1.SchemeGroupVersion, @@ -379,8 +383,8 @@ func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig { appsv1beta1.SchemeGroupVersion, policyapiv1beta1.SchemeGroupVersion, rbacv1beta1.SchemeGroupVersion, - rbacapi.SchemeGroupVersion, - settingsapi.SchemeGroupVersion, + rbacv1alpha1.SchemeGroupVersion, + settingv1alpha1.SchemeGroupVersion, storageapiv1.SchemeGroupVersion, storageapiv1beta1.SchemeGroupVersion, certificatesapiv1beta1.SchemeGroupVersion, diff --git a/pkg/registry/admissionregistration/externaladmissionhookconfiguration/doc.go b/pkg/registry/admissionregistration/externaladmissionhookconfiguration/doc.go new file mode 100644 index 0000000000..dcbd2a048c --- /dev/null +++ b/pkg/registry/admissionregistration/externaladmissionhookconfiguration/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2015 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 externaladmissionhookconfiguration // import "k8s.io/kubernetes/pkg/registry/admissionregistration/externaladmissionhookconfiguration" diff --git a/pkg/registry/admissionregistration/externaladmissionhookconfiguration/storage/storage.go b/pkg/registry/admissionregistration/externaladmissionhookconfiguration/storage/storage.go new file mode 100644 index 0000000000..0aefa3b452 --- /dev/null +++ b/pkg/registry/admissionregistration/externaladmissionhookconfiguration/storage/storage.go @@ -0,0 +1,56 @@ +/* +Copyright 2015 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 ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/admissionregistration" + "k8s.io/kubernetes/pkg/registry/admissionregistration/externaladmissionhookconfiguration" + "k8s.io/kubernetes/pkg/registry/cachesize" +) + +// rest implements a RESTStorage for pod disruption budgets against etcd +type REST struct { + *genericregistry.Store +} + +// NewREST returns a RESTStorage object that will work against pod disruption budgets. +func NewREST(optsGetter generic.RESTOptionsGetter) *REST { + store := &genericregistry.Store{ + Copier: api.Scheme, + NewFunc: func() runtime.Object { return &admissionregistration.ExternalAdmissionHookConfiguration{} }, + NewListFunc: func() runtime.Object { return &admissionregistration.ExternalAdmissionHookConfigurationList{} }, + ObjectNameFunc: func(obj runtime.Object) (string, error) { + return obj.(*admissionregistration.ExternalAdmissionHookConfiguration).Name, nil + }, + PredicateFunc: externaladmissionhookconfiguration.MatchExternalAdmissionHookConfiguration, + QualifiedResource: admissionregistration.Resource("externaladmissionhookconfigurations"), + WatchCacheSize: cachesize.GetWatchCacheSizeByResource("externaladmissionhookconfigurations"), + + CreateStrategy: externaladmissionhookconfiguration.Strategy, + UpdateStrategy: externaladmissionhookconfiguration.Strategy, + DeleteStrategy: externaladmissionhookconfiguration.Strategy, + } + options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: externaladmissionhookconfiguration.GetAttrs} + if err := store.CompleteWithOptions(options); err != nil { + panic(err) // TODO: Propagate error up + } + return &REST{store} +} diff --git a/pkg/registry/admissionregistration/externaladmissionhookconfiguration/strategy.go b/pkg/registry/admissionregistration/externaladmissionhookconfiguration/strategy.go new file mode 100644 index 0000000000..eaa997206b --- /dev/null +++ b/pkg/registry/admissionregistration/externaladmissionhookconfiguration/strategy.go @@ -0,0 +1,120 @@ +/* +Copyright 2014 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 externaladmissionhookconfiguration + +import ( + "fmt" + "reflect" + + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/generic" + apistorage "k8s.io/apiserver/pkg/storage" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/admissionregistration" + "k8s.io/kubernetes/pkg/apis/admissionregistration/validation" +) + +// externaladmissionhookConfigurationStrategy implements verification logic for ExternalAdmissionHookConfiguration. +type externaladmissionhookConfigurationStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +// Strategy is the default logic that applies when creating and updating ExternalAdmissionHookConfiguration objects. +var Strategy = externaladmissionhookConfigurationStrategy{api.Scheme, names.SimpleNameGenerator} + +// NamespaceScoped returns true because all ExternalAdmissionHookConfiguration' need to be within a namespace. +func (externaladmissionhookConfigurationStrategy) NamespaceScoped() bool { + return false +} + +// PrepareForCreate clears the status of an ExternalAdmissionHookConfiguration before creation. +func (externaladmissionhookConfigurationStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { + ic := obj.(*admissionregistration.ExternalAdmissionHookConfiguration) + ic.Generation = 1 +} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update. +func (externaladmissionhookConfigurationStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { + newIC := obj.(*admissionregistration.ExternalAdmissionHookConfiguration) + oldIC := old.(*admissionregistration.ExternalAdmissionHookConfiguration) + + // Any changes to the spec increment the generation number, any changes to the + // status should reflect the generation number of the corresponding object. + // See metav1.ObjectMeta description for more information on Generation. + if !reflect.DeepEqual(oldIC.ExternalAdmissionHooks, newIC.ExternalAdmissionHooks) { + newIC.Generation = oldIC.Generation + 1 + } +} + +// Validate validates a new ExternalAdmissionHookConfiguration. +func (externaladmissionhookConfigurationStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList { + ic := obj.(*admissionregistration.ExternalAdmissionHookConfiguration) + return validation.ValidateExternalAdmissionHookConfiguration(ic) +} + +// Canonicalize normalizes the object after validation. +func (externaladmissionhookConfigurationStrategy) Canonicalize(obj runtime.Object) { +} + +// AllowCreateOnUpdate is true for ExternalAdmissionHookConfiguration; this means you may create one with a PUT request. +func (externaladmissionhookConfigurationStrategy) AllowCreateOnUpdate() bool { + return false +} + +// ValidateUpdate is the default update validation for an end user. +func (externaladmissionhookConfigurationStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList { + validationErrorList := validation.ValidateExternalAdmissionHookConfiguration(obj.(*admissionregistration.ExternalAdmissionHookConfiguration)) + updateErrorList := validation.ValidateExternalAdmissionHookConfigurationUpdate(obj.(*admissionregistration.ExternalAdmissionHookConfiguration), old.(*admissionregistration.ExternalAdmissionHookConfiguration)) + return append(validationErrorList, updateErrorList...) +} + +// AllowUnconditionalUpdate is the default update policy for ExternalAdmissionHookConfiguration objects. Status update should +// only be allowed if version match. +func (externaladmissionhookConfigurationStrategy) AllowUnconditionalUpdate() bool { + return false +} + +// MatchReplicaSet is the filter used by the generic etcd backend to route +// watch events from etcd to clients of the apiserver only interested in specific +// labels/fields. +func MatchExternalAdmissionHookConfiguration(label labels.Selector, field fields.Selector) apistorage.SelectionPredicate { + return apistorage.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: GetAttrs, + } +} + +// GetAttrs returns labels and fields of a given object for filtering purposes. +func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { + ic, ok := obj.(*admissionregistration.ExternalAdmissionHookConfiguration) + if !ok { + return nil, nil, fmt.Errorf("Given object is not a ExternalAdmissionHookConfiguration.") + } + return labels.Set(ic.ObjectMeta.Labels), ExternalAdmissionHookConfigurationToSelectableFields(ic), nil +} + +// ExternalAdmissionHookConfigurationToSelectableFields returns a field set that represents the object. +func ExternalAdmissionHookConfigurationToSelectableFields(ic *admissionregistration.ExternalAdmissionHookConfiguration) fields.Set { + return generic.ObjectMetaFieldsSet(&ic.ObjectMeta, true) +} diff --git a/pkg/registry/admissionregistration/initializerconfiguration/doc.go b/pkg/registry/admissionregistration/initializerconfiguration/doc.go new file mode 100644 index 0000000000..7f4cd229b8 --- /dev/null +++ b/pkg/registry/admissionregistration/initializerconfiguration/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2015 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 initializerconfiguration // import "k8s.io/kubernetes/pkg/registry/admissionregistration/initializerconfiguration" diff --git a/pkg/registry/admissionregistration/initializerconfiguration/storage/storage.go b/pkg/registry/admissionregistration/initializerconfiguration/storage/storage.go new file mode 100644 index 0000000000..e7351fc986 --- /dev/null +++ b/pkg/registry/admissionregistration/initializerconfiguration/storage/storage.go @@ -0,0 +1,56 @@ +/* +Copyright 2015 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 ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/admissionregistration" + "k8s.io/kubernetes/pkg/registry/admissionregistration/initializerconfiguration" + "k8s.io/kubernetes/pkg/registry/cachesize" +) + +// rest implements a RESTStorage for pod disruption budgets against etcd +type REST struct { + *genericregistry.Store +} + +// NewREST returns a RESTStorage object that will work against pod disruption budgets. +func NewREST(optsGetter generic.RESTOptionsGetter) *REST { + store := &genericregistry.Store{ + Copier: api.Scheme, + NewFunc: func() runtime.Object { return &admissionregistration.InitializerConfiguration{} }, + NewListFunc: func() runtime.Object { return &admissionregistration.InitializerConfigurationList{} }, + ObjectNameFunc: func(obj runtime.Object) (string, error) { + return obj.(*admissionregistration.InitializerConfiguration).Name, nil + }, + PredicateFunc: initializerconfiguration.MatchInitializerConfiguration, + QualifiedResource: admissionregistration.Resource("initializerconfigurations"), + WatchCacheSize: cachesize.GetWatchCacheSizeByResource("initializerconfigurations"), + + CreateStrategy: initializerconfiguration.Strategy, + UpdateStrategy: initializerconfiguration.Strategy, + DeleteStrategy: initializerconfiguration.Strategy, + } + options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: initializerconfiguration.GetAttrs} + if err := store.CompleteWithOptions(options); err != nil { + panic(err) // TODO: Propagate error up + } + return &REST{store} +} diff --git a/pkg/registry/admissionregistration/initializerconfiguration/strategy.go b/pkg/registry/admissionregistration/initializerconfiguration/strategy.go new file mode 100644 index 0000000000..c872c13bd9 --- /dev/null +++ b/pkg/registry/admissionregistration/initializerconfiguration/strategy.go @@ -0,0 +1,120 @@ +/* +Copyright 2014 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 initializerconfiguration + +import ( + "fmt" + "reflect" + + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/generic" + apistorage "k8s.io/apiserver/pkg/storage" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/admissionregistration" + "k8s.io/kubernetes/pkg/apis/admissionregistration/validation" +) + +// initializerConfigurationStrategy implements verification logic for InitializerConfigurations. +type initializerConfigurationStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +// Strategy is the default logic that applies when creating and updating InitializerConfiguration objects. +var Strategy = initializerConfigurationStrategy{api.Scheme, names.SimpleNameGenerator} + +// NamespaceScoped returns true because all InitializerConfiguration' need to be within a namespace. +func (initializerConfigurationStrategy) NamespaceScoped() bool { + return false +} + +// PrepareForCreate clears the status of an InitializerConfiguration before creation. +func (initializerConfigurationStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { + ic := obj.(*admissionregistration.InitializerConfiguration) + ic.Generation = 1 +} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update. +func (initializerConfigurationStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { + newIC := obj.(*admissionregistration.InitializerConfiguration) + oldIC := old.(*admissionregistration.InitializerConfiguration) + + // Any changes to the spec increment the generation number, any changes to the + // status should reflect the generation number of the corresponding object. + // See metav1.ObjectMeta description for more information on Generation. + if !reflect.DeepEqual(oldIC.Initializers, newIC.Initializers) { + newIC.Generation = oldIC.Generation + 1 + } +} + +// Validate validates a new InitializerConfiguration. +func (initializerConfigurationStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList { + ic := obj.(*admissionregistration.InitializerConfiguration) + return validation.ValidateInitializerConfiguration(ic) +} + +// Canonicalize normalizes the object after validation. +func (initializerConfigurationStrategy) Canonicalize(obj runtime.Object) { +} + +// AllowCreateOnUpdate is true for InitializerConfiguration; this means you may create one with a PUT request. +func (initializerConfigurationStrategy) AllowCreateOnUpdate() bool { + return false +} + +// ValidateUpdate is the default update validation for an end user. +func (initializerConfigurationStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList { + validationErrorList := validation.ValidateInitializerConfiguration(obj.(*admissionregistration.InitializerConfiguration)) + updateErrorList := validation.ValidateInitializerConfigurationUpdate(obj.(*admissionregistration.InitializerConfiguration), old.(*admissionregistration.InitializerConfiguration)) + return append(validationErrorList, updateErrorList...) +} + +// AllowUnconditionalUpdate is the default update policy for InitializerConfiguration objects. Status update should +// only be allowed if version match. +func (initializerConfigurationStrategy) AllowUnconditionalUpdate() bool { + return false +} + +// MatchReplicaSet is the filter used by the generic etcd backend to route +// watch events from etcd to clients of the apiserver only interested in specific +// labels/fields. +func MatchInitializerConfiguration(label labels.Selector, field fields.Selector) apistorage.SelectionPredicate { + return apistorage.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: GetAttrs, + } +} + +// GetAttrs returns labels and fields of a given object for filtering purposes. +func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { + ic, ok := obj.(*admissionregistration.InitializerConfiguration) + if !ok { + return nil, nil, fmt.Errorf("Given object is not a InitializerConfiguration.") + } + return labels.Set(ic.ObjectMeta.Labels), InitializerConfigurationToSelectableFields(ic), nil +} + +// InitializerConfigurationToSelectableFields returns a field set that represents the object. +func InitializerConfigurationToSelectableFields(ic *admissionregistration.InitializerConfiguration) fields.Set { + return generic.ObjectMetaFieldsSet(&ic.ObjectMeta, true) +} diff --git a/pkg/registry/admissionregistration/rest/storage_apiserver.go b/pkg/registry/admissionregistration/rest/storage_apiserver.go new file mode 100644 index 0000000000..a315cabf5d --- /dev/null +++ b/pkg/registry/admissionregistration/rest/storage_apiserver.go @@ -0,0 +1,59 @@ +/* +Copyright 2016 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 rest + +import ( + "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" + genericapiserver "k8s.io/apiserver/pkg/server" + serverstorage "k8s.io/apiserver/pkg/server/storage" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/admissionregistration" + admissionregistrationv1alpha1 "k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1" + externaladmissionhookconfigurationstorage "k8s.io/kubernetes/pkg/registry/admissionregistration/externaladmissionhookconfiguration/storage" + initializerconfigurationstorage "k8s.io/kubernetes/pkg/registry/admissionregistration/initializerconfiguration/storage" +) + +type RESTStorageProvider struct{} + +func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool) { + apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(admissionregistration.GroupName, api.Registry, api.Scheme, api.ParameterCodec, api.Codecs) + + if apiResourceConfigSource.AnyResourcesForVersionEnabled(admissionregistrationv1alpha1.SchemeGroupVersion) { + apiGroupInfo.VersionedResourcesStorageMap[admissionregistrationv1alpha1.SchemeGroupVersion.Version] = p.v1alpha1Storage(apiResourceConfigSource, restOptionsGetter) + apiGroupInfo.GroupMeta.GroupVersion = admissionregistrationv1alpha1.SchemeGroupVersion + } + return apiGroupInfo, true +} + +func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage { + version := admissionregistrationv1alpha1.SchemeGroupVersion + storage := map[string]rest.Storage{} + if apiResourceConfigSource.ResourceEnabled(version.WithResource("initializerconfigurations")) { + s := initializerconfigurationstorage.NewREST(restOptionsGetter) + storage["initializerconfigurations"] = s + } + if apiResourceConfigSource.ResourceEnabled(version.WithResource("externaladmissionhookconfigurations")) { + s := externaladmissionhookconfigurationstorage.NewREST(restOptionsGetter) + storage["externaladmissionhookconfigurations"] = s + } + return storage +} + +func (p RESTStorageProvider) GroupName() string { + return admissionregistration.GroupName +} diff --git a/test/integration/etcd/etcd_storage_path_test.go b/test/integration/etcd/etcd_storage_path_test.go index 33d0e984ac..5ab5b3355c 100644 --- a/test/integration/etcd/etcd_storage_path_test.go +++ b/test/integration/etcd/etcd_storage_path_test.go @@ -289,6 +289,16 @@ var etcdStorageData = map[schema.GroupVersionResource]struct { expectedEtcdPath: "/registry/clusterrolebindings/croleb2", }, // -- + + // k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1 + gvr("admissionregistration.k8s.io", "v1alpha1", "initializerconfigurations"): { + stub: `{"metadata":{"name":"ic1"},"initializers":[{"name":"initializer.k8s.io","rules":[{"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore"}]}`, + expectedEtcdPath: "/registry/initializerconfigurations/ic1", + }, + gvr("admissionregistration.k8s.io", "v1alpha1", "externaladmissionhookconfigurations"): { + stub: `{"metadata":{"name":"hook1","creationTimestamp":null},"externalAdmissionHooks":[{"name":"externaladmissionhook.k8s.io","clientConfig":{"service":{"namespace":"","name":""},"caBundle":null},"rules":[{"operations":["CREATE"],"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore"}]}`, + expectedEtcdPath: "/registry/externaladmissionhookconfigurations/hook1", + }, } // Be very careful when whitelisting an object as ephemeral.