From 7d3012f2979429fc4987c5b004f5fd38a4869df4 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Mon, 11 Nov 2019 12:46:48 -0500 Subject: [PATCH] Promote resource quota admission configuration to v1 --- hack/.golint_failures | 1 + plugin/pkg/admission/resourcequota/BUILD | 7 +- .../resourcequota/apis/resourcequota/BUILD | 1 + .../apis/resourcequota/install/BUILD | 1 + .../apis/resourcequota/install/install.go | 7 + .../apis/resourcequota/register.go | 24 ++- .../resourcequota/apis/resourcequota/v1/BUILD | 41 +++++ .../apis/resourcequota/v1/defaults.go | 25 +++ .../apis/resourcequota/v1/doc.go | 23 +++ .../apis/resourcequota/v1/register.go | 51 ++++++ .../apis/resourcequota/v1/types.go | 69 ++++++++ .../v1/zz_generated.conversion.go | 106 +++++++++++++ .../resourcequota/v1/zz_generated.deepcopy.go | 86 ++++++++++ .../resourcequota/v1/zz_generated.defaults.go | 37 +++++ plugin/pkg/admission/resourcequota/config.go | 4 +- .../admission/resourcequota/config_test.go | 150 ++++++++++++++++++ 16 files changed, 616 insertions(+), 17 deletions(-) create mode 100644 plugin/pkg/admission/resourcequota/apis/resourcequota/v1/BUILD create mode 100644 plugin/pkg/admission/resourcequota/apis/resourcequota/v1/defaults.go create mode 100644 plugin/pkg/admission/resourcequota/apis/resourcequota/v1/doc.go create mode 100644 plugin/pkg/admission/resourcequota/apis/resourcequota/v1/register.go create mode 100644 plugin/pkg/admission/resourcequota/apis/resourcequota/v1/types.go create mode 100644 plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.conversion.go create mode 100644 plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.deepcopy.go create mode 100644 plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.defaults.go create mode 100644 plugin/pkg/admission/resourcequota/config_test.go diff --git a/hack/.golint_failures b/hack/.golint_failures index 882b494988a..122dc6ef124 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -244,6 +244,7 @@ pkg/volume/util/volumepathhandler pkg/volume/vsphere_volume plugin/pkg/admission/eventratelimit/apis/eventratelimit/v1alpha1 plugin/pkg/admission/limitranger +plugin/pkg/admission/resourcequota/apis/resourcequota/v1 plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1 plugin/pkg/admission/resourcequota/apis/resourcequota/v1beta1 plugin/pkg/auth/authorizer/node diff --git a/plugin/pkg/admission/resourcequota/BUILD b/plugin/pkg/admission/resourcequota/BUILD index a4c8f1ddcae..33aa9c427ef 100644 --- a/plugin/pkg/admission/resourcequota/BUILD +++ b/plugin/pkg/admission/resourcequota/BUILD @@ -22,7 +22,7 @@ go_library( "//pkg/quota/v1/generic:go_default_library", "//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library", "//plugin/pkg/admission/resourcequota/apis/resourcequota/install:go_default_library", - "//plugin/pkg/admission/resourcequota/apis/resourcequota/v1beta1:go_default_library", + "//plugin/pkg/admission/resourcequota/apis/resourcequota/v1:go_default_library", "//plugin/pkg/admission/resourcequota/apis/resourcequota/validation:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", @@ -49,7 +49,10 @@ go_library( go_test( name = "go_default_test", - srcs = ["admission_test.go"], + srcs = [ + "admission_test.go", + "config_test.go", + ], embed = [":go_default_library"], deps = [ "//pkg/apis/core:go_default_library", diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/BUILD b/plugin/pkg/admission/resourcequota/apis/resourcequota/BUILD index b35353ab96d..21141c2f7b5 100644 --- a/plugin/pkg/admission/resourcequota/apis/resourcequota/BUILD +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/BUILD @@ -34,6 +34,7 @@ filegroup( srcs = [ ":package-srcs", "//plugin/pkg/admission/resourcequota/apis/resourcequota/install:all-srcs", + "//plugin/pkg/admission/resourcequota/apis/resourcequota/v1:all-srcs", "//plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1:all-srcs", "//plugin/pkg/admission/resourcequota/apis/resourcequota/v1beta1:all-srcs", "//plugin/pkg/admission/resourcequota/apis/resourcequota/validation:all-srcs", diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/install/BUILD b/plugin/pkg/admission/resourcequota/apis/resourcequota/install/BUILD index 1a45a3b9cba..a5f132fb6c3 100644 --- a/plugin/pkg/admission/resourcequota/apis/resourcequota/install/BUILD +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/install/BUILD @@ -11,6 +11,7 @@ go_library( importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install", deps = [ "//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library", + "//plugin/pkg/admission/resourcequota/apis/resourcequota/v1:go_default_library", "//plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1:go_default_library", "//plugin/pkg/admission/resourcequota/apis/resourcequota/v1beta1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/install/install.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/install/install.go index e152eedf750..d0d9033077d 100644 --- a/plugin/pkg/admission/resourcequota/apis/resourcequota/install/install.go +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/install/install.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota" + resourcequotav1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1" resourcequotav1alpha1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1" resourcequotav1beta1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1beta1" ) @@ -29,7 +30,13 @@ import ( // Install registers the API group and adds types to a scheme func Install(scheme *runtime.Scheme) { utilruntime.Must(resourcequotaapi.AddToScheme(scheme)) + + // v1beta1 and v1alpha1 are in the k8s.io-suffixed group utilruntime.Must(resourcequotav1beta1.AddToScheme(scheme)) utilruntime.Must(resourcequotav1alpha1.AddToScheme(scheme)) utilruntime.Must(scheme.SetVersionPriority(resourcequotav1beta1.SchemeGroupVersion, resourcequotav1alpha1.SchemeGroupVersion)) + + // v1 is in the config.k8s.io-suffixed group + utilruntime.Must(resourcequotav1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(resourcequotav1.SchemeGroupVersion)) } diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/register.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/register.go index e36b7143fa9..4d9735d49d5 100644 --- a/plugin/pkg/admission/resourcequota/apis/resourcequota/register.go +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/register.go @@ -28,25 +28,23 @@ var ( AddToScheme = SchemeBuilder.AddToScheme ) +// LegacyGroupName is the group name use in this package +const LegacyGroupName = "resourcequota.admission.k8s.io" + +// LegacySchemeGroupVersion is group version used to register these objects +var LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: runtime.APIVersionInternal} + // GroupName is the group name use in this package -const GroupName = "resourcequota.admission.k8s.io" +const GroupName = "apiserver.config.k8s.io" // SchemeGroupVersion is group version used to register these objects var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} -// Kind takes an unqualified kind and returns a Group qualified GroupKind -func Kind(kind string) schema.GroupKind { - return SchemeGroupVersion.WithKind(kind).GroupKind() -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - func addKnownTypes(scheme *runtime.Scheme) error { - // TODO this will get cleaned up with the scheme types are fixed - scheme.AddKnownTypes(SchemeGroupVersion, + scheme.AddKnownTypes(LegacySchemeGroupVersion, + &Configuration{}, + ) + scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ResourceQuotaConfiguration"), &Configuration{}, ) return nil diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/BUILD b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/BUILD new file mode 100644 index 00000000000..da66afcd3fc --- /dev/null +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/BUILD @@ -0,0 +1,41 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = [ + "defaults.go", + "doc.go", + "register.go", + "types.go", + "zz_generated.conversion.go", + "zz_generated.deepcopy.go", + "zz_generated.defaults.go", + ], + importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1", + deps = [ + "//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/defaults.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/defaults.go new file mode 100644 index 00000000000..1a2f1b4440d --- /dev/null +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/defaults.go @@ -0,0 +1,25 @@ +/* +Copyright 2019 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 v1 + +import kruntime "k8s.io/apimachinery/pkg/runtime" + +func addDefaultingFuncs(scheme *kruntime.Scheme) error { + return RegisterDefaults(scheme) +} + +func SetDefaults_Configuration(obj *Configuration) {} diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/doc.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/doc.go new file mode 100644 index 00000000000..f0af6d3692e --- /dev/null +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2019 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota +// +k8s:defaulter-gen=TypeMeta +// +groupName=resourcequota.admission.k8s.io + +// Package v1 is the v1 version of the API. +package v1 // import "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1" diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/register.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/register.go new file mode 100644 index 00000000000..04969a16299 --- /dev/null +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/register.go @@ -0,0 +1,51 @@ +/* +Copyright 2019 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 v1 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = "apiserver.config.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + + // SchemeBuilder is a pointer used to call AddToScheme + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + // AddToScheme is used to register the types to API encoding/decoding machinery + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs) +} + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ResourceQuotaConfiguration"), &Configuration{}) + return nil +} diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/types.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/types.go new file mode 100644 index 00000000000..e703724c658 --- /dev/null +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/types.go @@ -0,0 +1,69 @@ +/* +Copyright 2019 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 v1 + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Configuration provides configuration for the ResourceQuota admission controller. +type Configuration struct { + metav1.TypeMeta `json:",inline"` + + // LimitedResources whose consumption is limited by default. + // +optional + LimitedResources []LimitedResource `json:"limitedResources"` +} + +// LimitedResource matches a resource whose consumption is limited by default. +// To consume the resource, there must exist an associated quota that limits +// its consumption. +type LimitedResource struct { + + // APIGroup is the name of the APIGroup that contains the limited resource. + // +optional + APIGroup string `json:"apiGroup,omitempty"` + + // Resource is the name of the resource this rule applies to. + // For example, if the administrator wants to limit consumption + // of a storage resource associated with persistent volume claims, + // the value would be "persistentvolumeclaims". + Resource string `json:"resource"` + + // For each intercepted request, the quota system will evaluate + // its resource usage. It will iterate through each resource consumed + // and if the resource contains any substring in this listing, the + // quota system will ensure that there is a covering quota. In the + // absence of a covering quota, the quota system will deny the request. + // For example, if an administrator wants to globally enforce that + // that a quota must exist to consume persistent volume claims associated + // with any storage class, the list would include + // ".storageclass.storage.k8s.io/requests.storage" + MatchContains []string `json:"matchContains,omitempty"` + // For each intercepted request, the quota system will figure out if the input object + // satisfies a scope which is present in this listing, then + // quota system will ensure that there is a covering quota. In the + // absence of a covering quota, the quota system will deny the request. + // For example, if an administrator wants to globally enforce that + // a quota must exist to create a pod with "cluster-services" priorityclass + // the list would include "scopeName=PriorityClass, Operator=In, Value=cluster-services" + // +optional + MatchScopes []v1.ScopedResourceSelectorRequirement `json:"matchScopes,omitempty"` +} diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.conversion.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.conversion.go new file mode 100644 index 00000000000..3d4276ee203 --- /dev/null +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.conversion.go @@ -0,0 +1,106 @@ +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + corev1 "k8s.io/api/core/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + resourcequota "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*Configuration)(nil), (*resourcequota.Configuration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Configuration_To_resourcequota_Configuration(a.(*Configuration), b.(*resourcequota.Configuration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*resourcequota.Configuration)(nil), (*Configuration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_resourcequota_Configuration_To_v1_Configuration(a.(*resourcequota.Configuration), b.(*Configuration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*LimitedResource)(nil), (*resourcequota.LimitedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LimitedResource_To_resourcequota_LimitedResource(a.(*LimitedResource), b.(*resourcequota.LimitedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*resourcequota.LimitedResource)(nil), (*LimitedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_resourcequota_LimitedResource_To_v1_LimitedResource(a.(*resourcequota.LimitedResource), b.(*LimitedResource), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_Configuration_To_resourcequota_Configuration(in *Configuration, out *resourcequota.Configuration, s conversion.Scope) error { + out.LimitedResources = *(*[]resourcequota.LimitedResource)(unsafe.Pointer(&in.LimitedResources)) + return nil +} + +// Convert_v1_Configuration_To_resourcequota_Configuration is an autogenerated conversion function. +func Convert_v1_Configuration_To_resourcequota_Configuration(in *Configuration, out *resourcequota.Configuration, s conversion.Scope) error { + return autoConvert_v1_Configuration_To_resourcequota_Configuration(in, out, s) +} + +func autoConvert_resourcequota_Configuration_To_v1_Configuration(in *resourcequota.Configuration, out *Configuration, s conversion.Scope) error { + out.LimitedResources = *(*[]LimitedResource)(unsafe.Pointer(&in.LimitedResources)) + return nil +} + +// Convert_resourcequota_Configuration_To_v1_Configuration is an autogenerated conversion function. +func Convert_resourcequota_Configuration_To_v1_Configuration(in *resourcequota.Configuration, out *Configuration, s conversion.Scope) error { + return autoConvert_resourcequota_Configuration_To_v1_Configuration(in, out, s) +} + +func autoConvert_v1_LimitedResource_To_resourcequota_LimitedResource(in *LimitedResource, out *resourcequota.LimitedResource, s conversion.Scope) error { + out.APIGroup = in.APIGroup + out.Resource = in.Resource + out.MatchContains = *(*[]string)(unsafe.Pointer(&in.MatchContains)) + out.MatchScopes = *(*[]corev1.ScopedResourceSelectorRequirement)(unsafe.Pointer(&in.MatchScopes)) + return nil +} + +// Convert_v1_LimitedResource_To_resourcequota_LimitedResource is an autogenerated conversion function. +func Convert_v1_LimitedResource_To_resourcequota_LimitedResource(in *LimitedResource, out *resourcequota.LimitedResource, s conversion.Scope) error { + return autoConvert_v1_LimitedResource_To_resourcequota_LimitedResource(in, out, s) +} + +func autoConvert_resourcequota_LimitedResource_To_v1_LimitedResource(in *resourcequota.LimitedResource, out *LimitedResource, s conversion.Scope) error { + out.APIGroup = in.APIGroup + out.Resource = in.Resource + out.MatchContains = *(*[]string)(unsafe.Pointer(&in.MatchContains)) + out.MatchScopes = *(*[]corev1.ScopedResourceSelectorRequirement)(unsafe.Pointer(&in.MatchScopes)) + return nil +} + +// Convert_resourcequota_LimitedResource_To_v1_LimitedResource is an autogenerated conversion function. +func Convert_resourcequota_LimitedResource_To_v1_LimitedResource(in *resourcequota.LimitedResource, out *LimitedResource, s conversion.Scope) error { + return autoConvert_resourcequota_LimitedResource_To_v1_LimitedResource(in, out, s) +} diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.deepcopy.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..f777dbb0ef8 --- /dev/null +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.deepcopy.go @@ -0,0 +1,86 @@ +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Configuration) DeepCopyInto(out *Configuration) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.LimitedResources != nil { + in, out := &in.LimitedResources, &out.LimitedResources + *out = make([]LimitedResource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Configuration. +func (in *Configuration) DeepCopy() *Configuration { + if in == nil { + return nil + } + out := new(Configuration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Configuration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LimitedResource) DeepCopyInto(out *LimitedResource) { + *out = *in + if in.MatchContains != nil { + in, out := &in.MatchContains, &out.MatchContains + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.MatchScopes != nil { + in, out := &in.MatchScopes, &out.MatchScopes + *out = make([]corev1.ScopedResourceSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitedResource. +func (in *LimitedResource) DeepCopy() *LimitedResource { + if in == nil { + return nil + } + out := new(LimitedResource) + in.DeepCopyInto(out) + return out +} diff --git a/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.defaults.go b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.defaults.go new file mode 100644 index 00000000000..3299553542a --- /dev/null +++ b/plugin/pkg/admission/resourcequota/apis/resourcequota/v1/zz_generated.defaults.go @@ -0,0 +1,37 @@ +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&Configuration{}, func(obj interface{}) { SetObjectDefaults_Configuration(obj.(*Configuration)) }) + return nil +} + +func SetObjectDefaults_Configuration(in *Configuration) { + SetDefaults_Configuration(in) +} diff --git a/plugin/pkg/admission/resourcequota/config.go b/plugin/pkg/admission/resourcequota/config.go index 626b354b5b9..979ffba1330 100644 --- a/plugin/pkg/admission/resourcequota/config.go +++ b/plugin/pkg/admission/resourcequota/config.go @@ -25,7 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer" resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota" "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install" - resourcequotav1beta1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1beta1" + resourcequotav1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1" ) var ( @@ -41,7 +41,7 @@ func init() { func LoadConfiguration(config io.Reader) (*resourcequotaapi.Configuration, error) { // if no config is provided, return a default configuration if config == nil { - externalConfig := &resourcequotav1beta1.Configuration{} + externalConfig := &resourcequotav1.Configuration{} scheme.Default(externalConfig) internalConfig := &resourcequotaapi.Configuration{} if err := scheme.Convert(externalConfig, internalConfig, nil); err != nil { diff --git a/plugin/pkg/admission/resourcequota/config_test.go b/plugin/pkg/admission/resourcequota/config_test.go new file mode 100644 index 00000000000..18473ebf6e0 --- /dev/null +++ b/plugin/pkg/admission/resourcequota/config_test.go @@ -0,0 +1,150 @@ +/* +Copyright 2019 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 resourcequota + +import ( + "bytes" + "reflect" + "strings" + "testing" + + corev1 "k8s.io/api/core/v1" + resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota" +) + +func TestLoadConfiguration(t *testing.T) { + testcases := []struct { + name string + input string + expectErr string + expectConfig *resourcequotaapi.Configuration + }{ + { + name: "empty", + input: ``, + expectErr: `'Kind' is missing`, + }, + { + name: "unknown type", + input: `{"kind":"Unknown","apiVersion":"v1"}`, + expectErr: `no kind "Unknown" is registered`, + }, + { + name: "valid v1alpha1 config", + input: ` +kind: Configuration +apiVersion: resourcequota.admission.k8s.io/v1alpha1 +limitedResources: +- apiGroup: "" + resource: persistentvolumeclaims + matchContains: + - .storageclass.storage.k8s.io/requests.storage +- apiGroup: "" + resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: + - cluster-services +`, + expectConfig: &resourcequotaapi.Configuration{ + LimitedResources: []resourcequotaapi.LimitedResource{ + {APIGroup: "", Resource: "persistentvolumeclaims", MatchContains: []string{".storageclass.storage.k8s.io/requests.storage"}}, + {APIGroup: "", Resource: "pods", MatchScopes: []corev1.ScopedResourceSelectorRequirement{ + {ScopeName: "PriorityClass", Operator: "In", Values: []string{"cluster-services"}}, + }, + }, + }}, + }, + { + name: "valid v1beta1 config", + input: ` +kind: Configuration +apiVersion: resourcequota.admission.k8s.io/v1beta1 +limitedResources: +- apiGroup: "" + resource: persistentvolumeclaims + matchContains: + - .storageclass.storage.k8s.io/requests.storage +- apiGroup: "" + resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: + - cluster-services +`, + expectConfig: &resourcequotaapi.Configuration{ + LimitedResources: []resourcequotaapi.LimitedResource{ + {APIGroup: "", Resource: "persistentvolumeclaims", MatchContains: []string{".storageclass.storage.k8s.io/requests.storage"}}, + {APIGroup: "", Resource: "pods", MatchScopes: []corev1.ScopedResourceSelectorRequirement{ + {ScopeName: "PriorityClass", Operator: "In", Values: []string{"cluster-services"}}, + }, + }, + }}, + }, + { + name: "valid v1 config", + input: ` +kind: ResourceQuotaConfiguration +apiVersion: apiserver.config.k8s.io/v1 +limitedResources: +- apiGroup: "" + resource: persistentvolumeclaims + matchContains: + - .storageclass.storage.k8s.io/requests.storage +- apiGroup: "" + resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: + - cluster-services +`, + expectConfig: &resourcequotaapi.Configuration{ + LimitedResources: []resourcequotaapi.LimitedResource{ + {APIGroup: "", Resource: "persistentvolumeclaims", MatchContains: []string{".storageclass.storage.k8s.io/requests.storage"}}, + {APIGroup: "", Resource: "pods", MatchScopes: []corev1.ScopedResourceSelectorRequirement{ + {ScopeName: "PriorityClass", Operator: "In", Values: []string{"cluster-services"}}, + }, + }, + }}, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + config, err := LoadConfiguration(bytes.NewBuffer([]byte(tc.input))) + + if len(tc.expectErr) > 0 { + if err == nil { + t.Fatal("expected err, got none") + } + if !strings.Contains(err.Error(), tc.expectErr) { + t.Fatalf("expected err containing %q, got %v", tc.expectErr, err) + } + return + } + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(config, tc.expectConfig) { + t.Fatalf("expected\n%#v\ngot\n%#v", tc.expectConfig, config) + } + }) + } +}