Promote ValidatingAdmissionPolicy to GA.
This commit is contained in:
		| @@ -299,7 +299,7 @@ func CreateKubeAPIServerConfig(opts options.CompletedOptions) ( | |||||||
| 		CloudConfigFile:      opts.CloudProvider.CloudConfigFile, | 		CloudConfigFile:      opts.CloudProvider.CloudConfigFile, | ||||||
| 	} | 	} | ||||||
| 	serviceResolver := buildServiceResolver(opts.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers) | 	serviceResolver := buildServiceResolver(opts.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers) | ||||||
| 	pluginInitializers, admissionPostStartHook, err := admissionConfig.New(proxyTransport, genericConfig.EgressSelector, serviceResolver, genericConfig.TracerProvider) | 	pluginInitializers, err := admissionConfig.New(proxyTransport, genericConfig.EgressSelector, serviceResolver, genericConfig.TracerProvider) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err) | 		return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err) | ||||||
| 	} | 	} | ||||||
| @@ -321,9 +321,6 @@ func CreateKubeAPIServerConfig(opts options.CompletedOptions) ( | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, nil, nil, fmt.Errorf("failed to apply admission: %w", err) | 		return nil, nil, nil, fmt.Errorf("failed to apply admission: %w", err) | ||||||
| 	} | 	} | ||||||
| 	if err := config.GenericConfig.AddPostStartHook("start-kube-apiserver-admission-initializer", admissionPostStartHook); err != nil { |  | ||||||
| 		return nil, nil, nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if config.GenericConfig.EgressSelector != nil { | 	if config.GenericConfig.EgressSelector != nil { | ||||||
| 		// Use the config.GenericConfig.EgressSelector lookup to find the dialer to connect to the kubelet | 		// Use the config.GenericConfig.EgressSelector lookup to find the dialer to connect to the kubelet | ||||||
|   | |||||||
| @@ -52,8 +52,8 @@ func startValidatingAdmissionPolicyStatusController(ctx context.Context, control | |||||||
| 		RestMapper:     controllerContext.RESTMapper, | 		RestMapper:     controllerContext.RESTMapper, | ||||||
| 	} | 	} | ||||||
| 	c, err := validatingadmissionpolicystatus.NewController( | 	c, err := validatingadmissionpolicystatus.NewController( | ||||||
| 		controllerContext.InformerFactory.Admissionregistration().V1beta1().ValidatingAdmissionPolicies(), | 		controllerContext.InformerFactory.Admissionregistration().V1().ValidatingAdmissionPolicies(), | ||||||
| 		controllerContext.ClientBuilder.ClientOrDie(names.ValidatingAdmissionPolicyStatusController).AdmissionregistrationV1beta1().ValidatingAdmissionPolicies(), | 		controllerContext.ClientBuilder.ClientOrDie(names.ValidatingAdmissionPolicyStatusController).AdmissionregistrationV1().ValidatingAdmissionPolicies(), | ||||||
| 		typeChecker, | 		typeChecker, | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -151,6 +151,10 @@ func TestDefaulting(t *testing.T) { | |||||||
| 		{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyList"}:         {}, | 		{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyList"}:         {}, | ||||||
| 		{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBinding"}:      {}, | 		{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBinding"}:      {}, | ||||||
| 		{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBindingList"}:  {}, | 		{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBindingList"}:  {}, | ||||||
|  | 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicy"}:                  {}, | ||||||
|  | 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyList"}:              {}, | ||||||
|  | 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyBinding"}:           {}, | ||||||
|  | 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyBindingList"}:       {}, | ||||||
| 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfiguration"}:             {}, | 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfiguration"}:             {}, | ||||||
| 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfigurationList"}:         {}, | 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfigurationList"}:         {}, | ||||||
| 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfiguration"}:               {}, | 		{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfiguration"}:               {}, | ||||||
|   | |||||||
| @@ -93,3 +93,27 @@ func SetDefaults_ServiceReference(obj *admissionregistrationv1.ServiceReference) | |||||||
| 		obj.Port = utilpointer.Int32(443) | 		obj.Port = utilpointer.Int32(443) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // SetDefaults_ValidatingAdmissionPolicySpec sets defaults for ValidatingAdmissionPolicySpec | ||||||
|  | func SetDefaults_ValidatingAdmissionPolicySpec(obj *admissionregistrationv1.ValidatingAdmissionPolicySpec) { | ||||||
|  | 	if obj.FailurePolicy == nil { | ||||||
|  | 		policy := admissionregistrationv1.Fail | ||||||
|  | 		obj.FailurePolicy = &policy | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetDefaults_MatchResources sets defaults for MatchResources | ||||||
|  | func SetDefaults_MatchResources(obj *admissionregistrationv1.MatchResources) { | ||||||
|  | 	if obj.MatchPolicy == nil { | ||||||
|  | 		policy := admissionregistrationv1.Equivalent | ||||||
|  | 		obj.MatchPolicy = &policy | ||||||
|  | 	} | ||||||
|  | 	if obj.NamespaceSelector == nil { | ||||||
|  | 		selector := metav1.LabelSelector{} | ||||||
|  | 		obj.NamespaceSelector = &selector | ||||||
|  | 	} | ||||||
|  | 	if obj.ObjectSelector == nil { | ||||||
|  | 		selector := metav1.LabelSelector{} | ||||||
|  | 		obj.ObjectSelector = &selector | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -132,3 +132,91 @@ func TestDefaultAdmissionWebhook(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestDefaultAdmissionPolicy(t *testing.T) { | ||||||
|  | 	fail := v1.Fail | ||||||
|  | 	equivalent := v1.Equivalent | ||||||
|  | 	allScopes := v1.AllScopes | ||||||
|  |  | ||||||
|  | 	tests := []struct { | ||||||
|  | 		name     string | ||||||
|  | 		original runtime.Object | ||||||
|  | 		expected runtime.Object | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			name: "ValidatingAdmissionPolicy", | ||||||
|  | 			original: &v1.ValidatingAdmissionPolicy{ | ||||||
|  | 				Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
|  | 					MatchConstraints: &v1.MatchResources{}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expected: &v1.ValidatingAdmissionPolicy{ | ||||||
|  | 				Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
|  | 					MatchConstraints: &v1.MatchResources{ | ||||||
|  | 						MatchPolicy:       &equivalent, | ||||||
|  | 						NamespaceSelector: &metav1.LabelSelector{}, | ||||||
|  | 						ObjectSelector:    &metav1.LabelSelector{}, | ||||||
|  | 					}, | ||||||
|  | 					FailurePolicy: &fail, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "ValidatingAdmissionPolicyBinding", | ||||||
|  | 			original: &v1.ValidatingAdmissionPolicyBinding{ | ||||||
|  | 				Spec: v1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
|  | 					MatchResources: &v1.MatchResources{}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expected: &v1.ValidatingAdmissionPolicyBinding{ | ||||||
|  | 				Spec: v1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
|  | 					MatchResources: &v1.MatchResources{ | ||||||
|  | 						MatchPolicy:       &equivalent, | ||||||
|  | 						NamespaceSelector: &metav1.LabelSelector{}, | ||||||
|  | 						ObjectSelector:    &metav1.LabelSelector{}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "scope=*", | ||||||
|  | 			original: &v1.ValidatingAdmissionPolicy{ | ||||||
|  | 				Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
|  | 					MatchConstraints: &v1.MatchResources{ | ||||||
|  | 						ResourceRules: []v1.NamedRuleWithOperations{{}}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expected: &v1.ValidatingAdmissionPolicy{ | ||||||
|  | 				Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
|  | 					MatchConstraints: &v1.MatchResources{ | ||||||
|  | 						MatchPolicy:       &equivalent, | ||||||
|  | 						NamespaceSelector: &metav1.LabelSelector{}, | ||||||
|  | 						ObjectSelector:    &metav1.LabelSelector{}, | ||||||
|  | 						ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
|  | 							{ | ||||||
|  | 								RuleWithOperations: v1.RuleWithOperations{ | ||||||
|  | 									Rule: v1.Rule{ | ||||||
|  | 										Scope: &allScopes, // defaulted | ||||||
|  | 									}, | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 					FailurePolicy: &fail, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, test := range tests { | ||||||
|  | 		t.Run(test.name, func(t *testing.T) { | ||||||
|  | 			original := test.original | ||||||
|  | 			expected := test.expected | ||||||
|  | 			legacyscheme.Scheme.Default(original) | ||||||
|  | 			if !apiequality.Semantic.DeepEqual(original, expected) { | ||||||
|  | 				t.Error(cmp.Diff(expected, original)) | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -21,15 +21,15 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	"k8s.io/api/admissionregistration/v1" | ||||||
| 	kerrors "k8s.io/apimachinery/pkg/api/errors" | 	kerrors "k8s.io/apimachinery/pkg/api/errors" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	utilruntime "k8s.io/apimachinery/pkg/util/runtime" | 	utilruntime "k8s.io/apimachinery/pkg/util/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/util/wait" | 	"k8s.io/apimachinery/pkg/util/wait" | ||||||
| 	validatingadmissionpolicy "k8s.io/apiserver/pkg/admission/plugin/policy/validating" | 	validatingadmissionpolicy "k8s.io/apiserver/pkg/admission/plugin/policy/validating" | ||||||
| 	admissionregistrationv1beta1apply "k8s.io/client-go/applyconfigurations/admissionregistration/v1beta1" | 	admissionregistrationv1apply "k8s.io/client-go/applyconfigurations/admissionregistration/v1" | ||||||
| 	informerv1beta1 "k8s.io/client-go/informers/admissionregistration/v1beta1" | 	informerv1 "k8s.io/client-go/informers/admissionregistration/v1" | ||||||
| 	admissionregistrationv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1" | 	admissionregistrationv1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1" | ||||||
| 	"k8s.io/client-go/tools/cache" | 	"k8s.io/client-go/tools/cache" | ||||||
| 	"k8s.io/client-go/util/workqueue" | 	"k8s.io/client-go/util/workqueue" | ||||||
| ) | ) | ||||||
| @@ -40,10 +40,10 @@ const ControllerName = "validatingadmissionpolicy-status" | |||||||
| // Controller is the ValidatingAdmissionPolicy Status controller that reconciles the Status field of each policy object. | // Controller is the ValidatingAdmissionPolicy Status controller that reconciles the Status field of each policy object. | ||||||
| // This controller runs type checks against referred types for each policy definition. | // This controller runs type checks against referred types for each policy definition. | ||||||
| type Controller struct { | type Controller struct { | ||||||
| 	policyInformer informerv1beta1.ValidatingAdmissionPolicyInformer | 	policyInformer informerv1.ValidatingAdmissionPolicyInformer | ||||||
| 	policyQueue    workqueue.RateLimitingInterface | 	policyQueue    workqueue.RateLimitingInterface | ||||||
| 	policySynced   cache.InformerSynced | 	policySynced   cache.InformerSynced | ||||||
| 	policyClient   admissionregistrationv1beta1.ValidatingAdmissionPolicyInterface | 	policyClient   admissionregistrationv1.ValidatingAdmissionPolicyInterface | ||||||
|  |  | ||||||
| 	// typeChecker checks the policy's expressions for type errors. | 	// typeChecker checks the policy's expressions for type errors. | ||||||
| 	// Type of params is defined in policy.Spec.ParamsKind | 	// Type of params is defined in policy.Spec.ParamsKind | ||||||
| @@ -66,7 +66,7 @@ func (c *Controller) Run(ctx context.Context, workers int) { | |||||||
| 	<-ctx.Done() | 	<-ctx.Done() | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewController(policyInformer informerv1beta1.ValidatingAdmissionPolicyInformer, policyClient admissionregistrationv1beta1.ValidatingAdmissionPolicyInterface, typeChecker *validatingadmissionpolicy.TypeChecker) (*Controller, error) { | func NewController(policyInformer informerv1.ValidatingAdmissionPolicyInformer, policyClient admissionregistrationv1.ValidatingAdmissionPolicyInterface, typeChecker *validatingadmissionpolicy.TypeChecker) (*Controller, error) { | ||||||
| 	c := &Controller{ | 	c := &Controller{ | ||||||
| 		policyInformer: policyInformer, | 		policyInformer: policyInformer, | ||||||
| 		policyQueue:    workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: ControllerName}), | 		policyQueue:    workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: ControllerName}), | ||||||
| @@ -89,7 +89,7 @@ func NewController(policyInformer informerv1beta1.ValidatingAdmissionPolicyInfor | |||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Controller) enqueuePolicy(policy any) { | func (c *Controller) enqueuePolicy(policy any) { | ||||||
| 	if policy, ok := policy.(*v1beta1.ValidatingAdmissionPolicy); ok { | 	if policy, ok := policy.(*v1.ValidatingAdmissionPolicy); ok { | ||||||
| 		// policy objects are cluster-scoped, no point include its namespace. | 		// policy objects are cluster-scoped, no point include its namespace. | ||||||
| 		key := policy.ObjectMeta.Name | 		key := policy.ObjectMeta.Name | ||||||
| 		if key == "" { | 		if key == "" { | ||||||
| @@ -138,7 +138,7 @@ func (c *Controller) processNextWorkItem(ctx context.Context) bool { | |||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Controller) reconcile(ctx context.Context, policy *v1beta1.ValidatingAdmissionPolicy) error { | func (c *Controller) reconcile(ctx context.Context, policy *v1.ValidatingAdmissionPolicy) error { | ||||||
| 	if policy == nil { | 	if policy == nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| @@ -146,16 +146,16 @@ func (c *Controller) reconcile(ctx context.Context, policy *v1beta1.ValidatingAd | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	warnings := c.typeChecker.Check(policy) | 	warnings := c.typeChecker.Check(policy) | ||||||
| 	warningsConfig := make([]*admissionregistrationv1beta1apply.ExpressionWarningApplyConfiguration, 0, len(warnings)) | 	warningsConfig := make([]*admissionregistrationv1apply.ExpressionWarningApplyConfiguration, 0, len(warnings)) | ||||||
| 	for _, warning := range warnings { | 	for _, warning := range warnings { | ||||||
| 		warningsConfig = append(warningsConfig, admissionregistrationv1beta1apply.ExpressionWarning(). | 		warningsConfig = append(warningsConfig, admissionregistrationv1apply.ExpressionWarning(). | ||||||
| 			WithFieldRef(warning.FieldRef). | 			WithFieldRef(warning.FieldRef). | ||||||
| 			WithWarning(warning.Warning)) | 			WithWarning(warning.Warning)) | ||||||
| 	} | 	} | ||||||
| 	applyConfig := admissionregistrationv1beta1apply.ValidatingAdmissionPolicy(policy.Name). | 	applyConfig := admissionregistrationv1apply.ValidatingAdmissionPolicy(policy.Name). | ||||||
| 		WithStatus(admissionregistrationv1beta1apply.ValidatingAdmissionPolicyStatus(). | 		WithStatus(admissionregistrationv1apply.ValidatingAdmissionPolicyStatus(). | ||||||
| 			WithObservedGeneration(policy.Generation). | 			WithObservedGeneration(policy.Generation). | ||||||
| 			WithTypeChecking(admissionregistrationv1beta1apply.TypeChecking(). | 			WithTypeChecking(admissionregistrationv1apply.TypeChecking(). | ||||||
| 				WithExpressionWarnings(warningsConfig...))) | 				WithExpressionWarnings(warningsConfig...))) | ||||||
| 	_, err := c.policyClient.ApplyStatus(ctx, applyConfig, metav1.ApplyOptions{FieldManager: ControllerName, Force: true}) | 	_, err := c.policyClient.ApplyStatus(ctx, applyConfig, metav1.ApplyOptions{FieldManager: ControllerName, Force: true}) | ||||||
| 	return err | 	return err | ||||||
|   | |||||||
| @@ -23,7 +23,6 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1" | 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1" | ||||||
| 	admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" |  | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta/testrestmapper" | 	"k8s.io/apimachinery/pkg/api/meta/testrestmapper" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/util/wait" | 	"k8s.io/apimachinery/pkg/util/wait" | ||||||
| @@ -38,13 +37,13 @@ import ( | |||||||
| func TestTypeChecking(t *testing.T) { | func TestTypeChecking(t *testing.T) { | ||||||
| 	for _, tc := range []struct { | 	for _, tc := range []struct { | ||||||
| 		name           string | 		name           string | ||||||
| 		policy         *admissionregistrationv1beta1.ValidatingAdmissionPolicy | 		policy         *admissionregistrationv1.ValidatingAdmissionPolicy | ||||||
| 		assertFieldRef func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) // warning.fieldRef | 		assertFieldRef func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) // warning.fieldRef | ||||||
| 		assertWarnings func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) // warning.warning | 		assertWarnings func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) // warning.warning | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
| 			name: "deployment with correct expression", | 			name: "deployment with correct expression", | ||||||
| 			policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1beta1.Validation{ | 			policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1.Validation{ | ||||||
| 				{ | 				{ | ||||||
| 					Expression: "object.spec.replicas > 1", | 					Expression: "object.spec.replicas > 1", | ||||||
| 				}, | 				}, | ||||||
| @@ -54,7 +53,7 @@ func TestTypeChecking(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "deployment with type confusion", | 			name: "deployment with type confusion", | ||||||
| 			policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1beta1.Validation{ | 			policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1.Validation{ | ||||||
| 				{ | 				{ | ||||||
| 					Expression: "object.spec.replicas < 100", // this one passes | 					Expression: "object.spec.replicas < 100", // this one passes | ||||||
| 				}, | 				}, | ||||||
| @@ -67,7 +66,7 @@ func TestTypeChecking(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "two expressions different type checking errors", | 			name: "two expressions different type checking errors", | ||||||
| 			policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1beta1.Validation{ | 			policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1.Validation{ | ||||||
| 				{ | 				{ | ||||||
| 					Expression: "object.spec.nonExistingFirst > 1", | 					Expression: "object.spec.nonExistingFirst > 1", | ||||||
| 				}, | 				}, | ||||||
| @@ -83,7 +82,7 @@ func TestTypeChecking(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "one expression, two warnings", | 			name: "one expression, two warnings", | ||||||
| 			policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1beta1.Validation{ | 			policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1.Validation{ | ||||||
| 				{ | 				{ | ||||||
| 					Expression: "object.spec.replicas < 100", // this one passes | 					Expression: "object.spec.replicas < 100", // this one passes | ||||||
| 				}, | 				}, | ||||||
| @@ -107,8 +106,8 @@ func TestTypeChecking(t *testing.T) { | |||||||
| 				RestMapper:     testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme), | 				RestMapper:     testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme), | ||||||
| 			} | 			} | ||||||
| 			controller, err := NewController( | 			controller, err := NewController( | ||||||
| 				informerFactory.Admissionregistration().V1beta1().ValidatingAdmissionPolicies(), | 				informerFactory.Admissionregistration().V1().ValidatingAdmissionPolicies(), | ||||||
| 				client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies(), | 				client.AdmissionregistrationV1().ValidatingAdmissionPolicies(), | ||||||
| 				typeChecker, | 				typeChecker, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| @@ -120,7 +119,7 @@ func TestTypeChecking(t *testing.T) { | |||||||
| 				name := policy.Name | 				name := policy.Name | ||||||
| 				// wait until the typeChecking is set, which means the type checking | 				// wait until the typeChecking is set, which means the type checking | ||||||
| 				// is complete. | 				// is complete. | ||||||
| 				updated, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, name, metav1.GetOptions{}) | 				updated, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, name, metav1.GetOptions{}) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					return false, err | 					return false, err | ||||||
| 				} | 				} | ||||||
| @@ -143,8 +142,8 @@ func TestTypeChecking(t *testing.T) { | |||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func toBe(expected ...string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { | func toBe(expected ...string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { | ||||||
| 	return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { | 	return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { | ||||||
| 		if len(expected) != len(warnings) { | 		if len(expected) != len(warnings) { | ||||||
| 			t.Fatalf("mismatched length, expect %d, got %d", len(expected), len(warnings)) | 			t.Fatalf("mismatched length, expect %d, got %d", len(expected), len(warnings)) | ||||||
| 		} | 		} | ||||||
| @@ -156,8 +155,8 @@ func toBe(expected ...string) func(warnings []admissionregistrationv1beta1.Expre | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func toHaveSubstring(substrings ...string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { | func toHaveSubstring(substrings ...string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { | ||||||
| 	return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { | 	return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { | ||||||
| 		if len(substrings) != len(warnings) { | 		if len(substrings) != len(warnings) { | ||||||
| 			t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings)) | 			t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings)) | ||||||
| 		} | 		} | ||||||
| @@ -169,8 +168,8 @@ func toHaveSubstring(substrings ...string) func(warnings []admissionregistration | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { | func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { | ||||||
| 	return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { | 	return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { | ||||||
| 		if len(substrings) != len(warnings) { | 		if len(substrings) != len(warnings) { | ||||||
| 			t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings)) | 			t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings)) | ||||||
| 		} | 		} | ||||||
| @@ -184,19 +183,19 @@ func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionr | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func toHaveLengthOf(n int) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { | func toHaveLengthOf(n int) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { | ||||||
| 	return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { | 	return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { | ||||||
| 		if n != len(warnings) { | 		if n != len(warnings) { | ||||||
| 			t.Fatalf("mismatched length, expect %d, got %d", n, len(warnings)) | 			t.Fatalf("mismatched length, expect %d, got %d", n, len(warnings)) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func withGVRMatch(groups []string, versions []string, resources []string, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { | func withGVRMatch(groups []string, versions []string, resources []string, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { | ||||||
| 	policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{ | 	policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{ | ||||||
| 		ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ | 		ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{ | ||||||
| 			{ | 			{ | ||||||
| 				RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ | 				RuleWithOperations: admissionregistrationv1.RuleWithOperations{ | ||||||
| 					Operations: []admissionregistrationv1.OperationType{ | 					Operations: []admissionregistrationv1.OperationType{ | ||||||
| 						"*", | 						"*", | ||||||
| 					}, | 					}, | ||||||
| @@ -212,13 +211,13 @@ func withGVRMatch(groups []string, versions []string, resources []string, policy | |||||||
| 	return policy | 	return policy | ||||||
| } | } | ||||||
|  |  | ||||||
| func withValidations(validations []admissionregistrationv1beta1.Validation, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { | func withValidations(validations []admissionregistrationv1.Validation, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { | ||||||
| 	policy.Spec.Validations = validations | 	policy.Spec.Validations = validations | ||||||
| 	return policy | 	return policy | ||||||
| } | } | ||||||
|  |  | ||||||
| func makePolicy(name string) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { | func makePolicy(name string) *admissionregistrationv1.ValidatingAdmissionPolicy { | ||||||
| 	return &admissionregistrationv1beta1.ValidatingAdmissionPolicy{ | 	return &admissionregistrationv1.ValidatingAdmissionPolicy{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{Name: name}, | 		ObjectMeta: metav1.ObjectMeta{Name: name}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -81,6 +81,8 @@ var GVRToStorageVersionHash = map[string]string{ | |||||||
| 	"apps/v1/statefulsets":                                              "H+vl74LkKdo=", | 	"apps/v1/statefulsets":                                              "H+vl74LkKdo=", | ||||||
| 	"admissionregistration.k8s.io/v1/mutatingwebhookconfigurations":     "Sqi0GUgDaX0=", | 	"admissionregistration.k8s.io/v1/mutatingwebhookconfigurations":     "Sqi0GUgDaX0=", | ||||||
| 	"admissionregistration.k8s.io/v1/validatingwebhookconfigurations":   "B0wHjQmsGNk=", | 	"admissionregistration.k8s.io/v1/validatingwebhookconfigurations":   "B0wHjQmsGNk=", | ||||||
|  | 	"admissionregistration.k8s.io/v1/validatingadmissionpolicies":       "P/h9c6yIbaY=", | ||||||
|  | 	"admissionregistration.k8s.io/v1/validatingadmissionpolicybindings": "XYju31JKYek=", | ||||||
| 	"events.k8s.io/v1/events":                                           "r2yiGXH7wu8=", | 	"events.k8s.io/v1/events":                                           "r2yiGXH7wu8=", | ||||||
| 	"flowcontrol.apiserver.k8s.io/v1beta3/flowschemas":                  "GJVAJZSZBIw=", | 	"flowcontrol.apiserver.k8s.io/v1beta3/flowschemas":                  "GJVAJZSZBIw=", | ||||||
| 	"flowcontrol.apiserver.k8s.io/v1beta3/prioritylevelconfigurations":  "Kir5PVfvNeI=", | 	"flowcontrol.apiserver.k8s.io/v1beta3/prioritylevelconfigurations":  "Kir5PVfvNeI=", | ||||||
|   | |||||||
| @@ -1258,7 +1258,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS | |||||||
|  |  | ||||||
| 	genericfeatures.UnauthenticatedHTTP2DOSMitigation: {Default: true, PreRelease: featuregate.Beta}, | 	genericfeatures.UnauthenticatedHTTP2DOSMitigation: {Default: true, PreRelease: featuregate.Beta}, | ||||||
|  |  | ||||||
| 	genericfeatures.ValidatingAdmissionPolicy: {Default: false, PreRelease: featuregate.Beta}, | 	genericfeatures.ValidatingAdmissionPolicy: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32 | ||||||
|  |  | ||||||
| 	genericfeatures.WatchBookmark: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, | 	genericfeatures.WatchBookmark: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,23 +19,17 @@ package admission | |||||||
| import ( | import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"k8s.io/klog/v2" | 	"k8s.io/klog/v2" | ||||||
|  |  | ||||||
| 	"go.opentelemetry.io/otel/trace" | 	"go.opentelemetry.io/otel/trace" | ||||||
|  |  | ||||||
| 	utilwait "k8s.io/apimachinery/pkg/util/wait" |  | ||||||
| 	"k8s.io/apiserver/pkg/admission" | 	"k8s.io/apiserver/pkg/admission" | ||||||
| 	webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer" | 	webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer" | ||||||
| 	genericapiserver "k8s.io/apiserver/pkg/server" |  | ||||||
| 	"k8s.io/apiserver/pkg/server/egressselector" | 	"k8s.io/apiserver/pkg/server/egressselector" | ||||||
| 	"k8s.io/apiserver/pkg/util/webhook" | 	"k8s.io/apiserver/pkg/util/webhook" | ||||||
| 	cacheddiscovery "k8s.io/client-go/discovery/cached/memory" |  | ||||||
| 	externalinformers "k8s.io/client-go/informers" | 	externalinformers "k8s.io/client-go/informers" | ||||||
| 	"k8s.io/client-go/kubernetes" |  | ||||||
| 	"k8s.io/client-go/rest" | 	"k8s.io/client-go/rest" | ||||||
| 	"k8s.io/client-go/restmapper" |  | ||||||
| 	"k8s.io/kubernetes/pkg/kubeapiserver/admission/exclusion" | 	"k8s.io/kubernetes/pkg/kubeapiserver/admission/exclusion" | ||||||
| 	quotainstall "k8s.io/kubernetes/pkg/quota/v1/install" | 	quotainstall "k8s.io/kubernetes/pkg/quota/v1/install" | ||||||
| ) | ) | ||||||
| @@ -48,7 +42,7 @@ type Config struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| // New sets up the plugins and admission start hooks needed for admission | // New sets up the plugins and admission start hooks needed for admission | ||||||
| func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider) ([]admission.PluginInitializer, genericapiserver.PostStartHookFunc, error) { | func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider) ([]admission.PluginInitializer, error) { | ||||||
| 	webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig, tp) | 	webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig, tp) | ||||||
| 	webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver) | 	webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver) | ||||||
|  |  | ||||||
| @@ -60,24 +54,11 @@ func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselec | |||||||
| 			klog.Fatalf("Error reading from cloud configuration file %s: %#v", c.CloudConfigFile, err) | 			klog.Fatalf("Error reading from cloud configuration file %s: %#v", c.CloudConfigFile, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	clientset, err := kubernetes.NewForConfig(c.LoopbackClientConfig) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, nil, err |  | ||||||
| 	} |  | ||||||
| 	discoveryClient := cacheddiscovery.NewMemCacheClient(clientset.Discovery()) |  | ||||||
| 	discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) |  | ||||||
| 	kubePluginInitializer := NewPluginInitializer( | 	kubePluginInitializer := NewPluginInitializer( | ||||||
| 		cloudConfig, | 		cloudConfig, | ||||||
| 		discoveryRESTMapper, |  | ||||||
| 		quotainstall.NewQuotaConfigurationForAdmission(), | 		quotainstall.NewQuotaConfigurationForAdmission(), | ||||||
| 		exclusion.Excluded(), | 		exclusion.Excluded(), | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error { | 	return []admission.PluginInitializer{webhookPluginInitializer, kubePluginInitializer}, nil | ||||||
| 		discoveryRESTMapper.Reset() |  | ||||||
| 		go utilwait.Until(discoveryRESTMapper.Reset, 30*time.Second, context.StopCh) |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return []admission.PluginInitializer{webhookPluginInitializer, kubePluginInitializer}, admissionPostStartHook, nil |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -17,7 +17,6 @@ limitations under the License. | |||||||
| package admission | package admission | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" |  | ||||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
| 	"k8s.io/apiserver/pkg/admission" | 	"k8s.io/apiserver/pkg/admission" | ||||||
| 	"k8s.io/apiserver/pkg/admission/initializer" | 	"k8s.io/apiserver/pkg/admission/initializer" | ||||||
| @@ -34,7 +33,6 @@ type WantsCloudConfig interface { | |||||||
| // PluginInitializer is used for initialization of the Kubernetes specific admission plugins. | // PluginInitializer is used for initialization of the Kubernetes specific admission plugins. | ||||||
| type PluginInitializer struct { | type PluginInitializer struct { | ||||||
| 	cloudConfig                []byte | 	cloudConfig                []byte | ||||||
| 	restMapper                 meta.RESTMapper |  | ||||||
| 	quotaConfiguration         quota.Configuration | 	quotaConfiguration         quota.Configuration | ||||||
| 	excludedAdmissionResources []schema.GroupResource | 	excludedAdmissionResources []schema.GroupResource | ||||||
| } | } | ||||||
| @@ -46,13 +44,11 @@ var _ admission.PluginInitializer = &PluginInitializer{} | |||||||
| // all public, this construction method is pointless boilerplate. | // all public, this construction method is pointless boilerplate. | ||||||
| func NewPluginInitializer( | func NewPluginInitializer( | ||||||
| 	cloudConfig []byte, | 	cloudConfig []byte, | ||||||
| 	restMapper meta.RESTMapper, |  | ||||||
| 	quotaConfiguration quota.Configuration, | 	quotaConfiguration quota.Configuration, | ||||||
| 	excludedAdmissionResources []schema.GroupResource, | 	excludedAdmissionResources []schema.GroupResource, | ||||||
| ) *PluginInitializer { | ) *PluginInitializer { | ||||||
| 	return &PluginInitializer{ | 	return &PluginInitializer{ | ||||||
| 		cloudConfig:                cloudConfig, | 		cloudConfig:                cloudConfig, | ||||||
| 		restMapper:                 restMapper, |  | ||||||
| 		quotaConfiguration:         quotaConfiguration, | 		quotaConfiguration:         quotaConfiguration, | ||||||
| 		excludedAdmissionResources: excludedAdmissionResources, | 		excludedAdmissionResources: excludedAdmissionResources, | ||||||
| 	} | 	} | ||||||
| @@ -65,10 +61,6 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) { | |||||||
| 		wants.SetCloudConfig(i.cloudConfig) | 		wants.SetCloudConfig(i.cloudConfig) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if wants, ok := plugin.(initializer.WantsRESTMapper); ok { |  | ||||||
| 		wants.SetRESTMapper(i.restMapper) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok { | 	if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok { | ||||||
| 		wants.SetQuotaConfiguration(i.quotaConfiguration) | 		wants.SetQuotaConfiguration(i.quotaConfiguration) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" |  | ||||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
| 	"k8s.io/apiserver/pkg/admission" | 	"k8s.io/apiserver/pkg/admission" | ||||||
| 	quota "k8s.io/apiserver/pkg/quota/v1" | 	quota "k8s.io/apiserver/pkg/quota/v1" | ||||||
| @@ -49,7 +48,7 @@ func (p *WantsCloudConfigAdmissionPlugin) SetCloudConfig(cloudConfig []byte) { | |||||||
|  |  | ||||||
| func TestCloudConfigAdmissionPlugin(t *testing.T) { | func TestCloudConfigAdmissionPlugin(t *testing.T) { | ||||||
| 	cloudConfig := []byte("cloud-configuration") | 	cloudConfig := []byte("cloud-configuration") | ||||||
| 	initializer := NewPluginInitializer(cloudConfig, nil, nil, nil) | 	initializer := NewPluginInitializer(cloudConfig, nil, nil) | ||||||
| 	wantsCloudConfigAdmission := &WantsCloudConfigAdmissionPlugin{} | 	wantsCloudConfigAdmission := &WantsCloudConfigAdmissionPlugin{} | ||||||
| 	initializer.Initialize(wantsCloudConfigAdmission) | 	initializer.Initialize(wantsCloudConfigAdmission) | ||||||
|  |  | ||||||
| @@ -58,51 +57,6 @@ func TestCloudConfigAdmissionPlugin(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| type doNothingRESTMapper struct{} |  | ||||||
|  |  | ||||||
| func (doNothingRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { |  | ||||||
| 	return schema.GroupVersionKind{}, nil |  | ||||||
| } |  | ||||||
| func (doNothingRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
| func (doNothingRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) { |  | ||||||
| 	return schema.GroupVersionResource{}, nil |  | ||||||
| } |  | ||||||
| func (doNothingRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
| func (doNothingRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
| func (doNothingRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
| func (doNothingRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { |  | ||||||
| 	return "", nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type WantsRESTMapperAdmissionPlugin struct { |  | ||||||
| 	doNothingAdmission |  | ||||||
| 	doNothingPluginInitialization |  | ||||||
| 	mapper meta.RESTMapper |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *WantsRESTMapperAdmissionPlugin) SetRESTMapper(mapper meta.RESTMapper) { |  | ||||||
| 	p.mapper = mapper |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestRESTMapperAdmissionPlugin(t *testing.T) { |  | ||||||
| 	mapper := doNothingRESTMapper{} |  | ||||||
| 	initializer := NewPluginInitializer(nil, mapper, nil, nil) |  | ||||||
| 	wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{} |  | ||||||
| 	initializer.Initialize(wantsRESTMapperAdmission) |  | ||||||
|  |  | ||||||
| 	if wantsRESTMapperAdmission.mapper == nil { |  | ||||||
| 		t.Errorf("Expected REST mapper to be initialized but found nil") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type doNothingQuotaConfiguration struct{} | type doNothingQuotaConfiguration struct{} | ||||||
|  |  | ||||||
| func (doNothingQuotaConfiguration) IgnoredResources() map[schema.GroupResource]struct{} { return nil } | func (doNothingQuotaConfiguration) IgnoredResources() map[schema.GroupResource]struct{} { return nil } | ||||||
| @@ -121,7 +75,7 @@ func (p *WantsQuotaConfigurationAdmissionPlugin) SetQuotaConfiguration(config qu | |||||||
|  |  | ||||||
| func TestQuotaConfigurationAdmissionPlugin(t *testing.T) { | func TestQuotaConfigurationAdmissionPlugin(t *testing.T) { | ||||||
| 	config := doNothingQuotaConfiguration{} | 	config := doNothingQuotaConfiguration{} | ||||||
| 	initializer := NewPluginInitializer(nil, nil, config, nil) | 	initializer := NewPluginInitializer(nil, config, nil) | ||||||
| 	wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{} | 	wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{} | ||||||
| 	initializer.Initialize(wantsQuotaConfigurationAdmission) | 	initializer.Initialize(wantsQuotaConfigurationAdmission) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -68,6 +68,14 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorag | |||||||
| func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) { | func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) { | ||||||
| 	storage := map[string]rest.Storage{} | 	storage := map[string]rest.Storage{} | ||||||
|  |  | ||||||
|  | 	// use a simple wrapper so that initialization order won't cause a nil getter | ||||||
|  | 	var policyGetter rest.Getter | ||||||
|  |  | ||||||
|  | 	r, err := resolver.NewDiscoveryResourceResolver(p.DiscoveryClient) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return storage, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// validatingwebhookconfigurations | 	// validatingwebhookconfigurations | ||||||
| 	if resource := "validatingwebhookconfigurations"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1.SchemeGroupVersion.WithResource(resource)) { | 	if resource := "validatingwebhookconfigurations"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1.SchemeGroupVersion.WithResource(resource)) { | ||||||
| 		validatingStorage, err := validatingwebhookconfigurationstorage.NewREST(restOptionsGetter) | 		validatingStorage, err := validatingwebhookconfigurationstorage.NewREST(restOptionsGetter) | ||||||
| @@ -86,6 +94,26 @@ func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.API | |||||||
| 		storage[resource] = mutatingStorage | 		storage[resource] = mutatingStorage | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// validatingadmissionpolicies | ||||||
|  | 	if resource := "validatingadmissionpolicies"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1.SchemeGroupVersion.WithResource(resource)) { | ||||||
|  | 		policyStorage, policyStatusStorage, err := validatingadmissionpolicystorage.NewREST(restOptionsGetter, p.Authorizer, r) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return storage, err | ||||||
|  | 		} | ||||||
|  | 		policyGetter = policyStorage | ||||||
|  | 		storage[resource] = policyStorage | ||||||
|  | 		storage[resource+"/status"] = policyStatusStorage | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// validatingadmissionpolicybindings | ||||||
|  | 	if resource := "validatingadmissionpolicybindings"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1.SchemeGroupVersion.WithResource(resource)) { | ||||||
|  | 		policyBindingStorage, err := policybindingstorage.NewREST(restOptionsGetter, p.Authorizer, &policybindingstorage.DefaultPolicyGetter{Getter: policyGetter}, r) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return storage, err | ||||||
|  | 		} | ||||||
|  | 		storage[resource] = policyBindingStorage | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return storage, nil | 	return storage, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -138,6 +138,9 @@ func (v *validatingAdmissionPolicyStrategy) GetResetFields() map[fieldpath.APIVe | |||||||
| 		"admissionregistration.k8s.io/v1beta1": fieldpath.NewSet( | 		"admissionregistration.k8s.io/v1beta1": fieldpath.NewSet( | ||||||
| 			fieldpath.MakePathOrDie("status"), | 			fieldpath.MakePathOrDie("status"), | ||||||
| 		), | 		), | ||||||
|  | 		"admissionregistration.k8s.io/v1": fieldpath.NewSet( | ||||||
|  | 			fieldpath.MakePathOrDie("status"), | ||||||
|  | 		), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return fields | 	return fields | ||||||
| @@ -177,6 +180,10 @@ func (s *validatingAdmissionPolicyStatusStrategy) GetResetFields() map[fieldpath | |||||||
| 			fieldpath.MakePathOrDie("spec"), | 			fieldpath.MakePathOrDie("spec"), | ||||||
| 			fieldpath.MakePathOrDie("metadata"), | 			fieldpath.MakePathOrDie("metadata"), | ||||||
| 		), | 		), | ||||||
|  | 		"admissionregistration.k8s.io/v1": fieldpath.NewSet( | ||||||
|  | 			fieldpath.MakePathOrDie("spec"), | ||||||
|  | 			fieldpath.MakePathOrDie("metadata"), | ||||||
|  | 		), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -115,7 +115,6 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) { | |||||||
| 		whiteList: whiteList, | 		whiteList: whiteList, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	genericPluginInitializer := initializer.New(nil, nil, nil, fakeAuthorizer{}, nil, nil) |  | ||||||
| 	fakeDiscoveryClient := &fakediscovery.FakeDiscovery{Fake: &coretesting.Fake{}} | 	fakeDiscoveryClient := &fakediscovery.FakeDiscovery{Fake: &coretesting.Fake{}} | ||||||
| 	fakeDiscoveryClient.Resources = []*metav1.APIResourceList{ | 	fakeDiscoveryClient.Resources = []*metav1.APIResourceList{ | ||||||
| 		{ | 		{ | ||||||
| @@ -133,13 +132,14 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) { | |||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	restMapperRes, err := restmapper.GetAPIGroupResources(fakeDiscoveryClient) | 	restMapperRes, err := restmapper.GetAPIGroupResources(fakeDiscoveryClient) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("unexpected error while constructing resource list from fake discovery client: %v", err) | 		return nil, fmt.Errorf("unexpected error while constructing resource list from fake discovery client: %v", err) | ||||||
| 	} | 	} | ||||||
| 	restMapper := restmapper.NewDiscoveryRESTMapper(restMapperRes) | 	restMapper := restmapper.NewDiscoveryRESTMapper(restMapperRes) | ||||||
| 	pluginInitializer := kubeadmission.NewPluginInitializer(nil, restMapper, nil, nil) | 	genericPluginInitializer := initializer.New(nil, nil, nil, fakeAuthorizer{}, nil, nil, restMapper) | ||||||
|  |  | ||||||
|  | 	pluginInitializer := kubeadmission.NewPluginInitializer(nil, nil, nil) | ||||||
| 	initializersChain := admission.PluginInitializers{} | 	initializersChain := admission.PluginInitializers{} | ||||||
| 	initializersChain = append(initializersChain, genericPluginInitializer) | 	initializersChain = append(initializersChain, genericPluginInitializer) | ||||||
| 	initializersChain = append(initializersChain, pluginInitializer) | 	initializersChain = append(initializersChain, pluginInitializer) | ||||||
|   | |||||||
| @@ -817,7 +817,7 @@ func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInf | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, f, err | 		return nil, f, err | ||||||
| 	} | 	} | ||||||
| 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) | 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) | ||||||
| 	pluginInitializer.Initialize(handler) | 	pluginInitializer.Initialize(handler) | ||||||
| 	err = admission.ValidateInitialization(handler) | 	err = admission.ValidateInitialization(handler) | ||||||
| 	return handler, f, err | 	return handler, f, err | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ import ( | |||||||
| func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) { | func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) { | ||||||
| 	f := informers.NewSharedInformerFactory(c, 5*time.Minute) | 	f := informers.NewSharedInformerFactory(c, 5*time.Minute) | ||||||
| 	handler := NewProvision() | 	handler := NewProvision() | ||||||
| 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) | 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) | ||||||
| 	pluginInitializer.Initialize(handler) | 	pluginInitializer.Initialize(handler) | ||||||
| 	err := admission.ValidateInitialization(handler) | 	err := admission.ValidateInitialization(handler) | ||||||
| 	return handler, f, err | 	return handler, f, err | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ import ( | |||||||
| func newHandlerForTest(c kubernetes.Interface) (admission.ValidationInterface, informers.SharedInformerFactory, error) { | func newHandlerForTest(c kubernetes.Interface) (admission.ValidationInterface, informers.SharedInformerFactory, error) { | ||||||
| 	f := informers.NewSharedInformerFactory(c, 5*time.Minute) | 	f := informers.NewSharedInformerFactory(c, 5*time.Minute) | ||||||
| 	handler := NewExists() | 	handler := NewExists() | ||||||
| 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) | 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) | ||||||
| 	pluginInitializer.Initialize(handler) | 	pluginInitializer.Initialize(handler) | ||||||
| 	err := admission.ValidateInitialization(handler) | 	err := admission.ValidateInitialization(handler) | ||||||
| 	return handler, f, err | 	return handler, f, err | ||||||
|   | |||||||
| @@ -198,7 +198,7 @@ func TestHandles(t *testing.T) { | |||||||
| func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInformerFactory, error) { | func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInformerFactory, error) { | ||||||
| 	f := informers.NewSharedInformerFactory(c, 5*time.Minute) | 	f := informers.NewSharedInformerFactory(c, 5*time.Minute) | ||||||
| 	handler := NewPodNodeSelector(nil) | 	handler := NewPodNodeSelector(nil) | ||||||
| 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) | 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) | ||||||
| 	pluginInitializer.Initialize(handler) | 	pluginInitializer.Initialize(handler) | ||||||
| 	err := admission.ValidateInitialization(handler) | 	err := admission.ValidateInitialization(handler) | ||||||
| 	return handler, f, err | 	return handler, f, err | ||||||
|   | |||||||
| @@ -355,7 +355,7 @@ func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInforme | |||||||
| 		return nil, nil, err | 		return nil, nil, err | ||||||
| 	} | 	} | ||||||
| 	handler := NewPodTolerationsPlugin(pluginConfig) | 	handler := NewPodTolerationsPlugin(pluginConfig) | ||||||
| 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) | 	pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) | ||||||
| 	pluginInitializer.Initialize(handler) | 	pluginInitializer.Initialize(handler) | ||||||
| 	err = admission.ValidateInitialization(handler) | 	err = admission.ValidateInitialization(handler) | ||||||
| 	return handler, f, err | 	return handler, f, err | ||||||
|   | |||||||
| @@ -114,8 +114,8 @@ func createHandlerWithConfig(kubeClient kubernetes.Interface, informerFactory in | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	initializers := admission.PluginInitializers{ | 	initializers := admission.PluginInitializers{ | ||||||
| 		genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, stopCh), | 		genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, stopCh, nil), | ||||||
| 		kubeapiserveradmission.NewPluginInitializer(nil, nil, quotaConfiguration, nil), | 		kubeapiserveradmission.NewPluginInitializer(nil, quotaConfiguration, nil), | ||||||
| 	} | 	} | ||||||
| 	initializers.Initialize(handler) | 	initializers.Initialize(handler) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -544,5 +544,22 @@ items: | |||||||
|   - kind: ServiceAccount |   - kind: ServiceAccount | ||||||
|     name: ttl-controller |     name: ttl-controller | ||||||
|     namespace: kube-system |     namespace: kube-system | ||||||
|  | - apiVersion: rbac.authorization.k8s.io/v1 | ||||||
|  |   kind: ClusterRoleBinding | ||||||
|  |   metadata: | ||||||
|  |     annotations: | ||||||
|  |       rbac.authorization.kubernetes.io/autoupdate: "true" | ||||||
|  |     creationTimestamp: null | ||||||
|  |     labels: | ||||||
|  |       kubernetes.io/bootstrapping: rbac-defaults | ||||||
|  |     name: system:controller:validatingadmissionpolicy-status-controller | ||||||
|  |   roleRef: | ||||||
|  |     apiGroup: rbac.authorization.k8s.io | ||||||
|  |     kind: ClusterRole | ||||||
|  |     name: system:controller:validatingadmissionpolicy-status-controller | ||||||
|  |   subjects: | ||||||
|  |   - kind: ServiceAccount | ||||||
|  |     name: validatingadmissionpolicy-status-controller | ||||||
|  |     namespace: kube-system | ||||||
| kind: List | kind: List | ||||||
| metadata: {} | metadata: {} | ||||||
|   | |||||||
| @@ -1543,5 +1543,40 @@ items: | |||||||
|     - create |     - create | ||||||
|     - patch |     - patch | ||||||
|     - update |     - update | ||||||
|  | - apiVersion: rbac.authorization.k8s.io/v1 | ||||||
|  |   kind: ClusterRole | ||||||
|  |   metadata: | ||||||
|  |     annotations: | ||||||
|  |       rbac.authorization.kubernetes.io/autoupdate: "true" | ||||||
|  |     creationTimestamp: null | ||||||
|  |     labels: | ||||||
|  |       kubernetes.io/bootstrapping: rbac-defaults | ||||||
|  |     name: system:controller:validatingadmissionpolicy-status-controller | ||||||
|  |   rules: | ||||||
|  |   - apiGroups: | ||||||
|  |     - admissionregistration.k8s.io | ||||||
|  |     resources: | ||||||
|  |     - validatingadmissionpolicies | ||||||
|  |     verbs: | ||||||
|  |     - get | ||||||
|  |     - list | ||||||
|  |     - watch | ||||||
|  |   - apiGroups: | ||||||
|  |     - admissionregistration.k8s.io | ||||||
|  |     resources: | ||||||
|  |     - validatingadmissionpolicies/status | ||||||
|  |     verbs: | ||||||
|  |     - get | ||||||
|  |     - patch | ||||||
|  |     - update | ||||||
|  |   - apiGroups: | ||||||
|  |     - "" | ||||||
|  |     - events.k8s.io | ||||||
|  |     resources: | ||||||
|  |     - events | ||||||
|  |     verbs: | ||||||
|  |     - create | ||||||
|  |     - patch | ||||||
|  |     - update | ||||||
| kind: List | kind: List | ||||||
| metadata: {} | metadata: {} | ||||||
|   | |||||||
| @@ -50,6 +50,10 @@ func addKnownTypes(scheme *runtime.Scheme) error { | |||||||
| 		&ValidatingWebhookConfigurationList{}, | 		&ValidatingWebhookConfigurationList{}, | ||||||
| 		&MutatingWebhookConfiguration{}, | 		&MutatingWebhookConfiguration{}, | ||||||
| 		&MutatingWebhookConfigurationList{}, | 		&MutatingWebhookConfigurationList{}, | ||||||
|  | 		&ValidatingAdmissionPolicy{}, | ||||||
|  | 		&ValidatingAdmissionPolicyList{}, | ||||||
|  | 		&ValidatingAdmissionPolicyBinding{}, | ||||||
|  | 		&ValidatingAdmissionPolicyBindingList{}, | ||||||
| 	) | 	) | ||||||
| 	metav1.AddToGroupVersion(scheme, SchemeGroupVersion) | 	metav1.AddToGroupVersion(scheme, SchemeGroupVersion) | ||||||
| 	return nil | 	return nil | ||||||
|   | |||||||
| @@ -91,6 +91,18 @@ const ( | |||||||
| 	Fail FailurePolicyType = "Fail" | 	Fail FailurePolicyType = "Fail" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // ParameterNotFoundActionType specifies a failure policy that defines how a binding | ||||||
|  | // is evaluated when the param referred by its perNamespaceParamRef is not found. | ||||||
|  | type ParameterNotFoundActionType string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// Allow means all requests will be admitted if no param resources | ||||||
|  | 	// could be found. | ||||||
|  | 	AllowAction ParameterNotFoundActionType = "Allow" | ||||||
|  | 	// Deny means all requests will be denied if no param resources are found. | ||||||
|  | 	DenyAction ParameterNotFoundActionType = "Deny" | ||||||
|  | ) | ||||||
|  |  | ||||||
| // MatchPolicyType specifies the type of match policy. | // MatchPolicyType specifies the type of match policy. | ||||||
| // +enum | // +enum | ||||||
| type MatchPolicyType string | type MatchPolicyType string | ||||||
| @@ -120,6 +132,584 @@ const ( | |||||||
| 	SideEffectClassNoneOnDryRun SideEffectClass = "NoneOnDryRun" | 	SideEffectClassNoneOnDryRun SideEffectClass = "NoneOnDryRun" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||||||
|  | // +genclient | ||||||
|  | // +genclient:nonNamespaced | ||||||
|  | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||||||
|  | // +k8s:prerelease-lifecycle-gen:introduced=1.30 | ||||||
|  | // ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it. | ||||||
|  | type ValidatingAdmissionPolicy struct { | ||||||
|  | 	metav1.TypeMeta `json:",inline"` | ||||||
|  | 	// Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. | ||||||
|  | 	// +optional | ||||||
|  | 	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` | ||||||
|  | 	// Specification of the desired behavior of the ValidatingAdmissionPolicy. | ||||||
|  | 	Spec ValidatingAdmissionPolicySpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` | ||||||
|  | 	// The status of the ValidatingAdmissionPolicy, including warnings that are useful to determine if the policy | ||||||
|  | 	// behaves in the expected way. | ||||||
|  | 	// Populated by the system. | ||||||
|  | 	// Read-only. | ||||||
|  | 	// +optional | ||||||
|  | 	Status ValidatingAdmissionPolicyStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ValidatingAdmissionPolicyStatus represents the status of an admission validation policy. | ||||||
|  | type ValidatingAdmissionPolicyStatus struct { | ||||||
|  | 	// The generation observed by the controller. | ||||||
|  | 	// +optional | ||||||
|  | 	ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"varint,1,opt,name=observedGeneration"` | ||||||
|  | 	// The results of type checking for each expression. | ||||||
|  | 	// Presence of this field indicates the completion of the type checking. | ||||||
|  | 	// +optional | ||||||
|  | 	TypeChecking *TypeChecking `json:"typeChecking,omitempty" protobuf:"bytes,2,opt,name=typeChecking"` | ||||||
|  | 	// The conditions represent the latest available observations of a policy's current state. | ||||||
|  | 	// +optional | ||||||
|  | 	// +listType=map | ||||||
|  | 	// +listMapKey=type | ||||||
|  | 	Conditions []metav1.Condition `json:"conditions,omitempty" protobuf:"bytes,3,rep,name=conditions"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ValidatingAdmissionPolicyConditionType is the condition type of admission validation policy. | ||||||
|  | type ValidatingAdmissionPolicyConditionType string | ||||||
|  |  | ||||||
|  | // TypeChecking contains results of type checking the expressions in the | ||||||
|  | // ValidatingAdmissionPolicy | ||||||
|  | type TypeChecking struct { | ||||||
|  | 	// The type checking warnings for each expression. | ||||||
|  | 	// +optional | ||||||
|  | 	// +listType=atomic | ||||||
|  | 	ExpressionWarnings []ExpressionWarning `json:"expressionWarnings,omitempty" protobuf:"bytes,1,rep,name=expressionWarnings"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ExpressionWarning is a warning information that targets a specific expression. | ||||||
|  | type ExpressionWarning struct { | ||||||
|  | 	// The path to the field that refers the expression. | ||||||
|  | 	// For example, the reference to the expression of the first item of | ||||||
|  | 	// validations is "spec.validations[0].expression" | ||||||
|  | 	FieldRef string `json:"fieldRef" protobuf:"bytes,2,opt,name=fieldRef"` | ||||||
|  | 	// The content of type checking information in a human-readable form. | ||||||
|  | 	// Each line of the warning contains the type that the expression is checked | ||||||
|  | 	// against, followed by the type check error from the compiler. | ||||||
|  | 	Warning string `json:"warning" protobuf:"bytes,3,opt,name=warning"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||||||
|  | // +k8s:prerelease-lifecycle-gen:introduced=1.30 | ||||||
|  | // ValidatingAdmissionPolicyList is a list of ValidatingAdmissionPolicy. | ||||||
|  | type ValidatingAdmissionPolicyList struct { | ||||||
|  | 	metav1.TypeMeta `json:",inline"` | ||||||
|  | 	// Standard list metadata. | ||||||
|  | 	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | ||||||
|  | 	// +optional | ||||||
|  | 	metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` | ||||||
|  | 	// List of ValidatingAdmissionPolicy. | ||||||
|  | 	Items []ValidatingAdmissionPolicy `json:"items,omitempty" protobuf:"bytes,2,rep,name=items"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ValidatingAdmissionPolicySpec is the specification of the desired behavior of the AdmissionPolicy. | ||||||
|  | type ValidatingAdmissionPolicySpec struct { | ||||||
|  | 	// ParamKind specifies the kind of resources used to parameterize this policy. | ||||||
|  | 	// If absent, there are no parameters for this policy and the param CEL variable will not be provided to validation expressions. | ||||||
|  | 	// If ParamKind refers to a non-existent kind, this policy definition is mis-configured and the FailurePolicy is applied. | ||||||
|  | 	// If paramKind is specified but paramRef is unset in ValidatingAdmissionPolicyBinding, the params variable will be null. | ||||||
|  | 	// +optional | ||||||
|  | 	ParamKind *ParamKind `json:"paramKind,omitempty" protobuf:"bytes,1,rep,name=paramKind"` | ||||||
|  |  | ||||||
|  | 	// MatchConstraints specifies what resources this policy is designed to validate. | ||||||
|  | 	// The AdmissionPolicy cares about a request if it matches _all_ Constraints. | ||||||
|  | 	// However, in order to prevent clusters from being put into an unstable state that cannot be recovered from via the API | ||||||
|  | 	// ValidatingAdmissionPolicy cannot match ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding. | ||||||
|  | 	// Required. | ||||||
|  | 	MatchConstraints *MatchResources `json:"matchConstraints,omitempty" protobuf:"bytes,2,rep,name=matchConstraints"` | ||||||
|  |  | ||||||
|  | 	// Validations contain CEL expressions which is used to apply the validation. | ||||||
|  | 	// Validations and AuditAnnotations may not both be empty; a minimum of one Validations or AuditAnnotations is | ||||||
|  | 	// required. | ||||||
|  | 	// +listType=atomic | ||||||
|  | 	// +optional | ||||||
|  | 	Validations []Validation `json:"validations,omitempty" protobuf:"bytes,3,rep,name=validations"` | ||||||
|  |  | ||||||
|  | 	// failurePolicy defines how to handle failures for the admission policy. Failures can | ||||||
|  | 	// occur from CEL expression parse errors, type check errors, runtime errors and invalid | ||||||
|  | 	// or mis-configured policy definitions or bindings. | ||||||
|  | 	// | ||||||
|  | 	// A policy is invalid if spec.paramKind refers to a non-existent Kind. | ||||||
|  | 	// A binding is invalid if spec.paramRef.name refers to a non-existent resource. | ||||||
|  | 	// | ||||||
|  | 	// failurePolicy does not define how validations that evaluate to false are handled. | ||||||
|  | 	// | ||||||
|  | 	// When failurePolicy is set to Fail, ValidatingAdmissionPolicyBinding validationActions | ||||||
|  | 	// define how failures are enforced. | ||||||
|  | 	// | ||||||
|  | 	// Allowed values are Ignore or Fail. Defaults to Fail. | ||||||
|  | 	// +optional | ||||||
|  | 	FailurePolicy *FailurePolicyType `json:"failurePolicy,omitempty" protobuf:"bytes,4,opt,name=failurePolicy,casttype=FailurePolicyType"` | ||||||
|  |  | ||||||
|  | 	// auditAnnotations contains CEL expressions which are used to produce audit | ||||||
|  | 	// annotations for the audit event of the API request. | ||||||
|  | 	// validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is | ||||||
|  | 	// required. | ||||||
|  | 	// +listType=atomic | ||||||
|  | 	// +optional | ||||||
|  | 	AuditAnnotations []AuditAnnotation `json:"auditAnnotations,omitempty" protobuf:"bytes,5,rep,name=auditAnnotations"` | ||||||
|  |  | ||||||
|  | 	// MatchConditions is a list of conditions that must be met for a request to be validated. | ||||||
|  | 	// Match conditions filter requests that have already been matched by the rules, | ||||||
|  | 	// namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. | ||||||
|  | 	// There are a maximum of 64 match conditions allowed. | ||||||
|  | 	// | ||||||
|  | 	// If a parameter object is provided, it can be accessed via the `params` handle in the same | ||||||
|  | 	// manner as validation expressions. | ||||||
|  | 	// | ||||||
|  | 	// The exact matching logic is (in order): | ||||||
|  | 	//   1. If ANY matchCondition evaluates to FALSE, the policy is skipped. | ||||||
|  | 	//   2. If ALL matchConditions evaluate to TRUE, the policy is evaluated. | ||||||
|  | 	//   3. If any matchCondition evaluates to an error (but none are FALSE): | ||||||
|  | 	//      - If failurePolicy=Fail, reject the request | ||||||
|  | 	//      - If failurePolicy=Ignore, the policy is skipped | ||||||
|  | 	// | ||||||
|  | 	// +patchMergeKey=name | ||||||
|  | 	// +patchStrategy=merge | ||||||
|  | 	// +listType=map | ||||||
|  | 	// +listMapKey=name | ||||||
|  | 	// +optional | ||||||
|  | 	MatchConditions []MatchCondition `json:"matchConditions,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,6,rep,name=matchConditions"` | ||||||
|  |  | ||||||
|  | 	// Variables contain definitions of variables that can be used in composition of other expressions. | ||||||
|  | 	// Each variable is defined as a named CEL expression. | ||||||
|  | 	// The variables defined here will be available under `variables` in other expressions of the policy | ||||||
|  | 	// except MatchConditions because MatchConditions are evaluated before the rest of the policy. | ||||||
|  | 	// | ||||||
|  | 	// The expression of a variable can refer to other variables defined earlier in the list but not those after. | ||||||
|  | 	// Thus, Variables must be sorted by the order of first appearance and acyclic. | ||||||
|  | 	// +patchMergeKey=name | ||||||
|  | 	// +patchStrategy=merge | ||||||
|  | 	// +listType=map | ||||||
|  | 	// +listMapKey=name | ||||||
|  | 	// +optional | ||||||
|  | 	Variables []Variable `json:"variables,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,7,rep,name=variables"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParamKind is a tuple of Group Kind and Version. | ||||||
|  | // +structType=atomic | ||||||
|  | type ParamKind struct { | ||||||
|  | 	// APIVersion is the API group version the resources belong to. | ||||||
|  | 	// In format of "group/version". | ||||||
|  | 	// Required. | ||||||
|  | 	APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,1,rep,name=apiVersion"` | ||||||
|  |  | ||||||
|  | 	// Kind is the API kind the resources belong to. | ||||||
|  | 	// Required. | ||||||
|  | 	Kind string `json:"kind,omitempty" protobuf:"bytes,2,rep,name=kind"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Validation specifies the CEL expression which is used to apply the validation. | ||||||
|  | type Validation struct { | ||||||
|  | 	// Expression represents the expression which will be evaluated by CEL. | ||||||
|  | 	// ref: https://github.com/google/cel-spec | ||||||
|  | 	// CEL expressions have access to the contents of the API request/response, organized into CEL variables as well as some other useful variables: | ||||||
|  | 	// | ||||||
|  | 	// - 'object' - The object from the incoming request. The value is null for DELETE requests. | ||||||
|  | 	// - 'oldObject' - The existing object. The value is null for CREATE requests. | ||||||
|  | 	// - 'request' - Attributes of the API request([ref](/pkg/apis/admission/types.go#AdmissionRequest)). | ||||||
|  | 	// - 'params' - Parameter resource referred to by the policy binding being evaluated. Only populated if the policy has a ParamKind. | ||||||
|  | 	// - 'namespaceObject' - The namespace object that the incoming object belongs to. The value is null for cluster-scoped resources. | ||||||
|  | 	// - 'variables' - Map of composited variables, from its name to its lazily evaluated value. | ||||||
|  | 	//   For example, a variable named 'foo' can be accessed as 'variables.foo'. | ||||||
|  | 	// - 'authorizer' - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request. | ||||||
|  | 	//   See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz | ||||||
|  | 	// - 'authorizer.requestResource' - A CEL ResourceCheck constructed from the 'authorizer' and configured with the | ||||||
|  | 	//   request resource. | ||||||
|  | 	// | ||||||
|  | 	// The `apiVersion`, `kind`, `metadata.name` and `metadata.generateName` are always accessible from the root of the | ||||||
|  | 	// object. No other metadata properties are accessible. | ||||||
|  | 	// | ||||||
|  | 	// Only property names of the form `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*` are accessible. | ||||||
|  | 	// Accessible property names are escaped according to the following rules when accessed in the expression: | ||||||
|  | 	// - '__' escapes to '__underscores__' | ||||||
|  | 	// - '.' escapes to '__dot__' | ||||||
|  | 	// - '-' escapes to '__dash__' | ||||||
|  | 	// - '/' escapes to '__slash__' | ||||||
|  | 	// - Property names that exactly match a CEL RESERVED keyword escape to '__{keyword}__'. The keywords are: | ||||||
|  | 	//	  "true", "false", "null", "in", "as", "break", "const", "continue", "else", "for", "function", "if", | ||||||
|  | 	//	  "import", "let", "loop", "package", "namespace", "return". | ||||||
|  | 	// Examples: | ||||||
|  | 	//   - Expression accessing a property named "namespace": {"Expression": "object.__namespace__ > 0"} | ||||||
|  | 	//   - Expression accessing a property named "x-prop": {"Expression": "object.x__dash__prop > 0"} | ||||||
|  | 	//   - Expression accessing a property named "redact__d": {"Expression": "object.redact__underscores__d > 0"} | ||||||
|  | 	// | ||||||
|  | 	// Equality on arrays with list type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1]. | ||||||
|  | 	// Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type: | ||||||
|  | 	//   - 'set': `X + Y` performs a union where the array positions of all elements in `X` are preserved and | ||||||
|  | 	//     non-intersecting elements in `Y` are appended, retaining their partial order. | ||||||
|  | 	//   - 'map': `X + Y` performs a merge where the array positions of all keys in `X` are preserved but the values | ||||||
|  | 	//     are overwritten by values in `Y` when the key sets of `X` and `Y` intersect. Elements in `Y` with | ||||||
|  | 	//     non-intersecting keys are appended, retaining their partial order. | ||||||
|  | 	// Required. | ||||||
|  | 	Expression string `json:"expression" protobuf:"bytes,1,opt,name=Expression"` | ||||||
|  | 	// Message represents the message displayed when validation fails. The message is required if the Expression contains | ||||||
|  | 	// line breaks. The message must not contain line breaks. | ||||||
|  | 	// If unset, the message is "failed rule: {Rule}". | ||||||
|  | 	// e.g. "must be a URL with the host matching spec.host" | ||||||
|  | 	// If the Expression contains line breaks. Message is required. | ||||||
|  | 	// The message must not contain line breaks. | ||||||
|  | 	// If unset, the message is "failed Expression: {Expression}". | ||||||
|  | 	// +optional | ||||||
|  | 	Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"` | ||||||
|  | 	// Reason represents a machine-readable description of why this validation failed. | ||||||
|  | 	// If this is the first validation in the list to fail, this reason, as well as the | ||||||
|  | 	// corresponding HTTP response code, are used in the | ||||||
|  | 	// HTTP response to the client. | ||||||
|  | 	// The currently supported reasons are: "Unauthorized", "Forbidden", "Invalid", "RequestEntityTooLarge". | ||||||
|  | 	// If not set, StatusReasonInvalid is used in the response to the client. | ||||||
|  | 	// +optional | ||||||
|  | 	Reason *metav1.StatusReason `json:"reason,omitempty" protobuf:"bytes,3,opt,name=reason"` | ||||||
|  | 	// messageExpression declares a CEL expression that evaluates to the validation failure message that is returned when this rule fails. | ||||||
|  | 	// Since messageExpression is used as a failure message, it must evaluate to a string. | ||||||
|  | 	// If both message and messageExpression are present on a validation, then messageExpression will be used if validation fails. | ||||||
|  | 	// If messageExpression results in a runtime error, the runtime error is logged, and the validation failure message is produced | ||||||
|  | 	// as if the messageExpression field were unset. If messageExpression evaluates to an empty string, a string with only spaces, or a string | ||||||
|  | 	// that contains line breaks, then the validation failure message will also be produced as if the messageExpression field were unset, and | ||||||
|  | 	// the fact that messageExpression produced an empty string/string with only spaces/string with line breaks will be logged. | ||||||
|  | 	// messageExpression has access to all the same variables as the `expression` except for 'authorizer' and 'authorizer.requestResource'. | ||||||
|  | 	// Example: | ||||||
|  | 	// "object.x must be less than max ("+string(params.max)+")" | ||||||
|  | 	// +optional | ||||||
|  | 	MessageExpression string `json:"messageExpression,omitempty" protobuf:"bytes,4,opt,name=messageExpression"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Variable is the definition of a variable that is used for composition. A variable is defined as a named expression. | ||||||
|  | // +structType=atomic | ||||||
|  | type Variable struct { | ||||||
|  | 	// Name is the name of the variable. The name must be a valid CEL identifier and unique among all variables. | ||||||
|  | 	// The variable can be accessed in other expressions through `variables` | ||||||
|  | 	// For example, if name is "foo", the variable will be available as `variables.foo` | ||||||
|  | 	Name string `json:"name" protobuf:"bytes,1,opt,name=Name"` | ||||||
|  |  | ||||||
|  | 	// Expression is the expression that will be evaluated as the value of the variable. | ||||||
|  | 	// The CEL expression has access to the same identifiers as the CEL expressions in Validation. | ||||||
|  | 	Expression string `json:"expression" protobuf:"bytes,2,opt,name=Expression"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // AuditAnnotation describes how to produce an audit annotation for an API request. | ||||||
|  | type AuditAnnotation struct { | ||||||
|  | 	// key specifies the audit annotation key. The audit annotation keys of | ||||||
|  | 	// a ValidatingAdmissionPolicy must be unique. The key must be a qualified | ||||||
|  | 	// name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length. | ||||||
|  | 	// | ||||||
|  | 	// The key is combined with the resource name of the | ||||||
|  | 	// ValidatingAdmissionPolicy to construct an audit annotation key: | ||||||
|  | 	// "{ValidatingAdmissionPolicy name}/{key}". | ||||||
|  | 	// | ||||||
|  | 	// If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy | ||||||
|  | 	// and the same audit annotation key, the annotation key will be identical. | ||||||
|  | 	// In this case, the first annotation written with the key will be included | ||||||
|  | 	// in the audit event and all subsequent annotations with the same key | ||||||
|  | 	// will be discarded. | ||||||
|  | 	// | ||||||
|  | 	// Required. | ||||||
|  | 	Key string `json:"key" protobuf:"bytes,1,opt,name=key"` | ||||||
|  |  | ||||||
|  | 	// valueExpression represents the expression which is evaluated by CEL to | ||||||
|  | 	// produce an audit annotation value. The expression must evaluate to either | ||||||
|  | 	// a string or null value. If the expression evaluates to a string, the | ||||||
|  | 	// audit annotation is included with the string value. If the expression | ||||||
|  | 	// evaluates to null or empty string the audit annotation will be omitted. | ||||||
|  | 	// The valueExpression may be no longer than 5kb in length. | ||||||
|  | 	// If the result of the valueExpression is more than 10kb in length, it | ||||||
|  | 	// will be truncated to 10kb. | ||||||
|  | 	// | ||||||
|  | 	// If multiple ValidatingAdmissionPolicyBinding resources match an | ||||||
|  | 	// API request, then the valueExpression will be evaluated for | ||||||
|  | 	// each binding. All unique values produced by the valueExpressions | ||||||
|  | 	// will be joined together in a comma-separated list. | ||||||
|  | 	// | ||||||
|  | 	// Required. | ||||||
|  | 	ValueExpression string `json:"valueExpression" protobuf:"bytes,2,opt,name=valueExpression"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // +genclient | ||||||
|  | // +genclient:nonNamespaced | ||||||
|  | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||||||
|  | // +k8s:prerelease-lifecycle-gen:introduced=1.30 | ||||||
|  |  | ||||||
|  | // ValidatingAdmissionPolicyBinding binds the ValidatingAdmissionPolicy with paramerized resources. | ||||||
|  | // ValidatingAdmissionPolicyBinding and parameter CRDs together define how cluster administrators configure policies for clusters. | ||||||
|  | // | ||||||
|  | // For a given admission request, each binding will cause its policy to be | ||||||
|  | // evaluated N times, where N is 1 for policies/bindings that don't use | ||||||
|  | // params, otherwise N is the number of parameters selected by the binding. | ||||||
|  | // | ||||||
|  | // The CEL expressions of a policy must have a computed CEL cost below the maximum | ||||||
|  | // CEL budget. Each evaluation of the policy is given an independent CEL cost budget. | ||||||
|  | // Adding/removing policies, bindings, or params can not affect whether a | ||||||
|  | // given (policy, binding, param) combination is within its own CEL budget. | ||||||
|  | type ValidatingAdmissionPolicyBinding struct { | ||||||
|  | 	metav1.TypeMeta `json:",inline"` | ||||||
|  | 	// Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. | ||||||
|  | 	// +optional | ||||||
|  | 	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` | ||||||
|  | 	// Specification of the desired behavior of the ValidatingAdmissionPolicyBinding. | ||||||
|  | 	Spec ValidatingAdmissionPolicyBindingSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||||||
|  | // +k8s:prerelease-lifecycle-gen:introduced=1.30 | ||||||
|  |  | ||||||
|  | // ValidatingAdmissionPolicyBindingList is a list of ValidatingAdmissionPolicyBinding. | ||||||
|  | type ValidatingAdmissionPolicyBindingList struct { | ||||||
|  | 	metav1.TypeMeta `json:",inline"` | ||||||
|  | 	// Standard list metadata. | ||||||
|  | 	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | ||||||
|  | 	// +optional | ||||||
|  | 	metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` | ||||||
|  | 	// List of PolicyBinding. | ||||||
|  | 	Items []ValidatingAdmissionPolicyBinding `json:"items,omitempty" protobuf:"bytes,2,rep,name=items"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ValidatingAdmissionPolicyBindingSpec is the specification of the ValidatingAdmissionPolicyBinding. | ||||||
|  | type ValidatingAdmissionPolicyBindingSpec struct { | ||||||
|  | 	// PolicyName references a ValidatingAdmissionPolicy name which the ValidatingAdmissionPolicyBinding binds to. | ||||||
|  | 	// If the referenced resource does not exist, this binding is considered invalid and will be ignored | ||||||
|  | 	// Required. | ||||||
|  | 	PolicyName string `json:"policyName,omitempty" protobuf:"bytes,1,rep,name=policyName"` | ||||||
|  |  | ||||||
|  | 	// paramRef specifies the parameter resource used to configure the admission control policy. | ||||||
|  | 	// It should point to a resource of the type specified in ParamKind of the bound ValidatingAdmissionPolicy. | ||||||
|  | 	// If the policy specifies a ParamKind and the resource referred to by ParamRef does not exist, this binding is considered mis-configured and the FailurePolicy of the ValidatingAdmissionPolicy applied. | ||||||
|  | 	// If the policy does not specify a ParamKind then this field is ignored, and the rules are evaluated without a param. | ||||||
|  | 	// +optional | ||||||
|  | 	ParamRef *ParamRef `json:"paramRef,omitempty" protobuf:"bytes,2,rep,name=paramRef"` | ||||||
|  |  | ||||||
|  | 	// MatchResources declares what resources match this binding and will be validated by it. | ||||||
|  | 	// Note that this is intersected with the policy's matchConstraints, so only requests that are matched by the policy can be selected by this. | ||||||
|  | 	// If this is unset, all resources matched by the policy are validated by this binding | ||||||
|  | 	// When resourceRules is unset, it does not constrain resource matching. If a resource is matched by the other fields of this object, it will be validated. | ||||||
|  | 	// Note that this is differs from ValidatingAdmissionPolicy matchConstraints, where resourceRules are required. | ||||||
|  | 	// +optional | ||||||
|  | 	MatchResources *MatchResources `json:"matchResources,omitempty" protobuf:"bytes,3,rep,name=matchResources"` | ||||||
|  |  | ||||||
|  | 	// validationActions declares how Validations of the referenced ValidatingAdmissionPolicy are enforced. | ||||||
|  | 	// If a validation evaluates to false it is always enforced according to these actions. | ||||||
|  | 	// | ||||||
|  | 	// Failures defined by the ValidatingAdmissionPolicy's FailurePolicy are enforced according | ||||||
|  | 	// to these actions only if the FailurePolicy is set to Fail, otherwise the failures are | ||||||
|  | 	// ignored. This includes compilation errors, runtime errors and misconfigurations of the policy. | ||||||
|  | 	// | ||||||
|  | 	// validationActions is declared as a set of action values. Order does | ||||||
|  | 	// not matter. validationActions may not contain duplicates of the same action. | ||||||
|  | 	// | ||||||
|  | 	// The supported actions values are: | ||||||
|  | 	// | ||||||
|  | 	// "Deny" specifies that a validation failure results in a denied request. | ||||||
|  | 	// | ||||||
|  | 	// "Warn" specifies that a validation failure is reported to the request client | ||||||
|  | 	// in HTTP Warning headers, with a warning code of 299. Warnings can be sent | ||||||
|  | 	// both for allowed or denied admission responses. | ||||||
|  | 	// | ||||||
|  | 	// "Audit" specifies that a validation failure is included in the published | ||||||
|  | 	// audit event for the request. The audit event will contain a | ||||||
|  | 	// `validation.policy.admission.k8s.io/validation_failure` audit annotation | ||||||
|  | 	// with a value containing the details of the validation failures, formatted as | ||||||
|  | 	// a JSON list of objects, each with the following fields: | ||||||
|  | 	// - message: The validation failure message string | ||||||
|  | 	// - policy: The resource name of the ValidatingAdmissionPolicy | ||||||
|  | 	// - binding: The resource name of the ValidatingAdmissionPolicyBinding | ||||||
|  | 	// - expressionIndex: The index of the failed validations in the ValidatingAdmissionPolicy | ||||||
|  | 	// - validationActions: The enforcement actions enacted for the validation failure | ||||||
|  | 	// Example audit annotation: | ||||||
|  | 	// `"validation.policy.admission.k8s.io/validation_failure": "[{\"message\": \"Invalid value\", {\"policy\": \"policy.example.com\", {\"binding\": \"policybinding.example.com\", {\"expressionIndex\": \"1\", {\"validationActions\": [\"Audit\"]}]"` | ||||||
|  | 	// | ||||||
|  | 	// Clients should expect to handle additional values by ignoring | ||||||
|  | 	// any values not recognized. | ||||||
|  | 	// | ||||||
|  | 	// "Deny" and "Warn" may not be used together since this combination | ||||||
|  | 	// needlessly duplicates the validation failure both in the | ||||||
|  | 	// API response body and the HTTP warning headers. | ||||||
|  | 	// | ||||||
|  | 	// Required. | ||||||
|  | 	// +listType=set | ||||||
|  | 	ValidationActions []ValidationAction `json:"validationActions,omitempty" protobuf:"bytes,4,rep,name=validationActions"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParamRef describes how to locate the params to be used as input to | ||||||
|  | // expressions of rules applied by a policy binding. | ||||||
|  | // +structType=atomic | ||||||
|  | type ParamRef struct { | ||||||
|  | 	// name is the name of the resource being referenced. | ||||||
|  | 	// | ||||||
|  | 	// One of `name` or `selector` must be set, but `name` and `selector` are | ||||||
|  | 	// mutually exclusive properties. If one is set, the other must be unset. | ||||||
|  | 	// | ||||||
|  | 	// A single parameter used for all admission requests can be configured | ||||||
|  | 	// by setting the `name` field, leaving `selector` blank, and setting namespace | ||||||
|  | 	// if `paramKind` is namespace-scoped. | ||||||
|  | 	// | ||||||
|  | 	Name string `json:"name,omitempty" protobuf:"bytes,1,rep,name=name"` | ||||||
|  |  | ||||||
|  | 	// namespace is the namespace of the referenced resource. Allows limiting | ||||||
|  | 	// the search for params to a specific namespace. Applies to both `name` and | ||||||
|  | 	// `selector` fields. | ||||||
|  | 	// | ||||||
|  | 	// A per-namespace parameter may be used by specifying a namespace-scoped | ||||||
|  | 	// `paramKind` in the policy and leaving this field empty. | ||||||
|  | 	// | ||||||
|  | 	// - If `paramKind` is cluster-scoped, this field MUST be unset. Setting this | ||||||
|  | 	// field results in a configuration error. | ||||||
|  | 	// | ||||||
|  | 	// - If `paramKind` is namespace-scoped, the namespace of the object being | ||||||
|  | 	// evaluated for admission will be used when this field is left unset. Take | ||||||
|  | 	// care that if this is left empty the binding must not match any cluster-scoped | ||||||
|  | 	// resources, which will result in an error. | ||||||
|  | 	// | ||||||
|  | 	// +optional | ||||||
|  | 	Namespace string `json:"namespace,omitempty" protobuf:"bytes,2,rep,name=namespace"` | ||||||
|  |  | ||||||
|  | 	// selector can be used to match multiple param objects based on their labels. | ||||||
|  | 	// Supply selector: {} to match all resources of the ParamKind. | ||||||
|  | 	// | ||||||
|  | 	// If multiple params are found, they are all evaluated with the policy expressions | ||||||
|  | 	// and the results are ANDed together. | ||||||
|  | 	// | ||||||
|  | 	// One of `name` or `selector` must be set, but `name` and `selector` are | ||||||
|  | 	// mutually exclusive properties. If one is set, the other must be unset. | ||||||
|  | 	// | ||||||
|  | 	// +optional | ||||||
|  | 	Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,3,rep,name=selector"` | ||||||
|  |  | ||||||
|  | 	// `parameterNotFoundAction` controls the behavior of the binding when the resource | ||||||
|  | 	// exists, and name or selector is valid, but there are no parameters | ||||||
|  | 	// matched by the binding. If the value is set to `Allow`, then no | ||||||
|  | 	// matched parameters will be treated as successful validation by the binding. | ||||||
|  | 	// If set to `Deny`, then no matched parameters will be subject to the | ||||||
|  | 	// `failurePolicy` of the policy. | ||||||
|  | 	// | ||||||
|  | 	// Allowed values are `Allow` or `Deny` | ||||||
|  | 	// | ||||||
|  | 	// Required | ||||||
|  | 	ParameterNotFoundAction *ParameterNotFoundActionType `json:"parameterNotFoundAction,omitempty" protobuf:"bytes,4,rep,name=parameterNotFoundAction"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MatchResources decides whether to run the admission control policy on an object based | ||||||
|  | // on whether it meets the match criteria. | ||||||
|  | // The exclude rules take precedence over include rules (if a resource matches both, it is excluded) | ||||||
|  | // +structType=atomic | ||||||
|  | type MatchResources struct { | ||||||
|  | 	// NamespaceSelector decides whether to run the admission control policy on an object based | ||||||
|  | 	// on whether the namespace for that object matches the selector. If the | ||||||
|  | 	// object itself is a namespace, the matching is performed on | ||||||
|  | 	// object.metadata.labels. If the object is another cluster scoped resource, | ||||||
|  | 	// it never skips the policy. | ||||||
|  | 	// | ||||||
|  | 	// For example, to run the webhook on any objects whose namespace is not | ||||||
|  | 	// associated with "runlevel" of "0" or "1";  you will set the selector as | ||||||
|  | 	// follows: | ||||||
|  | 	// "namespaceSelector": { | ||||||
|  | 	//   "matchExpressions": [ | ||||||
|  | 	//     { | ||||||
|  | 	//       "key": "runlevel", | ||||||
|  | 	//       "operator": "NotIn", | ||||||
|  | 	//       "values": [ | ||||||
|  | 	//         "0", | ||||||
|  | 	//         "1" | ||||||
|  | 	//       ] | ||||||
|  | 	//     } | ||||||
|  | 	//   ] | ||||||
|  | 	// } | ||||||
|  | 	// | ||||||
|  | 	// If instead you want to only run the policy on any objects whose | ||||||
|  | 	// namespace is associated with the "environment" of "prod" or "staging"; | ||||||
|  | 	// you will set the selector as follows: | ||||||
|  | 	// "namespaceSelector": { | ||||||
|  | 	//   "matchExpressions": [ | ||||||
|  | 	//     { | ||||||
|  | 	//       "key": "environment", | ||||||
|  | 	//       "operator": "In", | ||||||
|  | 	//       "values": [ | ||||||
|  | 	//         "prod", | ||||||
|  | 	//         "staging" | ||||||
|  | 	//       ] | ||||||
|  | 	//     } | ||||||
|  | 	//   ] | ||||||
|  | 	// } | ||||||
|  | 	// | ||||||
|  | 	// See | ||||||
|  | 	// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ | ||||||
|  | 	// for more examples of label selectors. | ||||||
|  | 	// | ||||||
|  | 	// Default to the empty LabelSelector, which matches everything. | ||||||
|  | 	// +optional | ||||||
|  | 	NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty" protobuf:"bytes,1,opt,name=namespaceSelector"` | ||||||
|  | 	// ObjectSelector decides whether to run the validation based on if the | ||||||
|  | 	// object has matching labels. objectSelector is evaluated against both | ||||||
|  | 	// the oldObject and newObject that would be sent to the cel validation, and | ||||||
|  | 	// is considered to match if either object matches the selector. A null | ||||||
|  | 	// object (oldObject in the case of create, or newObject in the case of | ||||||
|  | 	// delete) or an object that cannot have labels (like a | ||||||
|  | 	// DeploymentRollback or a PodProxyOptions object) is not considered to | ||||||
|  | 	// match. | ||||||
|  | 	// Use the object selector only if the webhook is opt-in, because end | ||||||
|  | 	// users may skip the admission webhook by setting the labels. | ||||||
|  | 	// Default to the empty LabelSelector, which matches everything. | ||||||
|  | 	// +optional | ||||||
|  | 	ObjectSelector *metav1.LabelSelector `json:"objectSelector,omitempty" protobuf:"bytes,2,opt,name=objectSelector"` | ||||||
|  | 	// ResourceRules describes what operations on what resources/subresources the ValidatingAdmissionPolicy matches. | ||||||
|  | 	// The policy cares about an operation if it matches _any_ Rule. | ||||||
|  | 	// +listType=atomic | ||||||
|  | 	// +optional | ||||||
|  | 	ResourceRules []NamedRuleWithOperations `json:"resourceRules,omitempty" protobuf:"bytes,3,rep,name=resourceRules"` | ||||||
|  | 	// ExcludeResourceRules describes what operations on what resources/subresources the ValidatingAdmissionPolicy should not care about. | ||||||
|  | 	// The exclude rules take precedence over include rules (if a resource matches both, it is excluded) | ||||||
|  | 	// +listType=atomic | ||||||
|  | 	// +optional | ||||||
|  | 	ExcludeResourceRules []NamedRuleWithOperations `json:"excludeResourceRules,omitempty" protobuf:"bytes,4,rep,name=excludeResourceRules"` | ||||||
|  | 	// matchPolicy defines how the "MatchResources" list is used to match incoming requests. | ||||||
|  | 	// Allowed values are "Exact" or "Equivalent". | ||||||
|  | 	// | ||||||
|  | 	// - Exact: match a request only if it exactly matches a specified rule. | ||||||
|  | 	// For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, | ||||||
|  | 	// but "rules" only included `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]`, | ||||||
|  | 	// a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the ValidatingAdmissionPolicy. | ||||||
|  | 	// | ||||||
|  | 	// - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. | ||||||
|  | 	// For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, | ||||||
|  | 	// and "rules" only included `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]`, | ||||||
|  | 	// a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the ValidatingAdmissionPolicy. | ||||||
|  | 	// | ||||||
|  | 	// Defaults to "Equivalent" | ||||||
|  | 	// +optional | ||||||
|  | 	MatchPolicy *MatchPolicyType `json:"matchPolicy,omitempty" protobuf:"bytes,7,opt,name=matchPolicy,casttype=MatchPolicyType"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ValidationAction specifies a policy enforcement action. | ||||||
|  | // +enum | ||||||
|  | type ValidationAction string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// Deny specifies that a validation failure results in a denied request. | ||||||
|  | 	Deny ValidationAction = "Deny" | ||||||
|  | 	// Warn specifies that a validation failure is reported to the request client | ||||||
|  | 	// in HTTP Warning headers, with a warning code of 299. Warnings can be sent | ||||||
|  | 	// both for allowed or denied admission responses. | ||||||
|  | 	Warn ValidationAction = "Warn" | ||||||
|  | 	// Audit specifies that a validation failure is included in the published | ||||||
|  | 	// audit event for the request. The audit event will contain a | ||||||
|  | 	// `validation.policy.admission.k8s.io/validation_failure` audit annotation | ||||||
|  | 	// with a value containing the details of the validation failure. | ||||||
|  | 	Audit ValidationAction = "Audit" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // NamedRuleWithOperations is a tuple of Operations and Resources with ResourceNames. | ||||||
|  | // +structType=atomic | ||||||
|  | type NamedRuleWithOperations struct { | ||||||
|  | 	// ResourceNames is an optional white list of names that the rule applies to.  An empty set means that everything is allowed. | ||||||
|  | 	// +listType=atomic | ||||||
|  | 	// +optional | ||||||
|  | 	ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,1,rep,name=resourceNames"` | ||||||
|  | 	// RuleWithOperations is a tuple of Operations and Resources. | ||||||
|  | 	RuleWithOperations `json:",inline" protobuf:"bytes,2,opt,name=ruleWithOperations"` | ||||||
|  | } | ||||||
|  |  | ||||||
| // +genclient | // +genclient | ||||||
| // +genclient:nonNamespaced | // +genclient:nonNamespaced | ||||||
| // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||||||
|   | |||||||
| @@ -90,7 +90,7 @@ users: | |||||||
| 		"--kubeconfig", fakeKubeConfig.Name(), | 		"--kubeconfig", fakeKubeConfig.Name(), | ||||||
| 		// disable admission and filters that require talking to kube-apiserver | 		// disable admission and filters that require talking to kube-apiserver | ||||||
| 		"--enable-priority-and-fairness=false", | 		"--enable-priority-and-fairness=false", | ||||||
| 		"--disable-admission-plugins", "NamespaceLifecycle,MutatingAdmissionWebhook,ValidatingAdmissionWebhook"}, | 		"--disable-admission-plugins", "NamespaceLifecycle,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ValidatingAdmissionPolicy"}, | ||||||
| 		flags..., | 		flags..., | ||||||
| 	), nil) | 	), nil) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ limitations under the License. | |||||||
| package initializer | package initializer | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	"k8s.io/apiserver/pkg/admission" | 	"k8s.io/apiserver/pkg/admission" | ||||||
| 	"k8s.io/apiserver/pkg/authorization/authorizer" | 	"k8s.io/apiserver/pkg/authorization/authorizer" | ||||||
| 	"k8s.io/client-go/dynamic" | 	"k8s.io/client-go/dynamic" | ||||||
| @@ -32,6 +33,7 @@ type pluginInitializer struct { | |||||||
| 	authorizer        authorizer.Authorizer | 	authorizer        authorizer.Authorizer | ||||||
| 	featureGates      featuregate.FeatureGate | 	featureGates      featuregate.FeatureGate | ||||||
| 	stopCh            <-chan struct{} | 	stopCh            <-chan struct{} | ||||||
|  | 	restMapper        meta.RESTMapper | ||||||
| } | } | ||||||
|  |  | ||||||
| // New creates an instance of admission plugins initializer. | // New creates an instance of admission plugins initializer. | ||||||
| @@ -44,6 +46,7 @@ func New( | |||||||
| 	authz authorizer.Authorizer, | 	authz authorizer.Authorizer, | ||||||
| 	featureGates featuregate.FeatureGate, | 	featureGates featuregate.FeatureGate, | ||||||
| 	stopCh <-chan struct{}, | 	stopCh <-chan struct{}, | ||||||
|  | 	restMapper meta.RESTMapper, | ||||||
| ) pluginInitializer { | ) pluginInitializer { | ||||||
| 	return pluginInitializer{ | 	return pluginInitializer{ | ||||||
| 		externalClient:    extClientset, | 		externalClient:    extClientset, | ||||||
| @@ -52,6 +55,7 @@ func New( | |||||||
| 		authorizer:        authz, | 		authorizer:        authz, | ||||||
| 		featureGates:      featureGates, | 		featureGates:      featureGates, | ||||||
| 		stopCh:            stopCh, | 		stopCh:            stopCh, | ||||||
|  | 		restMapper:        restMapper, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -83,6 +87,9 @@ func (i pluginInitializer) Initialize(plugin admission.Interface) { | |||||||
| 	if wants, ok := plugin.(WantsAuthorizer); ok { | 	if wants, ok := plugin.(WantsAuthorizer); ok { | ||||||
| 		wants.SetAuthorizer(i.authorizer) | 		wants.SetAuthorizer(i.authorizer) | ||||||
| 	} | 	} | ||||||
|  | 	if wants, ok := plugin.(WantsRESTMapper); ok { | ||||||
|  | 		wants.SetRESTMapper(i.restMapper) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| var _ admission.PluginInitializer = pluginInitializer{} | var _ admission.PluginInitializer = pluginInitializer{} | ||||||
|   | |||||||
| @@ -21,6 +21,8 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
| 	"k8s.io/apiserver/pkg/admission" | 	"k8s.io/apiserver/pkg/admission" | ||||||
| 	"k8s.io/apiserver/pkg/admission/initializer" | 	"k8s.io/apiserver/pkg/admission/initializer" | ||||||
| 	"k8s.io/apiserver/pkg/authorization/authorizer" | 	"k8s.io/apiserver/pkg/authorization/authorizer" | ||||||
| @@ -32,7 +34,7 @@ import ( | |||||||
| // TestWantsAuthorizer ensures that the authorizer is injected | // TestWantsAuthorizer ensures that the authorizer is injected | ||||||
| // when the WantsAuthorizer interface is implemented by a plugin. | // when the WantsAuthorizer interface is implemented by a plugin. | ||||||
| func TestWantsAuthorizer(t *testing.T) { | func TestWantsAuthorizer(t *testing.T) { | ||||||
| 	target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil) | 	target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, nil) | ||||||
| 	wantAuthorizerAdmission := &WantAuthorizerAdmission{} | 	wantAuthorizerAdmission := &WantAuthorizerAdmission{} | ||||||
| 	target.Initialize(wantAuthorizerAdmission) | 	target.Initialize(wantAuthorizerAdmission) | ||||||
| 	if wantAuthorizerAdmission.auth == nil { | 	if wantAuthorizerAdmission.auth == nil { | ||||||
| @@ -44,7 +46,7 @@ func TestWantsAuthorizer(t *testing.T) { | |||||||
| // when the WantsExternalKubeClientSet interface is implemented by a plugin. | // when the WantsExternalKubeClientSet interface is implemented by a plugin. | ||||||
| func TestWantsExternalKubeClientSet(t *testing.T) { | func TestWantsExternalKubeClientSet(t *testing.T) { | ||||||
| 	cs := &fake.Clientset{} | 	cs := &fake.Clientset{} | ||||||
| 	target := initializer.New(cs, nil, nil, &TestAuthorizer{}, nil, nil) | 	target := initializer.New(cs, nil, nil, &TestAuthorizer{}, nil, nil, nil) | ||||||
| 	wantExternalKubeClientSet := &WantExternalKubeClientSet{} | 	wantExternalKubeClientSet := &WantExternalKubeClientSet{} | ||||||
| 	target.Initialize(wantExternalKubeClientSet) | 	target.Initialize(wantExternalKubeClientSet) | ||||||
| 	if wantExternalKubeClientSet.cs != cs { | 	if wantExternalKubeClientSet.cs != cs { | ||||||
| @@ -57,7 +59,7 @@ func TestWantsExternalKubeClientSet(t *testing.T) { | |||||||
| func TestWantsExternalKubeInformerFactory(t *testing.T) { | func TestWantsExternalKubeInformerFactory(t *testing.T) { | ||||||
| 	cs := &fake.Clientset{} | 	cs := &fake.Clientset{} | ||||||
| 	sf := informers.NewSharedInformerFactory(cs, time.Duration(1)*time.Second) | 	sf := informers.NewSharedInformerFactory(cs, time.Duration(1)*time.Second) | ||||||
| 	target := initializer.New(cs, nil, sf, &TestAuthorizer{}, nil, nil) | 	target := initializer.New(cs, nil, sf, &TestAuthorizer{}, nil, nil, nil) | ||||||
| 	wantExternalKubeInformerFactory := &WantExternalKubeInformerFactory{} | 	wantExternalKubeInformerFactory := &WantExternalKubeInformerFactory{} | ||||||
| 	target.Initialize(wantExternalKubeInformerFactory) | 	target.Initialize(wantExternalKubeInformerFactory) | ||||||
| 	if wantExternalKubeInformerFactory.sf != sf { | 	if wantExternalKubeInformerFactory.sf != sf { | ||||||
| @@ -69,7 +71,7 @@ func TestWantsExternalKubeInformerFactory(t *testing.T) { | |||||||
| // when the WantsShutdownSignal interface is implemented by a plugin. | // when the WantsShutdownSignal interface is implemented by a plugin. | ||||||
| func TestWantsShutdownNotification(t *testing.T) { | func TestWantsShutdownNotification(t *testing.T) { | ||||||
| 	stopCh := make(chan struct{}) | 	stopCh := make(chan struct{}) | ||||||
| 	target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, stopCh) | 	target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, stopCh, nil) | ||||||
| 	wantDrainedNotification := &WantDrainedNotification{} | 	wantDrainedNotification := &WantDrainedNotification{} | ||||||
| 	target.Initialize(wantDrainedNotification) | 	target.Initialize(wantDrainedNotification) | ||||||
| 	if wantDrainedNotification.stopCh == nil { | 	if wantDrainedNotification.stopCh == nil { | ||||||
| @@ -149,3 +151,59 @@ type TestAuthorizer struct{} | |||||||
| func (t *TestAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { | func (t *TestAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { | ||||||
| 	return authorizer.DecisionNoOpinion, "", nil | 	return authorizer.DecisionNoOpinion, "", nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestRESTMapperAdmissionPlugin(t *testing.T) { | ||||||
|  | 	initializer := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, &doNothingRESTMapper{}) | ||||||
|  | 	wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{} | ||||||
|  | 	initializer.Initialize(wantsRESTMapperAdmission) | ||||||
|  |  | ||||||
|  | 	if wantsRESTMapperAdmission.mapper == nil { | ||||||
|  | 		t.Errorf("Expected REST mapper to be initialized but found nil") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type WantsRESTMapperAdmissionPlugin struct { | ||||||
|  | 	doNothingAdmission | ||||||
|  | 	doNothingPluginInitialization | ||||||
|  | 	mapper meta.RESTMapper | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *WantsRESTMapperAdmissionPlugin) SetRESTMapper(mapper meta.RESTMapper) { | ||||||
|  | 	p.mapper = mapper | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type doNothingRESTMapper struct{} | ||||||
|  |  | ||||||
|  | func (doNothingRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { | ||||||
|  | 	return schema.GroupVersionKind{}, nil | ||||||
|  | } | ||||||
|  | func (doNothingRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
|  | func (doNothingRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) { | ||||||
|  | 	return schema.GroupVersionResource{}, nil | ||||||
|  | } | ||||||
|  | func (doNothingRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
|  | func (doNothingRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
|  | func (doNothingRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
|  | func (doNothingRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { | ||||||
|  | 	return "", nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type doNothingAdmission struct{} | ||||||
|  |  | ||||||
|  | func (doNothingAdmission) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | func (doNothingAdmission) Handles(o admission.Operation) bool { return false } | ||||||
|  | func (doNothingAdmission) Validate() error                    { return nil } | ||||||
|  |  | ||||||
|  | type doNothingPluginInitialization struct{} | ||||||
|  |  | ||||||
|  | func (doNothingPluginInitialization) ValidateInitialization() error { return nil } | ||||||
|   | |||||||
| @@ -53,7 +53,7 @@ func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) ( | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, f, err | 		return nil, f, err | ||||||
| 	} | 	} | ||||||
| 	pluginInitializer := kubeadmission.New(c, nil, f, nil, nil, nil) | 	pluginInitializer := kubeadmission.New(c, nil, f, nil, nil, nil, nil) | ||||||
| 	pluginInitializer.Initialize(handler) | 	pluginInitializer.Initialize(handler) | ||||||
| 	err = admission.ValidateInitialization(handler) | 	err = admission.ValidateInitialization(handler) | ||||||
| 	return handler, f, err | 	return handler, f, err | ||||||
|   | |||||||
| @@ -17,15 +17,15 @@ limitations under the License. | |||||||
| package generic | package generic | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	"k8s.io/api/admissionregistration/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type PolicyAccessor interface { | type PolicyAccessor interface { | ||||||
| 	GetName() string | 	GetName() string | ||||||
| 	GetNamespace() string | 	GetNamespace() string | ||||||
| 	GetParamKind() *v1beta1.ParamKind | 	GetParamKind() *v1.ParamKind | ||||||
| 	GetMatchConstraints() *v1beta1.MatchResources | 	GetMatchConstraints() *v1.MatchResources | ||||||
| } | } | ||||||
|  |  | ||||||
| type BindingAccessor interface { | type BindingAccessor interface { | ||||||
| @@ -36,7 +36,7 @@ type BindingAccessor interface { | |||||||
| 	// which is cluster-scoped, so namespace is usually left blank. | 	// which is cluster-scoped, so namespace is usually left blank. | ||||||
| 	// But we leave the door open to add a namespaced vesion in the future | 	// But we leave the door open to add a namespaced vesion in the future | ||||||
| 	GetPolicyName() types.NamespacedName | 	GetPolicyName() types.NamespacedName | ||||||
| 	GetParamRef() *v1beta1.ParamRef | 	GetParamRef() *v1.ParamRef | ||||||
|  |  | ||||||
| 	GetMatchResources() *v1beta1.MatchResources | 	GetMatchResources() *v1.MatchResources | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	"k8s.io/api/admissionregistration/v1" | ||||||
| 	apierrors "k8s.io/apimachinery/pkg/api/errors" | 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| @@ -217,10 +217,10 @@ func (d *policyDispatcher[P, B, E]) Dispatch(ctx context.Context, a admission.At | |||||||
| // configuration. If the policy-binding has no param configuration, it | // configuration. If the policy-binding has no param configuration, it | ||||||
| // returns a single-element list with a nil param. | // returns a single-element list with a nil param. | ||||||
| func CollectParams( | func CollectParams( | ||||||
| 	paramKind *v1beta1.ParamKind, | 	paramKind *v1.ParamKind, | ||||||
| 	paramInformer informers.GenericInformer, | 	paramInformer informers.GenericInformer, | ||||||
| 	paramScope meta.RESTScope, | 	paramScope meta.RESTScope, | ||||||
| 	paramRef *v1beta1.ParamRef, | 	paramRef *v1.ParamRef, | ||||||
| 	namespace string, | 	namespace string, | ||||||
| ) ([]runtime.Object, error) { | ) ([]runtime.Object, error) { | ||||||
| 	// If definition has paramKind, paramRef is required in binding. | 	// If definition has paramKind, paramRef is required in binding. | ||||||
| @@ -326,7 +326,7 @@ func CollectParams( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Apply fail action for params not found case | 	// Apply fail action for params not found case | ||||||
| 	if len(params) == 0 && paramRef.ParameterNotFoundAction != nil && *paramRef.ParameterNotFoundAction == v1beta1.DenyAction { | 	if len(params) == 0 && paramRef.ParameterNotFoundAction != nil && *paramRef.ParameterNotFoundAction == v1.DenyAction { | ||||||
| 		return nil, errors.New("no params found for policy binding with `Deny` parameterNotFoundAction") | 		return nil, errors.New("no params found for policy binding with `Deny` parameterNotFoundAction") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ package generic | |||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  |  | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1" | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/labels" | 	"k8s.io/apimachinery/pkg/labels" | ||||||
| @@ -89,7 +89,7 @@ func (c *matcher) GetNamespace(name string) (*corev1.Namespace, error) { | |||||||
| var _ matching.MatchCriteria = &matchCriteria{} | var _ matching.MatchCriteria = &matchCriteria{} | ||||||
|  |  | ||||||
| type matchCriteria struct { | type matchCriteria struct { | ||||||
| 	constraints *v1beta1.MatchResources | 	constraints *admissionregistrationv1.MatchResources | ||||||
| } | } | ||||||
|  |  | ||||||
| // GetParsedNamespaceSelector returns the converted LabelSelector which implements labels.Selector | // GetParsedNamespaceSelector returns the converted LabelSelector which implements labels.Selector | ||||||
| @@ -103,6 +103,6 @@ func (m *matchCriteria) GetParsedObjectSelector() (labels.Selector, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| // GetMatchResources returns the matchConstraints | // GetMatchResources returns the matchConstraints | ||||||
| func (m *matchCriteria) GetMatchResources() v1beta1.MatchResources { | func (m *matchCriteria) GetMatchResources() admissionregistrationv1.MatchResources { | ||||||
| 	return *m.constraints | 	return *m.constraints | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/stretchr/testify/require" | 	"github.com/stretchr/testify/require" | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	"k8s.io/api/admissionregistration/v1" | ||||||
| 	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" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| @@ -110,7 +110,7 @@ func TestPolicySourceHasSyncedInitialList(t *testing.T) { | |||||||
| 			ObjectMeta: metav1.ObjectMeta{ | 			ObjectMeta: metav1.ObjectMeta{ | ||||||
| 				Name: "policy2", | 				Name: "policy2", | ||||||
| 			}, | 			}, | ||||||
| 			ParamKind: &v1beta1.ParamKind{ | 			ParamKind: &v1.ParamKind{ | ||||||
| 				APIVersion: "policy.example.com/v1", | 				APIVersion: "policy.example.com/v1", | ||||||
| 				Kind:       "FakeParam", | 				Kind:       "FakeParam", | ||||||
| 			}, | 			}, | ||||||
| @@ -177,7 +177,7 @@ type FakePolicy struct { | |||||||
| 	metav1.TypeMeta | 	metav1.TypeMeta | ||||||
| 	metav1.ObjectMeta | 	metav1.ObjectMeta | ||||||
|  |  | ||||||
| 	ParamKind *v1beta1.ParamKind | 	ParamKind *v1.ParamKind | ||||||
| } | } | ||||||
|  |  | ||||||
| var _ generic.PolicyAccessor = &FakePolicy{} | var _ generic.PolicyAccessor = &FakePolicy{} | ||||||
| @@ -199,11 +199,11 @@ func (fp *FakePolicy) GetNamespace() string { | |||||||
| 	return fp.Namespace | 	return fp.Namespace | ||||||
| } | } | ||||||
|  |  | ||||||
| func (fp *FakePolicy) GetParamKind() *v1beta1.ParamKind { | func (fp *FakePolicy) GetParamKind() *v1.ParamKind { | ||||||
| 	return fp.ParamKind | 	return fp.ParamKind | ||||||
| } | } | ||||||
|  |  | ||||||
| func (fb *FakePolicy) GetMatchConstraints() *v1beta1.MatchResources { | func (fb *FakePolicy) GetMatchConstraints() *v1.MatchResources { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -221,11 +221,11 @@ func (fb *FakeBinding) GetPolicyName() types.NamespacedName { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (fb *FakeBinding) GetMatchResources() *v1beta1.MatchResources { | func (fb *FakeBinding) GetMatchResources() *v1.MatchResources { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (fb *FakeBinding) GetParamRef() *v1beta1.ParamRef { | func (fb *FakeBinding) GetParamRef() *v1.ParamRef { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -216,6 +216,7 @@ func NewPolicyTestContext[P, B runtime.Object, E Evaluator]( | |||||||
| 		fakeAuthorizer{}, | 		fakeAuthorizer{}, | ||||||
| 		featureGate, | 		featureGate, | ||||||
| 		testContext.Done(), | 		testContext.Done(), | ||||||
|  | 		fakeRestMapper, | ||||||
| 	) | 	) | ||||||
| 	genericInitializer.Initialize(plugin) | 	genericInitializer.Initialize(plugin) | ||||||
| 	plugin.SetRESTMapper(fakeRestMapper) | 	plugin.SetRESTMapper(fakeRestMapper) | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
|  |  | ||||||
| 	v1 "k8s.io/api/admissionregistration/v1" | 	v1 "k8s.io/api/admissionregistration/v1" | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" |  | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
| 	"k8s.io/apiserver/pkg/admission" | 	"k8s.io/apiserver/pkg/admission" | ||||||
| @@ -36,7 +35,7 @@ type MatchCriteria interface { | |||||||
| 	namespace.NamespaceSelectorProvider | 	namespace.NamespaceSelectorProvider | ||||||
| 	object.ObjectSelectorProvider | 	object.ObjectSelectorProvider | ||||||
|  |  | ||||||
| 	GetMatchResources() v1beta1.MatchResources | 	GetMatchResources() v1.MatchResources | ||||||
| } | } | ||||||
|  |  | ||||||
| // Matcher decides if a request matches against matchCriteria | // Matcher decides if a request matches against matchCriteria | ||||||
| @@ -121,7 +120,7 @@ func (m *Matcher) Matches(attr admission.Attributes, o admission.ObjectInterface | |||||||
| 	return true, matchResource, matchKind, nil | 	return true, matchResource, matchKind, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPolicy *v1beta1.MatchPolicyType, attr admission.Attributes, o admission.ObjectInterfaces) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error) { | func matchesResourceRules(namedRules []v1.NamedRuleWithOperations, matchPolicy *v1.MatchPolicyType, attr admission.Attributes, o admission.ObjectInterfaces) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error) { | ||||||
| 	matchKind := attr.GetKind() | 	matchKind := attr.GetKind() | ||||||
| 	matchResource := attr.GetResource() | 	matchResource := attr.GetResource() | ||||||
|  |  | ||||||
| @@ -150,7 +149,7 @@ func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPol | |||||||
|  |  | ||||||
| 	// if match policy is undefined or exact, don't perform fuzzy matching | 	// if match policy is undefined or exact, don't perform fuzzy matching | ||||||
| 	// note that defaulting to fuzzy matching is set by the API | 	// note that defaulting to fuzzy matching is set by the API | ||||||
| 	if matchPolicy == nil || *matchPolicy == v1beta1.Exact { | 	if matchPolicy == nil || *matchPolicy == v1.Exact { | ||||||
| 		return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, nil | 		return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,7 +22,6 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	v1 "k8s.io/api/admissionregistration/v1" | 	v1 "k8s.io/api/admissionregistration/v1" | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" |  | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/errors" | 	"k8s.io/apimachinery/pkg/api/errors" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| @@ -38,10 +37,10 @@ import ( | |||||||
| var _ MatchCriteria = &fakeCriteria{} | var _ MatchCriteria = &fakeCriteria{} | ||||||
|  |  | ||||||
| type fakeCriteria struct { | type fakeCriteria struct { | ||||||
| 	matchResources v1beta1.MatchResources | 	matchResources v1.MatchResources | ||||||
| } | } | ||||||
|  |  | ||||||
| func (fc *fakeCriteria) GetMatchResources() v1beta1.MatchResources { | func (fc *fakeCriteria) GetMatchResources() v1.MatchResources { | ||||||
| 	return fc.matchResources | 	return fc.matchResources | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -65,8 +64,8 @@ func TestMatcher(t *testing.T) { | |||||||
| 	a := &Matcher{namespaceMatcher: &namespace.Matcher{}, objectMatcher: &object.Matcher{}} | 	a := &Matcher{namespaceMatcher: &namespace.Matcher{}, objectMatcher: &object.Matcher{}} | ||||||
|  |  | ||||||
| 	allScopes := v1.AllScopes | 	allScopes := v1.AllScopes | ||||||
| 	exactMatch := v1beta1.Exact | 	exactMatch := v1.Exact | ||||||
| 	equivalentMatch := v1beta1.Equivalent | 	equivalentMatch := v1.Equivalent | ||||||
|  |  | ||||||
| 	mapper := runtime.NewEquivalentResourceRegistryWithIdentity(func(resource schema.GroupResource) string { | 	mapper := runtime.NewEquivalentResourceRegistryWithIdentity(func(resource schema.GroupResource) string { | ||||||
| 		if resource.Resource == "deployments" { | 		if resource.Resource == "deployments" { | ||||||
| @@ -95,7 +94,7 @@ func TestMatcher(t *testing.T) { | |||||||
| 	testcases := []struct { | 	testcases := []struct { | ||||||
| 		name string | 		name string | ||||||
|  |  | ||||||
| 		criteria *v1beta1.MatchResources | 		criteria *v1.MatchResources | ||||||
| 		attrs    admission.Attributes | 		attrs    admission.Attributes | ||||||
|  |  | ||||||
| 		expectMatches       bool | 		expectMatches       bool | ||||||
| @@ -105,17 +104,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
| 			name:          "no rules (just write)", | 			name:          "no rules (just write)", | ||||||
| 			criteria:      &v1beta1.MatchResources{NamespaceSelector: &metav1.LabelSelector{}, ResourceRules: []v1beta1.NamedRuleWithOperations{}}, | 			criteria:      &v1.MatchResources{NamespaceSelector: &metav1.LabelSelector{}, ResourceRules: []v1.NamedRuleWithOperations{}}, | ||||||
| 			attrs:         admission.NewAttributesRecord(nil, nil, gvk("apps", "v1", "Deployment"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil), | 			attrs:         admission.NewAttributesRecord(nil, nil, gvk("apps", "v1", "Deployment"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil), | ||||||
| 			expectMatches: false, | 			expectMatches: false, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "wildcard rule, match as requested", | 			name: "wildcard rule, match as requested", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -126,21 +125,21 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, prefer exact match", | 			name: "specific rules, prefer exact match", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -151,16 +150,16 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, match miss", | 			name: "specific rules, match miss", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -170,17 +169,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, exact match miss", | 			name: "specific rules, exact match miss", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				MatchPolicy:       &exactMatch, | 				MatchPolicy:       &exactMatch, | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -190,17 +189,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, equivalent match, prefer extensions", | 			name: "specific rules, equivalent match, prefer extensions", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				MatchPolicy:       &equivalentMatch, | 				MatchPolicy:       &equivalentMatch, | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -212,17 +211,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, equivalent match, prefer apps", | 			name: "specific rules, equivalent match, prefer apps", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				MatchPolicy:       &equivalentMatch, | 				MatchPolicy:       &equivalentMatch, | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -235,21 +234,21 @@ func TestMatcher(t *testing.T) { | |||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, subresource prefer exact match", | 			name: "specific rules, subresource prefer exact match", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -260,16 +259,16 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, subresource match miss", | 			name: "specific rules, subresource match miss", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -279,17 +278,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, subresource exact match miss", | 			name: "specific rules, subresource exact match miss", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				MatchPolicy:       &exactMatch, | 				MatchPolicy:       &exactMatch, | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -299,17 +298,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, subresource equivalent match, prefer extensions", | 			name: "specific rules, subresource equivalent match, prefer extensions", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				MatchPolicy:       &equivalentMatch, | 				MatchPolicy:       &equivalentMatch, | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -321,17 +320,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, subresource equivalent match, prefer apps", | 			name: "specific rules, subresource equivalent match, prefer apps", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				MatchPolicy:       &equivalentMatch, | 				MatchPolicy:       &equivalentMatch, | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}, { | 				}, { | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -343,12 +342,12 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, prefer exact match and name match", | 			name: "specific rules, prefer exact match and name match", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					ResourceNames: []string{"name"}, | 					ResourceNames: []string{"name"}, | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -359,12 +358,12 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, prefer exact match and name match miss", | 			name: "specific rules, prefer exact match and name match miss", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					ResourceNames: []string{"wrong-name"}, | 					ResourceNames: []string{"wrong-name"}, | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -374,13 +373,13 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, subresource equivalent match, prefer extensions and name match", | 			name: "specific rules, subresource equivalent match, prefer extensions and name match", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				MatchPolicy:       &equivalentMatch, | 				MatchPolicy:       &equivalentMatch, | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					ResourceNames: []string{"name"}, | 					ResourceNames: []string{"name"}, | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -392,13 +391,13 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific rules, subresource equivalent match, prefer extensions and name match miss", | 			name: "specific rules, subresource equivalent match, prefer extensions and name match miss", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				MatchPolicy:       &equivalentMatch, | 				MatchPolicy:       &equivalentMatch, | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					ResourceNames: []string{"wrong-name"}, | 					ResourceNames: []string{"wrong-name"}, | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -408,17 +407,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "exclude resource match on miss", | 			name: "exclude resource match on miss", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}}, | 				}}, | ||||||
| 				ExcludeResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ExcludeResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -430,17 +429,17 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "exclude resource miss on match", | 			name: "exclude resource miss on match", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| 				}}, | 				}}, | ||||||
| 				ExcludeResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ExcludeResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -451,11 +450,11 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "treat empty ResourceRules as match", | 			name: "treat empty ResourceRules as match", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ExcludeResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ExcludeResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Operations: []v1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | 						Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, | ||||||
| 					}, | 					}, | ||||||
| @@ -466,23 +465,23 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "treat non-empty ResourceRules as no match", | 			name: "treat non-empty ResourceRules as no match", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules:     []v1beta1.NamedRuleWithOperations{{}}, | 				ResourceRules:     []v1.NamedRuleWithOperations{{}}, | ||||||
| 			}, | 			}, | ||||||
| 			attrs:         admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil), | 			attrs:         admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil), | ||||||
| 			expectMatches: false, | 			expectMatches: false, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "erroring namespace selector on otherwise non-matching rule doesn't error", | 			name: "erroring namespace selector on otherwise non-matching rule doesn't error", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key ", Operator: "In", Values: []string{"bad value"}}}}, | 				NamespaceSelector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key ", Operator: "In", Values: []string{"bad value"}}}}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Rule:       v1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}}, | 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}}, | ||||||
| 						Operations: []v1beta1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 					}, | 					}, | ||||||
| 				}}, | 				}}, | ||||||
| 			}, | 			}, | ||||||
| @@ -492,13 +491,13 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "erroring namespace selector on otherwise matching rule errors", | 			name: "erroring namespace selector on otherwise matching rule errors", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, | 				NamespaceSelector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{}, | 				ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Rule:       v1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, | 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, | ||||||
| 						Operations: []v1beta1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 					}, | 					}, | ||||||
| 				}}, | 				}}, | ||||||
| 			}, | 			}, | ||||||
| @@ -508,13 +507,13 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "erroring object selector on otherwise non-matching rule doesn't error", | 			name: "erroring object selector on otherwise non-matching rule doesn't error", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, | 				ObjectSelector:    &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Rule:       v1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}}, | 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}}, | ||||||
| 						Operations: []v1beta1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 					}, | 					}, | ||||||
| 				}}, | 				}}, | ||||||
| 			}, | 			}, | ||||||
| @@ -524,13 +523,13 @@ func TestMatcher(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "erroring object selector on otherwise matching rule errors", | 			name: "erroring object selector on otherwise matching rule errors", | ||||||
| 			criteria: &v1beta1.MatchResources{ | 			criteria: &v1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{}, | 				NamespaceSelector: &metav1.LabelSelector{}, | ||||||
| 				ObjectSelector:    &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, | 				ObjectSelector:    &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, | ||||||
| 				ResourceRules: []v1beta1.NamedRuleWithOperations{{ | 				ResourceRules: []v1.NamedRuleWithOperations{{ | ||||||
| 					RuleWithOperations: v1beta1.RuleWithOperations{ | 					RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 						Rule:       v1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, | 						Rule:       v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, | ||||||
| 						Operations: []v1beta1.OperationType{"*"}, | 						Operations: []v1.OperationType{"*"}, | ||||||
| 					}, | 					}, | ||||||
| 				}}, | 				}}, | ||||||
| 			}, | 			}, | ||||||
| @@ -601,7 +600,7 @@ func (f fakeNamespaceLister) Get(name string) (*corev1.Namespace, error) { | |||||||
|  |  | ||||||
| func BenchmarkMatcher(b *testing.B) { | func BenchmarkMatcher(b *testing.B) { | ||||||
| 	allScopes := v1.AllScopes | 	allScopes := v1.AllScopes | ||||||
| 	equivalentMatch := v1beta1.Equivalent | 	equivalentMatch := v1.Equivalent | ||||||
|  |  | ||||||
| 	namespace1Labels := map[string]string{"ns": "ns1"} | 	namespace1Labels := map[string]string{"ns": "ns1"} | ||||||
| 	namespace1 := corev1.Namespace{ | 	namespace1 := corev1.Namespace{ | ||||||
| @@ -642,19 +641,19 @@ func BenchmarkMatcher(b *testing.B) { | |||||||
| 		nsSelector[fmt.Sprintf("key-%d", i)] = fmt.Sprintf("val-%d", i) | 		nsSelector[fmt.Sprintf("key-%d", i)] = fmt.Sprintf("val-%d", i) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	mr := v1beta1.MatchResources{ | 	mr := v1.MatchResources{ | ||||||
| 		MatchPolicy:       &equivalentMatch, | 		MatchPolicy:       &equivalentMatch, | ||||||
| 		NamespaceSelector: &metav1.LabelSelector{MatchLabels: nsSelector}, | 		NamespaceSelector: &metav1.LabelSelector{MatchLabels: nsSelector}, | ||||||
| 		ObjectSelector:    &metav1.LabelSelector{}, | 		ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 		ResourceRules: []v1beta1.NamedRuleWithOperations{ | 		ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 			{ | 			{ | ||||||
| 				RuleWithOperations: v1beta1.RuleWithOperations{ | 				RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 					Operations: []v1.OperationType{"*"}, | 					Operations: []v1.OperationType{"*"}, | ||||||
| 					Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 					Rule:       v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 			{ | 			{ | ||||||
| 				RuleWithOperations: v1beta1.RuleWithOperations{ | 				RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 					Operations: []v1.OperationType{"*"}, | 					Operations: []v1.OperationType{"*"}, | ||||||
| 					Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | 					Rule:       v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, | ||||||
| 				}, | 				}, | ||||||
| @@ -674,7 +673,7 @@ func BenchmarkMatcher(b *testing.B) { | |||||||
|  |  | ||||||
| func BenchmarkShouldCallHookWithComplexRule(b *testing.B) { | func BenchmarkShouldCallHookWithComplexRule(b *testing.B) { | ||||||
| 	allScopes := v1.AllScopes | 	allScopes := v1.AllScopes | ||||||
| 	equivalentMatch := v1beta1.Equivalent | 	equivalentMatch := v1.Equivalent | ||||||
|  |  | ||||||
| 	namespace1Labels := map[string]string{"ns": "ns1"} | 	namespace1Labels := map[string]string{"ns": "ns1"} | ||||||
| 	namespace1 := corev1.Namespace{ | 	namespace1 := corev1.Namespace{ | ||||||
| @@ -710,16 +709,16 @@ func BenchmarkShouldCallHookWithComplexRule(b *testing.B) { | |||||||
| 	mapper.RegisterKindFor(gvr("apps", "v1beta1", "statefulset"), "scale", gvk("apps", "v1beta1", "Scale")) | 	mapper.RegisterKindFor(gvr("apps", "v1beta1", "statefulset"), "scale", gvk("apps", "v1beta1", "Scale")) | ||||||
| 	mapper.RegisterKindFor(gvr("apps", "v1alpha2", "statefulset"), "scale", gvk("apps", "v1beta2", "Scale")) | 	mapper.RegisterKindFor(gvr("apps", "v1alpha2", "statefulset"), "scale", gvk("apps", "v1beta2", "Scale")) | ||||||
|  |  | ||||||
| 	mr := v1beta1.MatchResources{ | 	mr := v1.MatchResources{ | ||||||
| 		MatchPolicy:       &equivalentMatch, | 		MatchPolicy:       &equivalentMatch, | ||||||
| 		NamespaceSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, | 		NamespaceSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, | ||||||
| 		ObjectSelector:    &metav1.LabelSelector{}, | 		ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 		ResourceRules:     []v1beta1.NamedRuleWithOperations{}, | 		ResourceRules:     []v1.NamedRuleWithOperations{}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for i := 0; i < 100; i++ { | 	for i := 0; i < 100; i++ { | ||||||
| 		rule := v1beta1.NamedRuleWithOperations{ | 		rule := v1.NamedRuleWithOperations{ | ||||||
| 			RuleWithOperations: v1beta1.RuleWithOperations{ | 			RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 				Operations: []v1.OperationType{"*"}, | 				Operations: []v1.OperationType{"*"}, | ||||||
| 				Rule: v1.Rule{ | 				Rule: v1.Rule{ | ||||||
| 					APIGroups:   []string{fmt.Sprintf("app-%d", i)}, | 					APIGroups:   []string{fmt.Sprintf("app-%d", i)}, | ||||||
| @@ -744,7 +743,7 @@ func BenchmarkShouldCallHookWithComplexRule(b *testing.B) { | |||||||
|  |  | ||||||
| func BenchmarkShouldCallHookWithComplexSelectorAndRule(b *testing.B) { | func BenchmarkShouldCallHookWithComplexSelectorAndRule(b *testing.B) { | ||||||
| 	allScopes := v1.AllScopes | 	allScopes := v1.AllScopes | ||||||
| 	equivalentMatch := v1beta1.Equivalent | 	equivalentMatch := v1.Equivalent | ||||||
|  |  | ||||||
| 	namespace1Labels := map[string]string{"ns": "ns1"} | 	namespace1Labels := map[string]string{"ns": "ns1"} | ||||||
| 	namespace1 := corev1.Namespace{ | 	namespace1 := corev1.Namespace{ | ||||||
| @@ -785,16 +784,16 @@ func BenchmarkShouldCallHookWithComplexSelectorAndRule(b *testing.B) { | |||||||
| 		nsSelector[fmt.Sprintf("key-%d", i)] = fmt.Sprintf("val-%d", i) | 		nsSelector[fmt.Sprintf("key-%d", i)] = fmt.Sprintf("val-%d", i) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	mr := v1beta1.MatchResources{ | 	mr := v1.MatchResources{ | ||||||
| 		MatchPolicy:       &equivalentMatch, | 		MatchPolicy:       &equivalentMatch, | ||||||
| 		NamespaceSelector: &metav1.LabelSelector{MatchLabels: nsSelector}, | 		NamespaceSelector: &metav1.LabelSelector{MatchLabels: nsSelector}, | ||||||
| 		ObjectSelector:    &metav1.LabelSelector{}, | 		ObjectSelector:    &metav1.LabelSelector{}, | ||||||
| 		ResourceRules:     []v1beta1.NamedRuleWithOperations{}, | 		ResourceRules:     []v1.NamedRuleWithOperations{}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for i := 0; i < 100; i++ { | 	for i := 0; i < 100; i++ { | ||||||
| 		rule := v1beta1.NamedRuleWithOperations{ | 		rule := v1.NamedRuleWithOperations{ | ||||||
| 			RuleWithOperations: v1beta1.RuleWithOperations{ | 			RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 				Operations: []v1.OperationType{"*"}, | 				Operations: []v1.OperationType{"*"}, | ||||||
| 				Rule: v1.Rule{ | 				Rule: v1.Rule{ | ||||||
| 					APIGroups:   []string{fmt.Sprintf("app-%d", i)}, | 					APIGroups:   []string{fmt.Sprintf("app-%d", i)}, | ||||||
|   | |||||||
| @@ -17,25 +17,25 @@ limitations under the License. | |||||||
| package validating | package validating | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	"k8s.io/api/admissionregistration/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| 	"k8s.io/apiserver/pkg/admission/plugin/policy/generic" | 	"k8s.io/apiserver/pkg/admission/plugin/policy/generic" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func NewValidatingAdmissionPolicyAccessor(obj *v1beta1.ValidatingAdmissionPolicy) generic.PolicyAccessor { | func NewValidatingAdmissionPolicyAccessor(obj *v1.ValidatingAdmissionPolicy) generic.PolicyAccessor { | ||||||
| 	return &validatingAdmissionPolicyAccessor{ | 	return &validatingAdmissionPolicyAccessor{ | ||||||
| 		ValidatingAdmissionPolicy: obj, | 		ValidatingAdmissionPolicy: obj, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewValidatingAdmissionPolicyBindingAccessor(obj *v1beta1.ValidatingAdmissionPolicyBinding) generic.BindingAccessor { | func NewValidatingAdmissionPolicyBindingAccessor(obj *v1.ValidatingAdmissionPolicyBinding) generic.BindingAccessor { | ||||||
| 	return &validatingAdmissionPolicyBindingAccessor{ | 	return &validatingAdmissionPolicyBindingAccessor{ | ||||||
| 		ValidatingAdmissionPolicyBinding: obj, | 		ValidatingAdmissionPolicyBinding: obj, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| type validatingAdmissionPolicyAccessor struct { | type validatingAdmissionPolicyAccessor struct { | ||||||
| 	*v1beta1.ValidatingAdmissionPolicy | 	*v1.ValidatingAdmissionPolicy | ||||||
| } | } | ||||||
|  |  | ||||||
| func (v *validatingAdmissionPolicyAccessor) GetNamespace() string { | func (v *validatingAdmissionPolicyAccessor) GetNamespace() string { | ||||||
| @@ -46,16 +46,16 @@ func (v *validatingAdmissionPolicyAccessor) GetName() string { | |||||||
| 	return v.Name | 	return v.Name | ||||||
| } | } | ||||||
|  |  | ||||||
| func (v *validatingAdmissionPolicyAccessor) GetParamKind() *v1beta1.ParamKind { | func (v *validatingAdmissionPolicyAccessor) GetParamKind() *v1.ParamKind { | ||||||
| 	return v.Spec.ParamKind | 	return v.Spec.ParamKind | ||||||
| } | } | ||||||
|  |  | ||||||
| func (v *validatingAdmissionPolicyAccessor) GetMatchConstraints() *v1beta1.MatchResources { | func (v *validatingAdmissionPolicyAccessor) GetMatchConstraints() *v1.MatchResources { | ||||||
| 	return v.Spec.MatchConstraints | 	return v.Spec.MatchConstraints | ||||||
| } | } | ||||||
|  |  | ||||||
| type validatingAdmissionPolicyBindingAccessor struct { | type validatingAdmissionPolicyBindingAccessor struct { | ||||||
| 	*v1beta1.ValidatingAdmissionPolicyBinding | 	*v1.ValidatingAdmissionPolicyBinding | ||||||
| } | } | ||||||
|  |  | ||||||
| func (v *validatingAdmissionPolicyBindingAccessor) GetNamespace() string { | func (v *validatingAdmissionPolicyBindingAccessor) GetNamespace() string { | ||||||
| @@ -73,10 +73,10 @@ func (v *validatingAdmissionPolicyBindingAccessor) GetPolicyName() types.Namespa | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (v *validatingAdmissionPolicyBindingAccessor) GetMatchResources() *v1beta1.MatchResources { | func (v *validatingAdmissionPolicyBindingAccessor) GetMatchResources() *v1.MatchResources { | ||||||
| 	return v.Spec.MatchResources | 	return v.Spec.MatchResources | ||||||
| } | } | ||||||
|  |  | ||||||
| func (v *validatingAdmissionPolicyBindingAccessor) GetParamRef() *v1beta1.ParamRef { | func (v *validatingAdmissionPolicyBindingAccessor) GetParamRef() *v1.ParamRef { | ||||||
| 	return v.Spec.ParamRef | 	return v.Spec.ParamRef | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/stretchr/testify/require" | 	"github.com/stretchr/testify/require" | ||||||
|  |  | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1" | ||||||
| 	v1 "k8s.io/api/core/v1" | 	v1 "k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| @@ -61,18 +61,18 @@ var ( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Common objects | 	// Common objects | ||||||
| 	denyPolicy *v1beta1.ValidatingAdmissionPolicy = &v1beta1.ValidatingAdmissionPolicy{ | 	denyPolicy *admissionregistrationv1.ValidatingAdmissionPolicy = &admissionregistrationv1.ValidatingAdmissionPolicy{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{ | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
| 			Name:            "denypolicy.example.com", | 			Name:            "denypolicy.example.com", | ||||||
| 			ResourceVersion: "1", | 			ResourceVersion: "1", | ||||||
| 		}, | 		}, | ||||||
| 		Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 		Spec: admissionregistrationv1.ValidatingAdmissionPolicySpec{ | ||||||
| 			ParamKind: &v1beta1.ParamKind{ | 			ParamKind: &admissionregistrationv1.ParamKind{ | ||||||
| 				APIVersion: paramsGVK.GroupVersion().String(), | 				APIVersion: paramsGVK.GroupVersion().String(), | ||||||
| 				Kind:       paramsGVK.Kind, | 				Kind:       paramsGVK.Kind, | ||||||
| 			}, | 			}, | ||||||
| 			FailurePolicy: ptrTo(v1beta1.Fail), | 			FailurePolicy: ptrTo(admissionregistrationv1.Fail), | ||||||
| 			Validations: []v1beta1.Validation{ | 			Validations: []admissionregistrationv1.Validation{ | ||||||
| 				{ | 				{ | ||||||
| 					Expression: "messageId for deny policy", | 					Expression: "messageId for deny policy", | ||||||
| 				}, | 				}, | ||||||
| @@ -93,61 +93,61 @@ var ( | |||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	denyBinding *v1beta1.ValidatingAdmissionPolicyBinding = &v1beta1.ValidatingAdmissionPolicyBinding{ | 	denyBinding *admissionregistrationv1.ValidatingAdmissionPolicyBinding = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{ | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
| 			Name:            "denybinding.example.com", | 			Name:            "denybinding.example.com", | ||||||
| 			ResourceVersion: "1", | 			ResourceVersion: "1", | ||||||
| 		}, | 		}, | ||||||
| 		Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ | 		Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
| 			PolicyName: denyPolicy.Name, | 			PolicyName: denyPolicy.Name, | ||||||
| 			ParamRef: &v1beta1.ParamRef{ | 			ParamRef: &admissionregistrationv1.ParamRef{ | ||||||
| 				Name:      fakeParams.GetName(), | 				Name:      fakeParams.GetName(), | ||||||
| 				Namespace: fakeParams.GetNamespace(), | 				Namespace: fakeParams.GetNamespace(), | ||||||
| 				// fake object tracker does not populate defaults | 				// fake object tracker does not populate defaults | ||||||
| 				ParameterNotFoundAction: ptrTo(v1beta1.DenyAction), | 				ParameterNotFoundAction: ptrTo(admissionregistrationv1.DenyAction), | ||||||
| 			}, | 			}, | ||||||
| 			ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny}, | 			ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	denyBindingWithNoParamRef *v1beta1.ValidatingAdmissionPolicyBinding = &v1beta1.ValidatingAdmissionPolicyBinding{ | 	denyBindingWithNoParamRef *admissionregistrationv1.ValidatingAdmissionPolicyBinding = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{ | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
| 			Name:            "denybinding.example.com", | 			Name:            "denybinding.example.com", | ||||||
| 			ResourceVersion: "1", | 			ResourceVersion: "1", | ||||||
| 		}, | 		}, | ||||||
| 		Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ | 		Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
| 			PolicyName:        denyPolicy.Name, | 			PolicyName:        denyPolicy.Name, | ||||||
| 			ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny}, | 			ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	denyBindingWithAudit = &v1beta1.ValidatingAdmissionPolicyBinding{ | 	denyBindingWithAudit = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{ | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
| 			Name:            "denybinding.example.com", | 			Name:            "denybinding.example.com", | ||||||
| 			ResourceVersion: "1", | 			ResourceVersion: "1", | ||||||
| 		}, | 		}, | ||||||
| 		Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ | 		Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
| 			PolicyName:        denyPolicy.Name, | 			PolicyName:        denyPolicy.Name, | ||||||
| 			ValidationActions: []v1beta1.ValidationAction{v1beta1.Audit}, | 			ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Audit}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	denyBindingWithWarn = &v1beta1.ValidatingAdmissionPolicyBinding{ | 	denyBindingWithWarn = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{ | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
| 			Name:            "denybinding.example.com", | 			Name:            "denybinding.example.com", | ||||||
| 			ResourceVersion: "1", | 			ResourceVersion: "1", | ||||||
| 		}, | 		}, | ||||||
| 		Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ | 		Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
| 			PolicyName:        denyPolicy.Name, | 			PolicyName:        denyPolicy.Name, | ||||||
| 			ValidationActions: []v1beta1.ValidationAction{v1beta1.Warn}, | 			ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Warn}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	denyBindingWithAll = &v1beta1.ValidatingAdmissionPolicyBinding{ | 	denyBindingWithAll = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{ | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
| 			Name:            "denybinding.example.com", | 			Name:            "denybinding.example.com", | ||||||
| 			ResourceVersion: "1", | 			ResourceVersion: "1", | ||||||
| 		}, | 		}, | ||||||
| 		Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ | 		Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
| 			PolicyName:        denyPolicy.Name, | 			PolicyName:        denyPolicy.Name, | ||||||
| 			ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny, v1beta1.Warn, v1beta1.Audit}, | 			ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny, admissionregistrationv1.Warn, admissionregistrationv1.Audit}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| ) | ) | ||||||
| @@ -277,7 +277,7 @@ type fakeMatcher struct { | |||||||
| 	BindingMatchFuncs    map[types.NamespacedName]func(generic.BindingAccessor, admission.Attributes) bool | 	BindingMatchFuncs    map[types.NamespacedName]func(generic.BindingAccessor, admission.Attributes) bool | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *fakeMatcher) RegisterDefinition(definition *v1beta1.ValidatingAdmissionPolicy, matchFunc func(generic.PolicyAccessor, admission.Attributes) bool) { | func (f *fakeMatcher) RegisterDefinition(definition *admissionregistrationv1.ValidatingAdmissionPolicy, matchFunc func(generic.PolicyAccessor, admission.Attributes) bool) { | ||||||
| 	namespace, name := definition.Namespace, definition.Name | 	namespace, name := definition.Namespace, definition.Name | ||||||
| 	key := types.NamespacedName{ | 	key := types.NamespacedName{ | ||||||
| 		Name:      name, | 		Name:      name, | ||||||
| @@ -292,7 +292,7 @@ func (f *fakeMatcher) RegisterDefinition(definition *v1beta1.ValidatingAdmission | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *fakeMatcher) RegisterBinding(binding *v1beta1.ValidatingAdmissionPolicyBinding, matchFunc func(generic.BindingAccessor, admission.Attributes) bool) { | func (f *fakeMatcher) RegisterBinding(binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding, matchFunc func(generic.BindingAccessor, admission.Attributes) bool) { | ||||||
| 	namespace, name := binding.Namespace, binding.Name | 	namespace, name := binding.Namespace, binding.Name | ||||||
| 	key := types.NamespacedName{ | 	key := types.NamespacedName{ | ||||||
| 		Name:      name, | 		Name:      name, | ||||||
| @@ -644,19 +644,19 @@ func TestReconfigureBinding(t *testing.T) { | |||||||
| 		} | 		} | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	denyBinding2 := &v1beta1.ValidatingAdmissionPolicyBinding{ | 	denyBinding2 := &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{ | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
| 			Name:            "denybinding.example.com", | 			Name:            "denybinding.example.com", | ||||||
| 			ResourceVersion: "2", | 			ResourceVersion: "2", | ||||||
| 		}, | 		}, | ||||||
| 		Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ | 		Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
| 			PolicyName: denyPolicy.Name, | 			PolicyName: denyPolicy.Name, | ||||||
| 			ParamRef: &v1beta1.ParamRef{ | 			ParamRef: &admissionregistrationv1.ParamRef{ | ||||||
| 				Name:                    fakeParams2.GetName(), | 				Name:                    fakeParams2.GetName(), | ||||||
| 				Namespace:               fakeParams2.GetNamespace(), | 				Namespace:               fakeParams2.GetNamespace(), | ||||||
| 				ParameterNotFoundAction: ptrTo(v1beta1.DenyAction), | 				ParameterNotFoundAction: ptrTo(admissionregistrationv1.DenyAction), | ||||||
| 			}, | 			}, | ||||||
| 			ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny}, | 			ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -805,7 +805,7 @@ func TestInvalidParamSourceGVK(t *testing.T) { | |||||||
| 	passedParams := make(chan *unstructured.Unstructured) | 	passedParams := make(chan *unstructured.Unstructured) | ||||||
|  |  | ||||||
| 	badPolicy := *denyPolicy | 	badPolicy := *denyPolicy | ||||||
| 	badPolicy.Spec.ParamKind = &v1beta1.ParamKind{ | 	badPolicy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ | ||||||
| 		APIVersion: paramsGVK.GroupVersion().String(), | 		APIVersion: paramsGVK.GroupVersion().String(), | ||||||
| 		Kind:       "BadParamKind", | 		Kind:       "BadParamKind", | ||||||
| 	} | 	} | ||||||
| @@ -985,13 +985,13 @@ func TestMultiplePoliciesSharedParamType(t *testing.T) { | |||||||
| 	// Use ConfigMap native-typed param | 	// Use ConfigMap native-typed param | ||||||
| 	policy1 := *denyPolicy | 	policy1 := *denyPolicy | ||||||
| 	policy1.Name = "denypolicy1.example.com" | 	policy1.Name = "denypolicy1.example.com" | ||||||
| 	policy1.Spec = v1beta1.ValidatingAdmissionPolicySpec{ | 	policy1.Spec = admissionregistrationv1.ValidatingAdmissionPolicySpec{ | ||||||
| 		ParamKind: &v1beta1.ParamKind{ | 		ParamKind: &admissionregistrationv1.ParamKind{ | ||||||
| 			APIVersion: paramsGVK.GroupVersion().String(), | 			APIVersion: paramsGVK.GroupVersion().String(), | ||||||
| 			Kind:       paramsGVK.Kind, | 			Kind:       paramsGVK.Kind, | ||||||
| 		}, | 		}, | ||||||
| 		FailurePolicy: ptrTo(v1beta1.Fail), | 		FailurePolicy: ptrTo(admissionregistrationv1.Fail), | ||||||
| 		Validations: []v1beta1.Validation{ | 		Validations: []admissionregistrationv1.Validation{ | ||||||
| 			{ | 			{ | ||||||
| 				Expression: "policy1", | 				Expression: "policy1", | ||||||
| 			}, | 			}, | ||||||
| @@ -1000,13 +1000,13 @@ func TestMultiplePoliciesSharedParamType(t *testing.T) { | |||||||
|  |  | ||||||
| 	policy2 := *denyPolicy | 	policy2 := *denyPolicy | ||||||
| 	policy2.Name = "denypolicy2.example.com" | 	policy2.Name = "denypolicy2.example.com" | ||||||
| 	policy2.Spec = v1beta1.ValidatingAdmissionPolicySpec{ | 	policy2.Spec = admissionregistrationv1.ValidatingAdmissionPolicySpec{ | ||||||
| 		ParamKind: &v1beta1.ParamKind{ | 		ParamKind: &admissionregistrationv1.ParamKind{ | ||||||
| 			APIVersion: paramsGVK.GroupVersion().String(), | 			APIVersion: paramsGVK.GroupVersion().String(), | ||||||
| 			Kind:       paramsGVK.Kind, | 			Kind:       paramsGVK.Kind, | ||||||
| 		}, | 		}, | ||||||
| 		FailurePolicy: ptrTo(v1beta1.Fail), | 		FailurePolicy: ptrTo(admissionregistrationv1.Fail), | ||||||
| 		Validations: []v1beta1.Validation{ | 		Validations: []admissionregistrationv1.Validation{ | ||||||
| 			{ | 			{ | ||||||
| 				Expression: "policy2", | 				Expression: "policy2", | ||||||
| 			}, | 			}, | ||||||
| @@ -1106,7 +1106,7 @@ func TestNativeTypeParam(t *testing.T) { | |||||||
|  |  | ||||||
| 	// Use ConfigMap native-typed param | 	// Use ConfigMap native-typed param | ||||||
| 	nativeTypeParamPolicy := *denyPolicy | 	nativeTypeParamPolicy := *denyPolicy | ||||||
| 	nativeTypeParamPolicy.Spec.ParamKind = &v1beta1.ParamKind{ | 	nativeTypeParamPolicy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ | ||||||
| 		APIVersion: "v1", | 		APIVersion: "v1", | ||||||
| 		Kind:       "ConfigMap", | 		Kind:       "ConfigMap", | ||||||
| 	} | 	} | ||||||
| @@ -1208,7 +1208,7 @@ func TestAuditValidationAction(t *testing.T) { | |||||||
| 	expected := []validating.ValidationFailureValue{{ | 	expected := []validating.ValidationFailureValue{{ | ||||||
| 		ExpressionIndex:   0, | 		ExpressionIndex:   0, | ||||||
| 		Message:           "I'm sorry Dave", | 		Message:           "I'm sorry Dave", | ||||||
| 		ValidationActions: []v1beta1.ValidationAction{v1beta1.Audit}, | 		ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Audit}, | ||||||
| 		Binding:           "denybinding.example.com", | 		Binding:           "denybinding.example.com", | ||||||
| 		Policy:            noParamSourcePolicy.Name, | 		Policy:            noParamSourcePolicy.Name, | ||||||
| 	}} | 	}} | ||||||
| @@ -1305,7 +1305,7 @@ func TestAllValidationActions(t *testing.T) { | |||||||
| 	expected := []validating.ValidationFailureValue{{ | 	expected := []validating.ValidationFailureValue{{ | ||||||
| 		ExpressionIndex:   0, | 		ExpressionIndex:   0, | ||||||
| 		Message:           "I'm sorry Dave", | 		Message:           "I'm sorry Dave", | ||||||
| 		ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny, v1beta1.Warn, v1beta1.Audit}, | 		ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny, admissionregistrationv1.Warn, admissionregistrationv1.Audit}, | ||||||
| 		Binding:           "denybinding.example.com", | 		Binding:           "denybinding.example.com", | ||||||
| 		Policy:            noParamSourcePolicy.Name, | 		Policy:            noParamSourcePolicy.Name, | ||||||
| 	}} | 	}} | ||||||
| @@ -1325,13 +1325,13 @@ func TestNamespaceParamRefName(t *testing.T) { | |||||||
|  |  | ||||||
| 	// Use ConfigMap native-typed param | 	// Use ConfigMap native-typed param | ||||||
| 	nativeTypeParamPolicy := *denyPolicy | 	nativeTypeParamPolicy := *denyPolicy | ||||||
| 	nativeTypeParamPolicy.Spec.ParamKind = &v1beta1.ParamKind{ | 	nativeTypeParamPolicy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ | ||||||
| 		APIVersion: "v1", | 		APIVersion: "v1", | ||||||
| 		Kind:       "ConfigMap", | 		Kind:       "ConfigMap", | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	namespaceParamBinding := *denyBinding | 	namespaceParamBinding := *denyBinding | ||||||
| 	namespaceParamBinding.Spec.ParamRef = &v1beta1.ParamRef{ | 	namespaceParamBinding.Spec.ParamRef = &admissionregistrationv1.ParamRef{ | ||||||
| 		Name: "replicas-test.example.com", | 		Name: "replicas-test.example.com", | ||||||
| 	} | 	} | ||||||
| 	lock := sync.Mutex{} | 	lock := sync.Mutex{} | ||||||
| @@ -1543,7 +1543,7 @@ func testParamRefCase(t *testing.T, paramIsClusterScoped, nameIsSet, namespaceIs | |||||||
| 	// Create a cluster scoped and a namespace scoped CRD | 	// Create a cluster scoped and a namespace scoped CRD | ||||||
| 	policy := *denyPolicy | 	policy := *denyPolicy | ||||||
| 	binding := *denyBinding | 	binding := *denyBinding | ||||||
| 	binding.Spec.ParamRef = &v1beta1.ParamRef{} | 	binding.Spec.ParamRef = &admissionregistrationv1.ParamRef{} | ||||||
| 	paramRef := binding.Spec.ParamRef | 	paramRef := binding.Spec.ParamRef | ||||||
|  |  | ||||||
| 	shouldErrorOnClusterScopedRequests := !namespaceIsSet && !paramIsClusterScoped | 	shouldErrorOnClusterScopedRequests := !namespaceIsSet && !paramIsClusterScoped | ||||||
| @@ -1557,12 +1557,12 @@ func testParamRefCase(t *testing.T, paramIsClusterScoped, nameIsSet, namespaceIs | |||||||
| 	otherNonmatchingLabels := labels.Set{"notaffiliated": "no"} | 	otherNonmatchingLabels := labels.Set{"notaffiliated": "no"} | ||||||
|  |  | ||||||
| 	if paramIsClusterScoped { | 	if paramIsClusterScoped { | ||||||
| 		policy.Spec.ParamKind = &v1beta1.ParamKind{ | 		policy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ | ||||||
| 			APIVersion: clusterScopedParamsGVK.GroupVersion().String(), | 			APIVersion: clusterScopedParamsGVK.GroupVersion().String(), | ||||||
| 			Kind:       clusterScopedParamsGVK.Kind, | 			Kind:       clusterScopedParamsGVK.Kind, | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		policy.Spec.ParamKind = &v1beta1.ParamKind{ | 		policy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ | ||||||
| 			APIVersion: paramsGVK.GroupVersion().String(), | 			APIVersion: paramsGVK.GroupVersion().String(), | ||||||
| 			Kind:       paramsGVK.Kind, | 			Kind:       paramsGVK.Kind, | ||||||
| 		} | 		} | ||||||
| @@ -1581,9 +1581,9 @@ func testParamRefCase(t *testing.T, paramIsClusterScoped, nameIsSet, namespaceIs | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if denyNotFound { | 	if denyNotFound { | ||||||
| 		paramRef.ParameterNotFoundAction = ptrTo(v1beta1.DenyAction) | 		paramRef.ParameterNotFoundAction = ptrTo(admissionregistrationv1.DenyAction) | ||||||
| 	} else { | 	} else { | ||||||
| 		paramRef.ParameterNotFoundAction = ptrTo(v1beta1.AllowAction) | 		paramRef.ParameterNotFoundAction = ptrTo(admissionregistrationv1.AllowAction) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	compiler := &fakeCompiler{} | 	compiler := &fakeCompiler{} | ||||||
| @@ -1815,20 +1815,20 @@ func TestNamespaceParamRefClusterScopedParamError(t *testing.T) { | |||||||
|  |  | ||||||
| 	// Use ValidatingAdmissionPolicy for param type since it is cluster-scoped | 	// Use ValidatingAdmissionPolicy for param type since it is cluster-scoped | ||||||
| 	nativeTypeParamPolicy := *denyPolicy | 	nativeTypeParamPolicy := *denyPolicy | ||||||
| 	nativeTypeParamPolicy.Spec.ParamKind = &v1beta1.ParamKind{ | 	nativeTypeParamPolicy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ | ||||||
| 		APIVersion: "admissionregistration.k8s.io/v1beta1", | 		APIVersion: "admissionregistration.k8s.io/v1beta1", | ||||||
| 		Kind:       "ValidatingAdmissionPolicy", | 		Kind:       "ValidatingAdmissionPolicy", | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	namespaceParamBinding := *denyBinding | 	namespaceParamBinding := *denyBinding | ||||||
| 	namespaceParamBinding.Spec.ParamRef = &v1beta1.ParamRef{ | 	namespaceParamBinding.Spec.ParamRef = &admissionregistrationv1.ParamRef{ | ||||||
| 		Name:      "other-param-to-use-with-no-label.example.com", | 		Name:      "other-param-to-use-with-no-label.example.com", | ||||||
| 		Namespace: "mynamespace", | 		Namespace: "mynamespace", | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	compiler.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) validating.ValidateResult { | 	compiler.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) validating.ValidateResult { | ||||||
| 		evaluations.Add(1) | 		evaluations.Add(1) | ||||||
| 		if _, ok := versionedParams.(*v1beta1.ValidatingAdmissionPolicy); ok { | 		if _, ok := versionedParams.(*admissionregistrationv1.ValidatingAdmissionPolicy); ok { | ||||||
| 			return validating.ValidateResult{ | 			return validating.ValidateResult{ | ||||||
| 				Decisions: []validating.PolicyDecision{ | 				Decisions: []validating.PolicyDecision{ | ||||||
| 					{ | 					{ | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1" | ||||||
| 	v1 "k8s.io/api/core/v1" | 	v1 "k8s.io/api/core/v1" | ||||||
| 	k8serrors "k8s.io/apimachinery/pkg/api/errors" | 	k8serrors "k8s.io/apimachinery/pkg/api/errors" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| @@ -59,8 +59,8 @@ func NewDispatcher( | |||||||
| // that determined the decision | // that determined the decision | ||||||
| type policyDecisionWithMetadata struct { | type policyDecisionWithMetadata struct { | ||||||
| 	PolicyDecision | 	PolicyDecision | ||||||
| 	Definition *v1beta1.ValidatingAdmissionPolicy | 	Definition *admissionregistrationv1.ValidatingAdmissionPolicy | ||||||
| 	Binding    *v1beta1.ValidatingAdmissionPolicyBinding | 	Binding    *admissionregistrationv1.ValidatingAdmissionPolicyBinding | ||||||
| } | } | ||||||
|  |  | ||||||
| // Dispatch implements generic.Dispatcher. | // Dispatch implements generic.Dispatcher. | ||||||
| @@ -68,21 +68,21 @@ func (c *dispatcher) Dispatch(ctx context.Context, a admission.Attributes, o adm | |||||||
|  |  | ||||||
| 	var deniedDecisions []policyDecisionWithMetadata | 	var deniedDecisions []policyDecisionWithMetadata | ||||||
|  |  | ||||||
| 	addConfigError := func(err error, definition *v1beta1.ValidatingAdmissionPolicy, binding *v1beta1.ValidatingAdmissionPolicyBinding) { | 	addConfigError := func(err error, definition *admissionregistrationv1.ValidatingAdmissionPolicy, binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding) { | ||||||
| 		// we always default the FailurePolicy if it is unset and validate it in API level | 		// we always default the FailurePolicy if it is unset and validate it in API level | ||||||
| 		var policy v1beta1.FailurePolicyType | 		var policy admissionregistrationv1.FailurePolicyType | ||||||
| 		if definition.Spec.FailurePolicy == nil { | 		if definition.Spec.FailurePolicy == nil { | ||||||
| 			policy = v1beta1.Fail | 			policy = admissionregistrationv1.Fail | ||||||
| 		} else { | 		} else { | ||||||
| 			policy = *definition.Spec.FailurePolicy | 			policy = *definition.Spec.FailurePolicy | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// apply FailurePolicy specified in ValidatingAdmissionPolicy, the default would be Fail | 		// apply FailurePolicy specified in ValidatingAdmissionPolicy, the default would be Fail | ||||||
| 		switch policy { | 		switch policy { | ||||||
| 		case v1beta1.Ignore: | 		case admissionregistrationv1.Ignore: | ||||||
| 			// TODO: add metrics for ignored error here | 			// TODO: add metrics for ignored error here | ||||||
| 			return | 			return | ||||||
| 		case v1beta1.Fail: | 		case admissionregistrationv1.Fail: | ||||||
| 			var message string | 			var message string | ||||||
| 			if binding == nil { | 			if binding == nil { | ||||||
| 				message = fmt.Errorf("failed to configure policy: %w", err).Error() | 				message = fmt.Errorf("failed to configure policy: %w", err).Error() | ||||||
| @@ -228,17 +228,17 @@ func (c *dispatcher) Dispatch(ctx context.Context, a admission.Attributes, o adm | |||||||
| 					case ActionDeny: | 					case ActionDeny: | ||||||
| 						for _, action := range binding.Spec.ValidationActions { | 						for _, action := range binding.Spec.ValidationActions { | ||||||
| 							switch action { | 							switch action { | ||||||
| 							case v1beta1.Deny: | 							case admissionregistrationv1.Deny: | ||||||
| 								deniedDecisions = append(deniedDecisions, policyDecisionWithMetadata{ | 								deniedDecisions = append(deniedDecisions, policyDecisionWithMetadata{ | ||||||
| 									Definition:     definition, | 									Definition:     definition, | ||||||
| 									Binding:        binding, | 									Binding:        binding, | ||||||
| 									PolicyDecision: decision, | 									PolicyDecision: decision, | ||||||
| 								}) | 								}) | ||||||
| 								celmetrics.Metrics.ObserveRejection(ctx, decision.Elapsed, definition.Name, binding.Name, "active") | 								celmetrics.Metrics.ObserveRejection(ctx, decision.Elapsed, definition.Name, binding.Name, "active") | ||||||
| 							case v1beta1.Audit: | 							case admissionregistrationv1.Audit: | ||||||
| 								publishValidationFailureAnnotation(binding, i, decision, versionedAttr) | 								publishValidationFailureAnnotation(binding, i, decision, versionedAttr) | ||||||
| 								celmetrics.Metrics.ObserveAudit(ctx, decision.Elapsed, definition.Name, binding.Name, "active") | 								celmetrics.Metrics.ObserveAudit(ctx, decision.Elapsed, definition.Name, binding.Name, "active") | ||||||
| 							case v1beta1.Warn: | 							case admissionregistrationv1.Warn: | ||||||
| 								warning.AddWarning(ctx, "", fmt.Sprintf("Validation failed for ValidatingAdmissionPolicy '%s' with binding '%s': %s", definition.Name, binding.Name, decision.Message)) | 								warning.AddWarning(ctx, "", fmt.Sprintf("Validation failed for ValidatingAdmissionPolicy '%s' with binding '%s': %s", definition.Name, binding.Name, decision.Message)) | ||||||
| 								celmetrics.Metrics.ObserveWarn(ctx, decision.Elapsed, definition.Name, binding.Name, "active") | 								celmetrics.Metrics.ObserveWarn(ctx, decision.Elapsed, definition.Name, binding.Name, "active") | ||||||
| 							} | 							} | ||||||
| @@ -302,7 +302,7 @@ func (c *dispatcher) Dispatch(ctx context.Context, a admission.Attributes, o adm | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func publishValidationFailureAnnotation(binding *v1beta1.ValidatingAdmissionPolicyBinding, expressionIndex int, decision PolicyDecision, attributes admission.Attributes) { | func publishValidationFailureAnnotation(binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding, expressionIndex int, decision PolicyDecision, attributes admission.Attributes) { | ||||||
| 	key := "validation.policy.admission.k8s.io/validation_failure" | 	key := "validation.policy.admission.k8s.io/validation_failure" | ||||||
| 	// Marshal to a list of failures since, in the future, we may need to support multiple failures | 	// Marshal to a list of failures since, in the future, we may need to support multiple failures | ||||||
| 	valueJSON, err := utiljson.Marshal([]ValidationFailureValue{{ | 	valueJSON, err := utiljson.Marshal([]ValidationFailureValue{{ | ||||||
| @@ -330,7 +330,7 @@ type ValidationFailureValue struct { | |||||||
| 	Policy            string                                     `json:"policy"` | 	Policy            string                                     `json:"policy"` | ||||||
| 	Binding           string                                     `json:"binding"` | 	Binding           string                                     `json:"binding"` | ||||||
| 	ExpressionIndex   int                                        `json:"expressionIndex"` | 	ExpressionIndex   int                                        `json:"expressionIndex"` | ||||||
| 	ValidationActions []v1beta1.ValidationAction `json:"validationActions"` | 	ValidationActions []admissionregistrationv1.ValidationAction `json:"validationActions"` | ||||||
| } | } | ||||||
|  |  | ||||||
| type auditAnnotationCollector struct { | type auditAnnotationCollector struct { | ||||||
|   | |||||||
| @@ -21,7 +21,6 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
|  |  | ||||||
| 	v1 "k8s.io/api/admissionregistration/v1" | 	v1 "k8s.io/api/admissionregistration/v1" | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" |  | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	"k8s.io/apiserver/pkg/admission" | 	"k8s.io/apiserver/pkg/admission" | ||||||
| 	"k8s.io/apiserver/pkg/admission/initializer" | 	"k8s.io/apiserver/pkg/admission/initializer" | ||||||
| @@ -62,8 +61,8 @@ func Register(plugins *admission.Plugins) { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Plugin is an implementation of admission.Interface. | // Plugin is an implementation of admission.Interface. | ||||||
| type Policy = v1beta1.ValidatingAdmissionPolicy | type Policy = v1.ValidatingAdmissionPolicy | ||||||
| type PolicyBinding = v1beta1.ValidatingAdmissionPolicyBinding | type PolicyBinding = v1.ValidatingAdmissionPolicyBinding | ||||||
| type PolicyEvaluator = Validator | type PolicyEvaluator = Validator | ||||||
| type PolicyHook = generic.PolicyHook[*Policy, *PolicyBinding, PolicyEvaluator] | type PolicyHook = generic.PolicyHook[*Policy, *PolicyBinding, PolicyEvaluator] | ||||||
|  |  | ||||||
| @@ -84,8 +83,8 @@ func NewPlugin(_ io.Reader) *Plugin { | |||||||
| 			handler, | 			handler, | ||||||
| 			func(f informers.SharedInformerFactory, client kubernetes.Interface, dynamicClient dynamic.Interface, restMapper meta.RESTMapper) generic.Source[PolicyHook] { | 			func(f informers.SharedInformerFactory, client kubernetes.Interface, dynamicClient dynamic.Interface, restMapper meta.RESTMapper) generic.Source[PolicyHook] { | ||||||
| 				return generic.NewPolicySource( | 				return generic.NewPolicySource( | ||||||
| 					f.Admissionregistration().V1beta1().ValidatingAdmissionPolicies().Informer(), | 					f.Admissionregistration().V1().ValidatingAdmissionPolicies().Informer(), | ||||||
| 					f.Admissionregistration().V1beta1().ValidatingAdmissionPolicyBindings().Informer(), | 					f.Admissionregistration().V1().ValidatingAdmissionPolicyBindings().Informer(), | ||||||
| 					NewValidatingAdmissionPolicyAccessor, | 					NewValidatingAdmissionPolicyAccessor, | ||||||
| 					NewValidatingAdmissionPolicyBindingAccessor, | 					NewValidatingAdmissionPolicyBindingAccessor, | ||||||
| 					compilePolicy, | 					compilePolicy, | ||||||
| @@ -117,7 +116,7 @@ func compilePolicy(policy *Policy) Validator { | |||||||
| 	} | 	} | ||||||
| 	optionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: true} | 	optionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: true} | ||||||
| 	expressionOptionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: false} | 	expressionOptionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: false} | ||||||
| 	failurePolicy := convertv1beta1FailurePolicyTypeTov1FailurePolicyType(policy.Spec.FailurePolicy) | 	failurePolicy := policy.Spec.FailurePolicy | ||||||
| 	var matcher matchconditions.Matcher = nil | 	var matcher matchconditions.Matcher = nil | ||||||
| 	matchConditions := policy.Spec.MatchConditions | 	matchConditions := policy.Spec.MatchConditions | ||||||
|  |  | ||||||
| @@ -132,31 +131,17 @@ func compilePolicy(policy *Policy) Validator { | |||||||
| 		matcher = matchconditions.NewMatcher(filterCompiler.Compile(matchExpressionAccessors, optionalVars, environment.StoredExpressions), failurePolicy, "policy", "validate", policy.Name) | 		matcher = matchconditions.NewMatcher(filterCompiler.Compile(matchExpressionAccessors, optionalVars, environment.StoredExpressions), failurePolicy, "policy", "validate", policy.Name) | ||||||
| 	} | 	} | ||||||
| 	res := NewValidator( | 	res := NewValidator( | ||||||
| 		filterCompiler.Compile(convertv1beta1Validations(policy.Spec.Validations), optionalVars, environment.StoredExpressions), | 		filterCompiler.Compile(convertv1Validations(policy.Spec.Validations), optionalVars, environment.StoredExpressions), | ||||||
| 		matcher, | 		matcher, | ||||||
| 		filterCompiler.Compile(convertv1beta1AuditAnnotations(policy.Spec.AuditAnnotations), optionalVars, environment.StoredExpressions), | 		filterCompiler.Compile(convertv1AuditAnnotations(policy.Spec.AuditAnnotations), optionalVars, environment.StoredExpressions), | ||||||
| 		filterCompiler.Compile(convertv1beta1MessageExpressions(policy.Spec.Validations), expressionOptionalVars, environment.StoredExpressions), | 		filterCompiler.Compile(convertv1MessageExpressions(policy.Spec.Validations), expressionOptionalVars, environment.StoredExpressions), | ||||||
| 		failurePolicy, | 		failurePolicy, | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	return res | 	return res | ||||||
| } | } | ||||||
|  |  | ||||||
| func convertv1beta1FailurePolicyTypeTov1FailurePolicyType(policyType *v1beta1.FailurePolicyType) *v1.FailurePolicyType { | func convertv1Validations(inputValidations []v1.Validation) []cel.ExpressionAccessor { | ||||||
| 	if policyType == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var v1FailPolicy v1.FailurePolicyType |  | ||||||
| 	if *policyType == v1beta1.Fail { |  | ||||||
| 		v1FailPolicy = v1.Fail |  | ||||||
| 	} else if *policyType == v1beta1.Ignore { |  | ||||||
| 		v1FailPolicy = v1.Ignore |  | ||||||
| 	} |  | ||||||
| 	return &v1FailPolicy |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func convertv1beta1Validations(inputValidations []v1beta1.Validation) []cel.ExpressionAccessor { |  | ||||||
| 	celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) | 	celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) | ||||||
| 	for i, validation := range inputValidations { | 	for i, validation := range inputValidations { | ||||||
| 		validation := ValidationCondition{ | 		validation := ValidationCondition{ | ||||||
| @@ -169,7 +154,7 @@ func convertv1beta1Validations(inputValidations []v1beta1.Validation) []cel.Expr | |||||||
| 	return celExpressionAccessor | 	return celExpressionAccessor | ||||||
| } | } | ||||||
|  |  | ||||||
| func convertv1beta1MessageExpressions(inputValidations []v1beta1.Validation) []cel.ExpressionAccessor { | func convertv1MessageExpressions(inputValidations []v1.Validation) []cel.ExpressionAccessor { | ||||||
| 	celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) | 	celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) | ||||||
| 	for i, validation := range inputValidations { | 	for i, validation := range inputValidations { | ||||||
| 		if validation.MessageExpression != "" { | 		if validation.MessageExpression != "" { | ||||||
| @@ -182,7 +167,7 @@ func convertv1beta1MessageExpressions(inputValidations []v1beta1.Validation) []c | |||||||
| 	return celExpressionAccessor | 	return celExpressionAccessor | ||||||
| } | } | ||||||
|  |  | ||||||
| func convertv1beta1AuditAnnotations(inputValidations []v1beta1.AuditAnnotation) []cel.ExpressionAccessor { | func convertv1AuditAnnotations(inputValidations []v1.AuditAnnotation) []cel.ExpressionAccessor { | ||||||
| 	celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) | 	celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) | ||||||
| 	for i, validation := range inputValidations { | 	for i, validation := range inputValidations { | ||||||
| 		validation := AuditAnnotationCondition{ | 		validation := AuditAnnotationCondition{ | ||||||
| @@ -194,7 +179,7 @@ func convertv1beta1AuditAnnotations(inputValidations []v1beta1.AuditAnnotation) | |||||||
| 	return celExpressionAccessor | 	return celExpressionAccessor | ||||||
| } | } | ||||||
|  |  | ||||||
| func convertv1beta1Variables(variables []v1beta1.Variable) []cel.NamedExpressionAccessor { | func convertv1beta1Variables(variables []v1.Variable) []cel.NamedExpressionAccessor { | ||||||
| 	namedExpressions := make([]cel.NamedExpressionAccessor, len(variables)) | 	namedExpressions := make([]cel.NamedExpressionAccessor, len(variables)) | ||||||
| 	for i, variable := range variables { | 	for i, variable := range variables { | ||||||
| 		namedExpressions[i] = &Variable{Name: variable.Name, Expression: variable.Expression} | 		namedExpressions[i] = &Variable{Name: variable.Name, Expression: variable.Expression} | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/google/cel-go/cel" | 	"github.com/google/cel-go/cel" | ||||||
|  |  | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	"k8s.io/api/admissionregistration/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
| 	utilruntime "k8s.io/apimachinery/pkg/util/runtime" | 	utilruntime "k8s.io/apimachinery/pkg/util/runtime" | ||||||
| @@ -57,7 +57,7 @@ type TypeCheckingContext struct { | |||||||
| 	paramGVK      schema.GroupVersionKind | 	paramGVK      schema.GroupVersionKind | ||||||
| 	paramDeclType *apiservercel.DeclType | 	paramDeclType *apiservercel.DeclType | ||||||
|  |  | ||||||
| 	variables []v1beta1.Variable | 	variables []v1.Variable | ||||||
| } | } | ||||||
|  |  | ||||||
| type typeOverwrite struct { | type typeOverwrite struct { | ||||||
| @@ -105,18 +105,18 @@ func (r *TypeCheckingResult) String() string { | |||||||
| // as []ExpressionWarning that is ready to be set in policy.Status | // as []ExpressionWarning that is ready to be set in policy.Status | ||||||
| // The result is nil if type checking returns no warning. | // The result is nil if type checking returns no warning. | ||||||
| // The policy object is NOT mutated. The caller should update Status accordingly | // The policy object is NOT mutated. The caller should update Status accordingly | ||||||
| func (c *TypeChecker) Check(policy *v1beta1.ValidatingAdmissionPolicy) []v1beta1.ExpressionWarning { | func (c *TypeChecker) Check(policy *v1.ValidatingAdmissionPolicy) []v1.ExpressionWarning { | ||||||
| 	ctx := c.CreateContext(policy) | 	ctx := c.CreateContext(policy) | ||||||
|  |  | ||||||
| 	// warnings to return, note that the capacity is optimistically set to zero | 	// warnings to return, note that the capacity is optimistically set to zero | ||||||
| 	var warnings []v1beta1.ExpressionWarning // intentionally not setting capacity | 	var warnings []v1.ExpressionWarning // intentionally not setting capacity | ||||||
|  |  | ||||||
| 	// check main validation expressions and their message expressions, located in spec.validations[*] | 	// check main validation expressions and their message expressions, located in spec.validations[*] | ||||||
| 	fieldRef := field.NewPath("spec", "validations") | 	fieldRef := field.NewPath("spec", "validations") | ||||||
| 	for i, v := range policy.Spec.Validations { | 	for i, v := range policy.Spec.Validations { | ||||||
| 		results := c.CheckExpression(ctx, v.Expression) | 		results := c.CheckExpression(ctx, v.Expression) | ||||||
| 		if len(results) != 0 { | 		if len(results) != 0 { | ||||||
| 			warnings = append(warnings, v1beta1.ExpressionWarning{ | 			warnings = append(warnings, v1.ExpressionWarning{ | ||||||
| 				FieldRef: fieldRef.Index(i).Child("expression").String(), | 				FieldRef: fieldRef.Index(i).Child("expression").String(), | ||||||
| 				Warning:  results.String(), | 				Warning:  results.String(), | ||||||
| 			}) | 			}) | ||||||
| @@ -127,7 +127,7 @@ func (c *TypeChecker) Check(policy *v1beta1.ValidatingAdmissionPolicy) []v1beta1 | |||||||
| 		} | 		} | ||||||
| 		results = c.CheckExpression(ctx, v.MessageExpression) | 		results = c.CheckExpression(ctx, v.MessageExpression) | ||||||
| 		if len(results) != 0 { | 		if len(results) != 0 { | ||||||
| 			warnings = append(warnings, v1beta1.ExpressionWarning{ | 			warnings = append(warnings, v1.ExpressionWarning{ | ||||||
| 				FieldRef: fieldRef.Index(i).Child("messageExpression").String(), | 				FieldRef: fieldRef.Index(i).Child("messageExpression").String(), | ||||||
| 				Warning:  results.String(), | 				Warning:  results.String(), | ||||||
| 			}) | 			}) | ||||||
| @@ -138,7 +138,7 @@ func (c *TypeChecker) Check(policy *v1beta1.ValidatingAdmissionPolicy) []v1beta1 | |||||||
| } | } | ||||||
|  |  | ||||||
| // CreateContext resolves all types and their schemas from a policy definition and creates the context. | // CreateContext resolves all types and their schemas from a policy definition and creates the context. | ||||||
| func (c *TypeChecker) CreateContext(policy *v1beta1.ValidatingAdmissionPolicy) *TypeCheckingContext { | func (c *TypeChecker) CreateContext(policy *v1.ValidatingAdmissionPolicy) *TypeCheckingContext { | ||||||
| 	ctx := new(TypeCheckingContext) | 	ctx := new(TypeCheckingContext) | ||||||
| 	allGvks := c.typesToCheck(policy) | 	allGvks := c.typesToCheck(policy) | ||||||
| 	gvks := make([]schema.GroupVersionKind, 0, len(allGvks)) | 	gvks := make([]schema.GroupVersionKind, 0, len(allGvks)) | ||||||
| @@ -250,7 +250,7 @@ func (c *TypeChecker) declType(gvk schema.GroupVersionKind) (*apiservercel.DeclT | |||||||
| 	return common.SchemaDeclType(&openapi.Schema{Schema: s}, true).MaybeAssignTypeName(generateUniqueTypeName(gvk.Kind)), nil | 	return common.SchemaDeclType(&openapi.Schema{Schema: s}, true).MaybeAssignTypeName(generateUniqueTypeName(gvk.Kind)), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *TypeChecker) paramsGVK(policy *v1beta1.ValidatingAdmissionPolicy) schema.GroupVersionKind { | func (c *TypeChecker) paramsGVK(policy *v1.ValidatingAdmissionPolicy) schema.GroupVersionKind { | ||||||
| 	if policy.Spec.ParamKind == nil { | 	if policy.Spec.ParamKind == nil { | ||||||
| 		return schema.GroupVersionKind{} | 		return schema.GroupVersionKind{} | ||||||
| 	} | 	} | ||||||
| @@ -263,7 +263,7 @@ func (c *TypeChecker) paramsGVK(policy *v1beta1.ValidatingAdmissionPolicy) schem | |||||||
|  |  | ||||||
| // typesToCheck extracts a list of GVKs that needs type checking from the policy | // typesToCheck extracts a list of GVKs that needs type checking from the policy | ||||||
| // the result is sorted in the order of Group, Version, and Kind | // the result is sorted in the order of Group, Version, and Kind | ||||||
| func (c *TypeChecker) typesToCheck(p *v1beta1.ValidatingAdmissionPolicy) []schema.GroupVersionKind { | func (c *TypeChecker) typesToCheck(p *v1.ValidatingAdmissionPolicy) []schema.GroupVersionKind { | ||||||
| 	gvks := sets.New[schema.GroupVersionKind]() | 	gvks := sets.New[schema.GroupVersionKind]() | ||||||
| 	if p.Spec.MatchConstraints == nil || len(p.Spec.MatchConstraints.ResourceRules) == 0 { | 	if p.Spec.MatchConstraints == nil || len(p.Spec.MatchConstraints.ResourceRules) == 0 { | ||||||
| 		return nil | 		return nil | ||||||
| @@ -333,7 +333,7 @@ func (c *TypeChecker) typesToCheck(p *v1beta1.ValidatingAdmissionPolicy) []schem | |||||||
| 	return sortGVKList(gvks.UnsortedList()) | 	return sortGVKList(gvks.UnsortedList()) | ||||||
| } | } | ||||||
|  |  | ||||||
| func extractGroups(rule *v1beta1.Rule) []string { | func extractGroups(rule *v1.Rule) []string { | ||||||
| 	groups := make([]string, 0, len(rule.APIGroups)) | 	groups := make([]string, 0, len(rule.APIGroups)) | ||||||
| 	for _, group := range rule.APIGroups { | 	for _, group := range rule.APIGroups { | ||||||
| 		// give up if wildcard | 		// give up if wildcard | ||||||
| @@ -345,7 +345,7 @@ func extractGroups(rule *v1beta1.Rule) []string { | |||||||
| 	return groups | 	return groups | ||||||
| } | } | ||||||
|  |  | ||||||
| func extractVersions(rule *v1beta1.Rule) []string { | func extractVersions(rule *v1.Rule) []string { | ||||||
| 	versions := make([]string, 0, len(rule.APIVersions)) | 	versions := make([]string, 0, len(rule.APIVersions)) | ||||||
| 	for _, version := range rule.APIVersions { | 	for _, version := range rule.APIVersions { | ||||||
| 		if strings.ContainsAny(version, "*") { | 		if strings.ContainsAny(version, "*") { | ||||||
| @@ -356,7 +356,7 @@ func extractVersions(rule *v1beta1.Rule) []string { | |||||||
| 	return versions | 	return versions | ||||||
| } | } | ||||||
|  |  | ||||||
| func extractResources(rule *v1beta1.Rule) []string { | func extractResources(rule *v1.Rule) []string { | ||||||
| 	resources := make([]string, 0, len(rule.Resources)) | 	resources := make([]string, 0, len(rule.Resources)) | ||||||
| 	for _, resource := range rule.Resources { | 	for _, resource := range rule.Resources { | ||||||
| 		// skip wildcard and subresources | 		// skip wildcard and subresources | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"k8s.io/api/admissionregistration/v1beta1" | 	"k8s.io/api/admissionregistration/v1" | ||||||
| 	appsv1 "k8s.io/api/apps/v1" | 	appsv1 "k8s.io/api/apps/v1" | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| @@ -36,7 +36,7 @@ import ( | |||||||
| var ( | var ( | ||||||
| 	scheme *runtime.Scheme = func() *runtime.Scheme { | 	scheme *runtime.Scheme = func() *runtime.Scheme { | ||||||
| 		res := runtime.NewScheme() | 		res := runtime.NewScheme() | ||||||
| 		if err := v1beta1.AddToScheme(res); err != nil { | 		if err := v1.AddToScheme(res); err != nil { | ||||||
| 			panic(err) | 			panic(err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -58,21 +58,21 @@ func must3[T any, I any](val T, _ I, err error) T { | |||||||
| func TestExtractTypeNames(t *testing.T) { | func TestExtractTypeNames(t *testing.T) { | ||||||
| 	for _, tc := range []struct { | 	for _, tc := range []struct { | ||||||
| 		name     string | 		name     string | ||||||
| 		policy   *v1beta1.ValidatingAdmissionPolicy | 		policy   *v1.ValidatingAdmissionPolicy | ||||||
| 		expected []schema.GroupVersionKind // must be sorted | 		expected []schema.GroupVersionKind // must be sorted | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
| 			name:     "empty", | 			name:     "empty", | ||||||
| 			policy:   &v1beta1.ValidatingAdmissionPolicy{}, | 			policy:   &v1.ValidatingAdmissionPolicy{}, | ||||||
| 			expected: nil, | 			expected: nil, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "specific", | 			name: "specific", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 				MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 					{ | 					{ | ||||||
| 						RuleWithOperations: v1beta1.RuleWithOperations{ | 						RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 							Rule: v1beta1.Rule{ | 							Rule: v1.Rule{ | ||||||
| 								APIGroups:   []string{"apps"}, | 								APIGroups:   []string{"apps"}, | ||||||
| 								APIVersions: []string{"v1"}, | 								APIVersions: []string{"v1"}, | ||||||
| 								Resources:   []string{"deployments"}, | 								Resources:   []string{"deployments"}, | ||||||
| @@ -89,19 +89,19 @@ func TestExtractTypeNames(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "multiple", | 			name: "multiple", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 				MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 					{ | 					{ | ||||||
| 						RuleWithOperations: v1beta1.RuleWithOperations{ | 						RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 							Rule: v1beta1.Rule{ | 							Rule: v1.Rule{ | ||||||
| 								APIGroups:   []string{"apps"}, | 								APIGroups:   []string{"apps"}, | ||||||
| 								APIVersions: []string{"v1"}, | 								APIVersions: []string{"v1"}, | ||||||
| 								Resources:   []string{"deployments"}, | 								Resources:   []string{"deployments"}, | ||||||
| 							}, | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, { | 					}, { | ||||||
| 						RuleWithOperations: v1beta1.RuleWithOperations{ | 						RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 							Rule: v1beta1.Rule{ | 							Rule: v1.Rule{ | ||||||
| 								APIGroups:   []string{""}, | 								APIGroups:   []string{""}, | ||||||
| 								APIVersions: []string{"v1"}, | 								APIVersions: []string{"v1"}, | ||||||
| 								Resources:   []string{"pods"}, | 								Resources:   []string{"pods"}, | ||||||
| @@ -122,11 +122,11 @@ func TestExtractTypeNames(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "all resources", | 			name: "all resources", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 				MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 					{ | 					{ | ||||||
| 						RuleWithOperations: v1beta1.RuleWithOperations{ | 						RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 							Rule: v1beta1.Rule{ | 							Rule: v1.Rule{ | ||||||
| 								APIGroups:   []string{"apps"}, | 								APIGroups:   []string{"apps"}, | ||||||
| 								APIVersions: []string{"v1"}, | 								APIVersions: []string{"v1"}, | ||||||
| 								Resources:   []string{"*"}, | 								Resources:   []string{"*"}, | ||||||
| @@ -139,11 +139,11 @@ func TestExtractTypeNames(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "sub resources", | 			name: "sub resources", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 				MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 					{ | 					{ | ||||||
| 						RuleWithOperations: v1beta1.RuleWithOperations{ | 						RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 							Rule: v1beta1.Rule{ | 							Rule: v1.Rule{ | ||||||
| 								APIGroups:   []string{"apps"}, | 								APIGroups:   []string{"apps"}, | ||||||
| 								APIVersions: []string{"v1"}, | 								APIVersions: []string{"v1"}, | ||||||
| 								Resources:   []string{"pods/*"}, | 								Resources:   []string{"pods/*"}, | ||||||
| @@ -156,11 +156,11 @@ func TestExtractTypeNames(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "mixtures", | 			name: "mixtures", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 				MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 					{ | 					{ | ||||||
| 						RuleWithOperations: v1beta1.RuleWithOperations{ | 						RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 							Rule: v1beta1.Rule{ | 							Rule: v1.Rule{ | ||||||
| 								APIGroups:   []string{"apps"}, | 								APIGroups:   []string{"apps"}, | ||||||
| 								APIVersions: []string{"v1"}, | 								APIVersions: []string{"v1"}, | ||||||
| 								Resources:   []string{"deployments"}, | 								Resources:   []string{"deployments"}, | ||||||
| @@ -168,8 +168,8 @@ func TestExtractTypeNames(t *testing.T) { | |||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
| 						RuleWithOperations: v1beta1.RuleWithOperations{ | 						RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 							Rule: v1beta1.Rule{ | 							Rule: v1.Rule{ | ||||||
| 								APIGroups:   []string{"apps"}, | 								APIGroups:   []string{"apps"}, | ||||||
| 								APIVersions: []string{"*"}, | 								APIVersions: []string{"*"}, | ||||||
| 								Resources:   []string{"deployments"}, | 								Resources:   []string{"deployments"}, | ||||||
| @@ -196,16 +196,16 @@ func TestExtractTypeNames(t *testing.T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func TestTypeCheck(t *testing.T) { | func TestTypeCheck(t *testing.T) { | ||||||
| 	deploymentPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 	deploymentPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 		Validations: []v1beta1.Validation{ | 		Validations: []v1.Validation{ | ||||||
| 			{ | 			{ | ||||||
| 				Expression: "object.foo == 'bar'", | 				Expression: "object.foo == 'bar'", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 		MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 			{ | 			{ | ||||||
| 				RuleWithOperations: v1beta1.RuleWithOperations{ | 				RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 					Rule: v1beta1.Rule{ | 					Rule: v1.Rule{ | ||||||
| 						APIGroups:   []string{"apps"}, | 						APIGroups:   []string{"apps"}, | ||||||
| 						APIVersions: []string{"v1"}, | 						APIVersions: []string{"v1"}, | ||||||
| 						Resources:   []string{"deployments"}, | 						Resources:   []string{"deployments"}, | ||||||
| @@ -218,8 +218,8 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 	deploymentPolicyWithBadMessageExpression := deploymentPolicy.DeepCopy() | 	deploymentPolicyWithBadMessageExpression := deploymentPolicy.DeepCopy() | ||||||
| 	deploymentPolicyWithBadMessageExpression.Spec.Validations[0].MessageExpression = "object.foo + 114514" // confusion | 	deploymentPolicyWithBadMessageExpression.Spec.Validations[0].MessageExpression = "object.foo + 114514" // confusion | ||||||
|  |  | ||||||
| 	multiExpressionPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 	multiExpressionPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 		Validations: []v1beta1.Validation{ | 		Validations: []v1.Validation{ | ||||||
| 			{ | 			{ | ||||||
| 				Expression: "object.foo == 'bar'", | 				Expression: "object.foo == 'bar'", | ||||||
| 			}, | 			}, | ||||||
| @@ -227,10 +227,10 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 				Expression: "object.bar == 'foo'", | 				Expression: "object.bar == 'foo'", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 		MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 			{ | 			{ | ||||||
| 				RuleWithOperations: v1beta1.RuleWithOperations{ | 				RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 					Rule: v1beta1.Rule{ | 					Rule: v1.Rule{ | ||||||
| 						APIGroups:   []string{"apps"}, | 						APIGroups:   []string{"apps"}, | ||||||
| 						APIVersions: []string{"v1"}, | 						APIVersions: []string{"v1"}, | ||||||
| 						Resources:   []string{"deployments"}, | 						Resources:   []string{"deployments"}, | ||||||
| @@ -239,20 +239,20 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 			}, | 			}, | ||||||
| 		}}, | 		}}, | ||||||
| 	}} | 	}} | ||||||
| 	paramsRefPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 	paramsRefPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 		ParamKind: &v1beta1.ParamKind{ | 		ParamKind: &v1.ParamKind{ | ||||||
| 			APIVersion: "v1", | 			APIVersion: "v1", | ||||||
| 			Kind:       "DoesNotMatter", | 			Kind:       "DoesNotMatter", | ||||||
| 		}, | 		}, | ||||||
| 		Validations: []v1beta1.Validation{ | 		Validations: []v1.Validation{ | ||||||
| 			{ | 			{ | ||||||
| 				Expression: "object.foo == params.bar", | 				Expression: "object.foo == params.bar", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 		MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 			{ | 			{ | ||||||
| 				RuleWithOperations: v1beta1.RuleWithOperations{ | 				RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 					Rule: v1beta1.Rule{ | 					Rule: v1.Rule{ | ||||||
| 						APIGroups:   []string{"apps"}, | 						APIGroups:   []string{"apps"}, | ||||||
| 						APIVersions: []string{"v1"}, | 						APIVersions: []string{"v1"}, | ||||||
| 						Resources:   []string{"deployments"}, | 						Resources:   []string{"deployments"}, | ||||||
| @@ -261,16 +261,16 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 			}, | 			}, | ||||||
| 		}}, | 		}}, | ||||||
| 	}} | 	}} | ||||||
| 	authorizerPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 	authorizerPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 		Validations: []v1beta1.Validation{ | 		Validations: []v1.Validation{ | ||||||
| 			{ | 			{ | ||||||
| 				Expression: "authorizer.group('').resource('endpoints').check('create').allowed()", | 				Expression: "authorizer.group('').resource('endpoints').check('create').allowed()", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 		MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 			{ | 			{ | ||||||
| 				RuleWithOperations: v1beta1.RuleWithOperations{ | 				RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 					Rule: v1beta1.Rule{ | 					Rule: v1.Rule{ | ||||||
| 						APIGroups:   []string{"apps"}, | 						APIGroups:   []string{"apps"}, | ||||||
| 						APIVersions: []string{"v1"}, | 						APIVersions: []string{"v1"}, | ||||||
| 						Resources:   []string{"deployments"}, | 						Resources:   []string{"deployments"}, | ||||||
| @@ -279,16 +279,16 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 			}, | 			}, | ||||||
| 		}}, | 		}}, | ||||||
| 	}} | 	}} | ||||||
| 	authorizerInvalidPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 	authorizerInvalidPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 		Validations: []v1beta1.Validation{ | 		Validations: []v1.Validation{ | ||||||
| 			{ | 			{ | ||||||
| 				Expression: "authorizer.allowed()", | 				Expression: "authorizer.allowed()", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ | 		MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ | ||||||
| 			{ | 			{ | ||||||
| 				RuleWithOperations: v1beta1.RuleWithOperations{ | 				RuleWithOperations: v1.RuleWithOperations{ | ||||||
| 					Rule: v1beta1.Rule{ | 					Rule: v1.Rule{ | ||||||
| 						APIGroups:   []string{"apps"}, | 						APIGroups:   []string{"apps"}, | ||||||
| 						APIVersions: []string{"v1"}, | 						APIVersions: []string{"v1"}, | ||||||
| 						Resources:   []string{"deployments"}, | 						Resources:   []string{"deployments"}, | ||||||
| @@ -300,12 +300,12 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 	for _, tc := range []struct { | 	for _, tc := range []struct { | ||||||
| 		name           string | 		name           string | ||||||
| 		schemaToReturn *spec.Schema | 		schemaToReturn *spec.Schema | ||||||
| 		policy         *v1beta1.ValidatingAdmissionPolicy | 		policy         *v1.ValidatingAdmissionPolicy | ||||||
| 		assertions     []assertionFunc | 		assertions     []assertionFunc | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
| 			name:       "empty", | 			name:       "empty", | ||||||
| 			policy:     &v1beta1.ValidatingAdmissionPolicy{}, | 			policy:     &v1.ValidatingAdmissionPolicy{}, | ||||||
| 			assertions: []assertionFunc{toBeEmpty}, | 			assertions: []assertionFunc{toBeEmpty}, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| @@ -439,14 +439,14 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "variables valid", | 			name: "variables valid", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				Variables: []v1beta1.Variable{ | 				Variables: []v1.Variable{ | ||||||
| 					{ | 					{ | ||||||
| 						Name:       "works", | 						Name:       "works", | ||||||
| 						Expression: "true", | 						Expression: "true", | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				Validations: []v1beta1.Validation{ | 				Validations: []v1.Validation{ | ||||||
| 					{ | 					{ | ||||||
| 						Expression: "variables.works", | 						Expression: "variables.works", | ||||||
| 					}, | 					}, | ||||||
| @@ -466,14 +466,14 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "variables missing field", | 			name: "variables missing field", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				Variables: []v1beta1.Variable{ | 				Variables: []v1.Variable{ | ||||||
| 					{ | 					{ | ||||||
| 						Name:       "works", | 						Name:       "works", | ||||||
| 						Expression: "true", | 						Expression: "true", | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				Validations: []v1beta1.Validation{ | 				Validations: []v1.Validation{ | ||||||
| 					{ | 					{ | ||||||
| 						Expression: "variables.nonExisting", | 						Expression: "variables.nonExisting", | ||||||
| 					}, | 					}, | ||||||
| @@ -497,14 +497,14 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "variables field wrong type", | 			name: "variables field wrong type", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				Variables: []v1beta1.Variable{ | 				Variables: []v1.Variable{ | ||||||
| 					{ | 					{ | ||||||
| 						Name:       "name", | 						Name:       "name", | ||||||
| 						Expression: "'something'", | 						Expression: "'something'", | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				Validations: []v1beta1.Validation{ | 				Validations: []v1.Validation{ | ||||||
| 					{ | 					{ | ||||||
| 						Expression: "variables.name == object.foo", // foo is int64 | 						Expression: "variables.name == object.foo", // foo is int64 | ||||||
| 					}, | 					}, | ||||||
| @@ -528,14 +528,14 @@ func TestTypeCheck(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "error in variables, not reported during type checking.", | 			name: "error in variables, not reported during type checking.", | ||||||
| 			policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ | 			policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ | ||||||
| 				Variables: []v1beta1.Variable{ | 				Variables: []v1.Variable{ | ||||||
| 					{ | 					{ | ||||||
| 						Name:       "name", | 						Name:       "name", | ||||||
| 						Expression: "object.foo == 'str'", | 						Expression: "object.foo == 'str'", | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				Validations: []v1beta1.Validation{ | 				Validations: []v1.Validation{ | ||||||
| 					{ | 					{ | ||||||
| 						Expression: "variables.name == object.foo", // foo is int64 | 						Expression: "variables.name == object.foo", // foo is int64 | ||||||
| 					}, | 					}, | ||||||
| @@ -593,14 +593,14 @@ func (r *fakeSchemaResolver) ResolveSchema(gvk schema.GroupVersionKind) (*spec.S | |||||||
| 	return r.schemaToReturn, nil | 	return r.schemaToReturn, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func toBeEmpty(warnings []v1beta1.ExpressionWarning, t *testing.T) { | func toBeEmpty(warnings []v1.ExpressionWarning, t *testing.T) { | ||||||
| 	if len(warnings) != 0 { | 	if len(warnings) != 0 { | ||||||
| 		t.Fatalf("expected empty but got %v", warnings) | 		t.Fatalf("expected empty but got %v", warnings) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func toContain(substring string) func(warnings []v1beta1.ExpressionWarning, t *testing.T) { | func toContain(substring string) func(warnings []v1.ExpressionWarning, t *testing.T) { | ||||||
| 	return func(warnings []v1beta1.ExpressionWarning, t *testing.T) { | 	return func(warnings []v1.ExpressionWarning, t *testing.T) { | ||||||
| 		if len(warnings) == 0 { | 		if len(warnings) == 0 { | ||||||
| 			t.Errorf("expected containing %q but got empty", substring) | 			t.Errorf("expected containing %q but got empty", substring) | ||||||
| 		} | 		} | ||||||
| @@ -612,8 +612,8 @@ func toContain(substring string) func(warnings []v1beta1.ExpressionWarning, t *t | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func toHaveLengthOf(expected int) func(warnings []v1beta1.ExpressionWarning, t *testing.T) { | func toHaveLengthOf(expected int) func(warnings []v1.ExpressionWarning, t *testing.T) { | ||||||
| 	return func(warnings []v1beta1.ExpressionWarning, t *testing.T) { | 	return func(warnings []v1.ExpressionWarning, t *testing.T) { | ||||||
| 		got := len(warnings) | 		got := len(warnings) | ||||||
| 		if expected != got { | 		if expected != got { | ||||||
| 			t.Errorf("expect warnings to have length of %d, but got %d", expected, got) | 			t.Errorf("expect warnings to have length of %d, but got %d", expected, got) | ||||||
| @@ -621,8 +621,8 @@ func toHaveLengthOf(expected int) func(warnings []v1beta1.ExpressionWarning, t * | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func toHaveFieldRef(paths ...string) func(warnings []v1beta1.ExpressionWarning, t *testing.T) { | func toHaveFieldRef(paths ...string) func(warnings []v1.ExpressionWarning, t *testing.T) { | ||||||
| 	return func(warnings []v1beta1.ExpressionWarning, t *testing.T) { | 	return func(warnings []v1.ExpressionWarning, t *testing.T) { | ||||||
| 		if len(paths) != len(warnings) { | 		if len(paths) != len(warnings) { | ||||||
| 			t.Errorf("expect warnings to have length of %d, but got %d", len(paths), len(warnings)) | 			t.Errorf("expect warnings to have length of %d, but got %d", len(paths), len(warnings)) | ||||||
| 		} | 		} | ||||||
| @@ -634,4 +634,4 @@ func toHaveFieldRef(paths ...string) func(warnings []v1beta1.ExpressionWarning, | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| type assertionFunc func(warnings []v1beta1.ExpressionWarning, t *testing.T) | type assertionFunc func(warnings []v1.ExpressionWarning, t *testing.T) | ||||||
|   | |||||||
| @@ -101,7 +101,10 @@ const ( | |||||||
| 	// owner: @cici37 @jpbetz | 	// owner: @cici37 @jpbetz | ||||||
| 	// kep: http://kep.k8s.io/3488 | 	// kep: http://kep.k8s.io/3488 | ||||||
| 	// alpha: v1.26 | 	// alpha: v1.26 | ||||||
|  | 	// beta: v1.28 | ||||||
|  | 	// stable: v1.30 | ||||||
| 	// | 	// | ||||||
|  | 	// Note: the feature gate can be removed in 1.32 | ||||||
| 	// Enables expression validation in Admission Control | 	// Enables expression validation in Admission Control | ||||||
| 	ValidatingAdmissionPolicy featuregate.Feature = "ValidatingAdmissionPolicy" | 	ValidatingAdmissionPolicy featuregate.Feature = "ValidatingAdmissionPolicy" | ||||||
|  |  | ||||||
| @@ -309,7 +312,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS | |||||||
|  |  | ||||||
| 	APIServingWithRoutine: {Default: true, PreRelease: featuregate.Beta}, | 	APIServingWithRoutine: {Default: true, PreRelease: featuregate.Beta}, | ||||||
|  |  | ||||||
| 	ValidatingAdmissionPolicy: {Default: false, PreRelease: featuregate.Beta}, | 	ValidatingAdmissionPolicy: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32 | ||||||
|  |  | ||||||
| 	CustomResourceValidationExpressions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31 | 	CustomResourceValidationExpressions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,12 +19,14 @@ package options | |||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/spf13/pflag" | 	"github.com/spf13/pflag" | ||||||
|  |  | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	utilruntime "k8s.io/apimachinery/pkg/util/runtime" | 	utilruntime "k8s.io/apimachinery/pkg/util/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/util/sets" | 	"k8s.io/apimachinery/pkg/util/sets" | ||||||
|  | 	utilwait "k8s.io/apimachinery/pkg/util/wait" | ||||||
| 	"k8s.io/apiserver/pkg/admission" | 	"k8s.io/apiserver/pkg/admission" | ||||||
| 	"k8s.io/apiserver/pkg/admission/initializer" | 	"k8s.io/apiserver/pkg/admission/initializer" | ||||||
| 	admissionmetrics "k8s.io/apiserver/pkg/admission/metrics" | 	admissionmetrics "k8s.io/apiserver/pkg/admission/metrics" | ||||||
| @@ -36,9 +38,11 @@ import ( | |||||||
| 	apiserverapiv1 "k8s.io/apiserver/pkg/apis/apiserver/v1" | 	apiserverapiv1 "k8s.io/apiserver/pkg/apis/apiserver/v1" | ||||||
| 	apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" | 	apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" | ||||||
| 	"k8s.io/apiserver/pkg/server" | 	"k8s.io/apiserver/pkg/server" | ||||||
|  | 	cacheddiscovery "k8s.io/client-go/discovery/cached/memory" | ||||||
| 	"k8s.io/client-go/dynamic" | 	"k8s.io/client-go/dynamic" | ||||||
| 	"k8s.io/client-go/informers" | 	"k8s.io/client-go/informers" | ||||||
| 	"k8s.io/client-go/kubernetes" | 	"k8s.io/client-go/kubernetes" | ||||||
|  | 	"k8s.io/client-go/restmapper" | ||||||
| 	"k8s.io/component-base/featuregate" | 	"k8s.io/component-base/featuregate" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -143,11 +147,24 @@ func (a *AdmissionOptions) ApplyTo( | |||||||
| 		return fmt.Errorf("failed to read plugin config: %v", err) | 		return fmt.Errorf("failed to read plugin config: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery()) | ||||||
|  | 	discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) | ||||||
| 	genericInitializer := initializer.New(kubeClient, dynamicClient, informers, c.Authorization.Authorizer, features, | 	genericInitializer := initializer.New(kubeClient, dynamicClient, informers, c.Authorization.Authorizer, features, | ||||||
| 		c.DrainedNotify()) | 		c.DrainedNotify(), discoveryRESTMapper) | ||||||
| 	initializersChain := admission.PluginInitializers{genericInitializer} | 	initializersChain := admission.PluginInitializers{genericInitializer} | ||||||
| 	initializersChain = append(initializersChain, pluginInitializers...) | 	initializersChain = append(initializersChain, pluginInitializers...) | ||||||
|  |  | ||||||
|  | 	admissionPostStartHook := func(context server.PostStartHookContext) error { | ||||||
|  | 		discoveryRESTMapper.Reset() | ||||||
|  | 		go utilwait.Until(discoveryRESTMapper.Reset, 30*time.Second, context.StopCh) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = c.AddPostStartHook("start-apiserver-admission-initializer", admissionPostStartHook) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("failed to add post start hook for policy admission: %w", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, a.Decorators) | 	admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, a.Decorators) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
|   | |||||||
| @@ -37,7 +37,7 @@ var ( | |||||||
| 		"[+]ping ok", | 		"[+]ping ok", | ||||||
| 		"[+]log ok", | 		"[+]log ok", | ||||||
| 		"[+]etcd ok", | 		"[+]etcd ok", | ||||||
| 		"[+]poststarthook/start-kube-apiserver-admission-initializer ok", | 		"[+]poststarthook/start-apiserver-admission-initializer ok", | ||||||
| 		"[+]poststarthook/generic-apiserver-start-informers ok", | 		"[+]poststarthook/generic-apiserver-start-informers ok", | ||||||
| 		"[+]poststarthook/start-apiextensions-informers ok", | 		"[+]poststarthook/start-apiextensions-informers ok", | ||||||
| 		"[+]poststarthook/start-apiextensions-controllers ok", | 		"[+]poststarthook/start-apiextensions-controllers ok", | ||||||
| @@ -58,7 +58,7 @@ var ( | |||||||
| 		"[+]ping ok", | 		"[+]ping ok", | ||||||
| 		"[+]log ok", | 		"[+]log ok", | ||||||
| 		"[+]etcd ok", | 		"[+]etcd ok", | ||||||
| 		"[+]poststarthook/start-kube-apiserver-admission-initializer ok", | 		"[+]poststarthook/start-apiserver-admission-initializer ok", | ||||||
| 		"[+]poststarthook/generic-apiserver-start-informers ok", | 		"[+]poststarthook/generic-apiserver-start-informers ok", | ||||||
| 		"[+]poststarthook/start-apiextensions-informers ok", | 		"[+]poststarthook/start-apiextensions-informers ok", | ||||||
| 		"[+]poststarthook/start-apiextensions-controllers ok", | 		"[+]poststarthook/start-apiextensions-controllers ok", | ||||||
| @@ -80,7 +80,7 @@ var ( | |||||||
| 		"[+]log ok", | 		"[+]log ok", | ||||||
| 		"[+]etcd ok", | 		"[+]etcd ok", | ||||||
| 		"[+]informer-sync ok", | 		"[+]informer-sync ok", | ||||||
| 		"[+]poststarthook/start-kube-apiserver-admission-initializer ok", | 		"[+]poststarthook/start-apiserver-admission-initializer ok", | ||||||
| 		"[+]poststarthook/generic-apiserver-start-informers ok", | 		"[+]poststarthook/generic-apiserver-start-informers ok", | ||||||
| 		"[+]poststarthook/start-apiextensions-informers ok", | 		"[+]poststarthook/start-apiextensions-informers ok", | ||||||
| 		"[+]poststarthook/start-apiextensions-controllers ok", | 		"[+]poststarthook/start-apiextensions-controllers ok", | ||||||
|   | |||||||
| @@ -18,14 +18,12 @@ package apimachinery | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" |  | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/onsi/ginkgo/v2" | 	"github.com/onsi/ginkgo/v2" | ||||||
| 	"github.com/onsi/gomega" | 	"github.com/onsi/gomega" | ||||||
|  |  | ||||||
| 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1" | 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1" | ||||||
| 	admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" |  | ||||||
| 	appsv1 "k8s.io/api/apps/v1" | 	appsv1 "k8s.io/api/apps/v1" | ||||||
| 	v1 "k8s.io/api/core/v1" | 	v1 "k8s.io/api/core/v1" | ||||||
| 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" | 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" | ||||||
| @@ -52,11 +50,6 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 		var err error | 		var err error | ||||||
| 		client, err = clientset.NewForConfig(f.ClientConfig()) | 		client, err = clientset.NewForConfig(f.ClientConfig()) | ||||||
| 		framework.ExpectNoError(err, "initializing client") | 		framework.ExpectNoError(err, "initializing client") | ||||||
| 		_, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().List(context.Background(), metav1.ListOptions{}) |  | ||||||
| 		if apierrors.IsNotFound(err) { |  | ||||||
| 			// TODO: feature check should fail after GA graduation |  | ||||||
| 			ginkgo.Skip(fmt.Sprintf("server does not support ValidatingAdmissionPolicy v1beta1: %v, feature gate not enabled?", err)) |  | ||||||
| 		} |  | ||||||
| 		extensionsClient, err = apiextensionsclientset.NewForConfig(f.ClientConfig()) | 		extensionsClient, err = apiextensionsclientset.NewForConfig(f.ClientConfig()) | ||||||
| 		framework.ExpectNoError(err, "initializing api-extensions client") | 		framework.ExpectNoError(err, "initializing api-extensions client") | ||||||
| 	}) | 	}) | ||||||
| @@ -76,25 +69,25 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 				StartResourceRule(). | 				StartResourceRule(). | ||||||
| 				MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). | 				MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). | ||||||
| 				EndResourceRule(). | 				EndResourceRule(). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression:        "object.spec.replicas > 1", | 					Expression:        "object.spec.replicas > 1", | ||||||
| 					MessageExpression: "'wants replicas > 1, got ' + object.spec.replicas", | 					MessageExpression: "'wants replicas > 1, got ' + object.spec.replicas", | ||||||
| 				}). | 				}). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression: "namespaceObject.metadata.name == '" + f.UniqueName + "'", | 					Expression: "namespaceObject.metadata.name == '" + f.UniqueName + "'", | ||||||
| 					Message:    "Internal error! Other namespace should not be allowed.", | 					Message:    "Internal error! Other namespace should not be allowed.", | ||||||
| 				}). | 				}). | ||||||
| 				Build() | 				Build() | ||||||
| 			policy, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | 			policy, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | ||||||
| 			framework.ExpectNoError(err, "create policy") | 			framework.ExpectNoError(err, "create policy") | ||||||
| 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | ||||||
| 				return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | 				return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | ||||||
| 			}, policy.Name) | 			}, policy.Name) | ||||||
| 			binding := createBinding(f.UniqueName+".binding.example.com", f.UniqueName, policy.Name) | 			binding := createBinding(f.UniqueName+".binding.example.com", f.UniqueName, policy.Name) | ||||||
| 			binding, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Create(ctx, binding, metav1.CreateOptions{}) | 			binding, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Create(ctx, binding, metav1.CreateOptions{}) | ||||||
| 			framework.ExpectNoError(err, "create policy binding") | 			framework.ExpectNoError(err, "create policy binding") | ||||||
| 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | ||||||
| 				return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Delete(ctx, name, metav1.DeleteOptions{}) | 				return client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Delete(ctx, name, metav1.DeleteOptions{}) | ||||||
| 			}, binding.Name) | 			}, binding.Name) | ||||||
| 		}) | 		}) | ||||||
| 		ginkgo.By("waiting until the marker is denied", func() { | 		ginkgo.By("waiting until the marker is denied", func() { | ||||||
| @@ -127,27 +120,27 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	ginkgo.It("should type check validation expressions", func(ctx context.Context) { | 	ginkgo.It("should type check validation expressions", func(ctx context.Context) { | ||||||
| 		var policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy | 		var policy *admissionregistrationv1.ValidatingAdmissionPolicy | ||||||
| 		ginkgo.By("creating the policy with correct types", func() { | 		ginkgo.By("creating the policy with correct types", func() { | ||||||
| 			policy = newValidatingAdmissionPolicyBuilder(f.UniqueName+".correct-policy.example.com"). | 			policy = newValidatingAdmissionPolicyBuilder(f.UniqueName+".correct-policy.example.com"). | ||||||
| 				MatchUniqueNamespace(f.UniqueName). | 				MatchUniqueNamespace(f.UniqueName). | ||||||
| 				StartResourceRule(). | 				StartResourceRule(). | ||||||
| 				MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). | 				MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). | ||||||
| 				EndResourceRule(). | 				EndResourceRule(). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression: "object.spec.replicas > 1", | 					Expression: "object.spec.replicas > 1", | ||||||
| 				}). | 				}). | ||||||
| 				Build() | 				Build() | ||||||
| 			var err error | 			var err error | ||||||
| 			policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | 			policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | ||||||
| 			framework.ExpectNoError(err, "create policy") | 			framework.ExpectNoError(err, "create policy") | ||||||
| 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | ||||||
| 				return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | 				return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | ||||||
| 			}, policy.Name) | 			}, policy.Name) | ||||||
| 		}) | 		}) | ||||||
| 		ginkgo.By("waiting for the type check to finish without any warnings", func() { | 		ginkgo.By("waiting for the type check to finish without any warnings", func() { | ||||||
| 			err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { | 			err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { | ||||||
| 				policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) | 				policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					return false, err | 					return false, err | ||||||
| 				} | 				} | ||||||
| @@ -165,21 +158,21 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 				StartResourceRule(). | 				StartResourceRule(). | ||||||
| 				MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). | 				MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). | ||||||
| 				EndResourceRule(). | 				EndResourceRule(). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression:        "object.spec.replicas > '1'",                        // confusion: int > string | 					Expression:        "object.spec.replicas > '1'",                        // confusion: int > string | ||||||
| 					MessageExpression: "'wants replicas > 1, got ' + object.spec.replicas", // confusion: string + int | 					MessageExpression: "'wants replicas > 1, got ' + object.spec.replicas", // confusion: string + int | ||||||
| 				}). | 				}). | ||||||
| 				Build() | 				Build() | ||||||
| 			var err error | 			var err error | ||||||
| 			policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | 			policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | ||||||
| 			framework.ExpectNoError(err, "create policy") | 			framework.ExpectNoError(err, "create policy") | ||||||
| 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | ||||||
| 				return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | 				return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | ||||||
| 			}, policy.Name) | 			}, policy.Name) | ||||||
| 		}) | 		}) | ||||||
| 		ginkgo.By("waiting for the type check to finish with warnings", func() { | 		ginkgo.By("waiting for the type check to finish with warnings", func() { | ||||||
| 			err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { | 			err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { | ||||||
| 				policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) | 				policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					return false, err | 					return false, err | ||||||
| 				} | 				} | ||||||
| @@ -208,31 +201,31 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 				StartResourceRule(). | 				StartResourceRule(). | ||||||
| 				MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). | 				MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). | ||||||
| 				EndResourceRule(). | 				EndResourceRule(). | ||||||
| 				WithVariable(admissionregistrationv1beta1.Variable{ | 				WithVariable(admissionregistrationv1.Variable{ | ||||||
| 					Name:       "replicas", | 					Name:       "replicas", | ||||||
| 					Expression: "object.spec.replicas", | 					Expression: "object.spec.replicas", | ||||||
| 				}). | 				}). | ||||||
| 				WithVariable(admissionregistrationv1beta1.Variable{ | 				WithVariable(admissionregistrationv1.Variable{ | ||||||
| 					Name:       "oddReplicas", | 					Name:       "oddReplicas", | ||||||
| 					Expression: "variables.replicas % 2 == 1", | 					Expression: "variables.replicas % 2 == 1", | ||||||
| 				}). | 				}). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression: "variables.replicas > 1", | 					Expression: "variables.replicas > 1", | ||||||
| 				}). | 				}). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression: "variables.oddReplicas", | 					Expression: "variables.oddReplicas", | ||||||
| 				}). | 				}). | ||||||
| 				Build() | 				Build() | ||||||
| 			policy, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | 			policy, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | ||||||
| 			framework.ExpectNoError(err, "create policy") | 			framework.ExpectNoError(err, "create policy") | ||||||
| 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | ||||||
| 				return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | 				return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | ||||||
| 			}, policy.Name) | 			}, policy.Name) | ||||||
| 			binding := createBinding(f.UniqueName+".binding.example.com", f.UniqueName, policy.Name) | 			binding := createBinding(f.UniqueName+".binding.example.com", f.UniqueName, policy.Name) | ||||||
| 			binding, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Create(ctx, binding, metav1.CreateOptions{}) | 			binding, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Create(ctx, binding, metav1.CreateOptions{}) | ||||||
| 			framework.ExpectNoError(err, "create policy binding") | 			framework.ExpectNoError(err, "create policy binding") | ||||||
| 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | ||||||
| 				return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Delete(ctx, name, metav1.DeleteOptions{}) | 				return client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Delete(ctx, name, metav1.DeleteOptions{}) | ||||||
| 			}, binding.Name) | 			}, binding.Name) | ||||||
| 		}) | 		}) | ||||||
| 		ginkgo.By("waiting until the marker is denied", func() { | 		ginkgo.By("waiting until the marker is denied", func() { | ||||||
| @@ -268,7 +261,7 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 		crd := crontabExampleCRD() | 		crd := crontabExampleCRD() | ||||||
| 		crd.Spec.Group = "stable." + f.UniqueName | 		crd.Spec.Group = "stable." + f.UniqueName | ||||||
| 		crd.Name = crd.Spec.Names.Plural + "." + crd.Spec.Group | 		crd.Name = crd.Spec.Names.Plural + "." + crd.Spec.Group | ||||||
| 		var policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy | 		var policy *admissionregistrationv1.ValidatingAdmissionPolicy | ||||||
| 		ginkgo.By("creating the CRD", func() { | 		ginkgo.By("creating the CRD", func() { | ||||||
| 			var err error | 			var err error | ||||||
| 			crd, err = extensionsClient.ApiextensionsV1().CustomResourceDefinitions().Create(ctx, crd, metav1.CreateOptions{}) | 			crd, err = extensionsClient.ApiextensionsV1().CustomResourceDefinitions().Create(ctx, crd, metav1.CreateOptions{}) | ||||||
| @@ -290,19 +283,19 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 				StartResourceRule(). | 				StartResourceRule(). | ||||||
| 				MatchResource([]string{crd.Spec.Group}, []string{"v1"}, []string{"crontabs"}). | 				MatchResource([]string{crd.Spec.Group}, []string{"v1"}, []string{"crontabs"}). | ||||||
| 				EndResourceRule(). | 				EndResourceRule(). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression: "object.spec.replicas > 1", | 					Expression: "object.spec.replicas > 1", | ||||||
| 				}). | 				}). | ||||||
| 				Build() | 				Build() | ||||||
| 			policy, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | 			policy, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | ||||||
| 			framework.ExpectNoError(err, "create policy") | 			framework.ExpectNoError(err, "create policy") | ||||||
| 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | ||||||
| 				return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | 				return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | ||||||
| 			}, policy.Name) | 			}, policy.Name) | ||||||
| 		}) | 		}) | ||||||
| 		ginkgo.By("waiting for the type check to finish without warnings", func() { | 		ginkgo.By("waiting for the type check to finish without warnings", func() { | ||||||
| 			err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { | 			err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { | ||||||
| 				policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) | 				policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					return false, err | 					return false, err | ||||||
| 				} | 				} | ||||||
| @@ -320,22 +313,22 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 				StartResourceRule(). | 				StartResourceRule(). | ||||||
| 				MatchResource([]string{crd.Spec.Group}, []string{"v1"}, []string{"crontabs"}). | 				MatchResource([]string{crd.Spec.Group}, []string{"v1"}, []string{"crontabs"}). | ||||||
| 				EndResourceRule(). | 				EndResourceRule(). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression: "object.spec.replicas > '1'", // type confusion | 					Expression: "object.spec.replicas > '1'", // type confusion | ||||||
| 				}). | 				}). | ||||||
| 				WithValidation(admissionregistrationv1beta1.Validation{ | 				WithValidation(admissionregistrationv1.Validation{ | ||||||
| 					Expression: "object.spec.maxRetries < 10", // not yet existing field | 					Expression: "object.spec.maxRetries < 10", // not yet existing field | ||||||
| 				}). | 				}). | ||||||
| 				Build() | 				Build() | ||||||
| 			policy, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | 			policy, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) | ||||||
| 			framework.ExpectNoError(err, "create policy") | 			framework.ExpectNoError(err, "create policy") | ||||||
| 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | 			ginkgo.DeferCleanup(func(ctx context.Context, name string) error { | ||||||
| 				return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | 				return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) | ||||||
| 			}, policy.Name) | 			}, policy.Name) | ||||||
| 		}) | 		}) | ||||||
| 		ginkgo.By("waiting for the type check to finish with warnings", func() { | 		ginkgo.By("waiting for the type check to finish with warnings", func() { | ||||||
| 			err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { | 			err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { | ||||||
| 				policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) | 				policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					return false, err | 					return false, err | ||||||
| 				} | 				} | ||||||
| @@ -357,17 +350,17 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame | |||||||
| 	}) | 	}) | ||||||
| }) | }) | ||||||
|  |  | ||||||
| func createBinding(bindingName string, uniqueLabel string, policyName string) *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding { | func createBinding(bindingName string, uniqueLabel string, policyName string) *admissionregistrationv1.ValidatingAdmissionPolicyBinding { | ||||||
| 	return &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{ | 	return &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{Name: bindingName}, | 		ObjectMeta: metav1.ObjectMeta{Name: bindingName}, | ||||||
| 		Spec: admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec{ | 		Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ | ||||||
| 			PolicyName: policyName, | 			PolicyName: policyName, | ||||||
| 			MatchResources: &admissionregistrationv1beta1.MatchResources{ | 			MatchResources: &admissionregistrationv1.MatchResources{ | ||||||
| 				NamespaceSelector: &metav1.LabelSelector{ | 				NamespaceSelector: &metav1.LabelSelector{ | ||||||
| 					MatchLabels: map[string]string{uniqueLabel: "true"}, | 					MatchLabels: map[string]string{uniqueLabel: "true"}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 			ValidationActions: []admissionregistrationv1beta1.ValidationAction{admissionregistrationv1beta1.Deny}, | 			ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -427,17 +420,17 @@ func basicReplicaSet(name string, replicas int32) *appsv1.ReplicaSet { | |||||||
| } | } | ||||||
|  |  | ||||||
| type validatingAdmissionPolicyBuilder struct { | type validatingAdmissionPolicyBuilder struct { | ||||||
| 	policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy | 	policy *admissionregistrationv1.ValidatingAdmissionPolicy | ||||||
| } | } | ||||||
|  |  | ||||||
| type resourceRuleBuilder struct { | type resourceRuleBuilder struct { | ||||||
| 	policyBuilder *validatingAdmissionPolicyBuilder | 	policyBuilder *validatingAdmissionPolicyBuilder | ||||||
| 	resourceRule  *admissionregistrationv1beta1.NamedRuleWithOperations | 	resourceRule  *admissionregistrationv1.NamedRuleWithOperations | ||||||
| } | } | ||||||
|  |  | ||||||
| func newValidatingAdmissionPolicyBuilder(policyName string) *validatingAdmissionPolicyBuilder { | func newValidatingAdmissionPolicyBuilder(policyName string) *validatingAdmissionPolicyBuilder { | ||||||
| 	return &validatingAdmissionPolicyBuilder{ | 	return &validatingAdmissionPolicyBuilder{ | ||||||
| 		policy: &admissionregistrationv1beta1.ValidatingAdmissionPolicy{ | 		policy: &admissionregistrationv1.ValidatingAdmissionPolicy{ | ||||||
| 			ObjectMeta: metav1.ObjectMeta{Name: policyName}, | 			ObjectMeta: metav1.ObjectMeta{Name: policyName}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| @@ -445,7 +438,7 @@ func newValidatingAdmissionPolicyBuilder(policyName string) *validatingAdmission | |||||||
|  |  | ||||||
| func (b *validatingAdmissionPolicyBuilder) MatchUniqueNamespace(uniqueLabel string) *validatingAdmissionPolicyBuilder { | func (b *validatingAdmissionPolicyBuilder) MatchUniqueNamespace(uniqueLabel string) *validatingAdmissionPolicyBuilder { | ||||||
| 	if b.policy.Spec.MatchConstraints == nil { | 	if b.policy.Spec.MatchConstraints == nil { | ||||||
| 		b.policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{} | 		b.policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{} | ||||||
| 	} | 	} | ||||||
| 	b.policy.Spec.MatchConstraints.NamespaceSelector = &metav1.LabelSelector{ | 	b.policy.Spec.MatchConstraints.NamespaceSelector = &metav1.LabelSelector{ | ||||||
| 		MatchLabels: map[string]string{ | 		MatchLabels: map[string]string{ | ||||||
| @@ -458,10 +451,10 @@ func (b *validatingAdmissionPolicyBuilder) MatchUniqueNamespace(uniqueLabel stri | |||||||
| func (b *validatingAdmissionPolicyBuilder) StartResourceRule() *resourceRuleBuilder { | func (b *validatingAdmissionPolicyBuilder) StartResourceRule() *resourceRuleBuilder { | ||||||
| 	return &resourceRuleBuilder{ | 	return &resourceRuleBuilder{ | ||||||
| 		policyBuilder: b, | 		policyBuilder: b, | ||||||
| 		resourceRule: &admissionregistrationv1beta1.NamedRuleWithOperations{ | 		resourceRule: &admissionregistrationv1.NamedRuleWithOperations{ | ||||||
| 			RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ | 			RuleWithOperations: admissionregistrationv1.RuleWithOperations{ | ||||||
| 				Operations: []admissionregistrationv1.OperationType{admissionregistrationv1.Create, admissionregistrationv1.Update}, | 				Operations: []admissionregistrationv1.OperationType{admissionregistrationv1.Create, admissionregistrationv1.Update}, | ||||||
| 				Rule: admissionregistrationv1beta1.Rule{ | 				Rule: admissionregistrationv1.Rule{ | ||||||
| 					APIGroups:   []string{"apps"}, | 					APIGroups:   []string{"apps"}, | ||||||
| 					APIVersions: []string{"v1"}, | 					APIVersions: []string{"v1"}, | ||||||
| 					Resources:   []string{"deployments"}, | 					Resources:   []string{"deployments"}, | ||||||
| @@ -477,7 +470,7 @@ func (rb *resourceRuleBuilder) CreateAndUpdate() *resourceRuleBuilder { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (rb *resourceRuleBuilder) MatchResource(groups []string, versions []string, resources []string) *resourceRuleBuilder { | func (rb *resourceRuleBuilder) MatchResource(groups []string, versions []string, resources []string) *resourceRuleBuilder { | ||||||
| 	rb.resourceRule.Rule = admissionregistrationv1beta1.Rule{ | 	rb.resourceRule.Rule = admissionregistrationv1.Rule{ | ||||||
| 		APIGroups:   groups, | 		APIGroups:   groups, | ||||||
| 		APIVersions: versions, | 		APIVersions: versions, | ||||||
| 		Resources:   resources, | 		Resources:   resources, | ||||||
| @@ -488,23 +481,23 @@ func (rb *resourceRuleBuilder) MatchResource(groups []string, versions []string, | |||||||
| func (rb *resourceRuleBuilder) EndResourceRule() *validatingAdmissionPolicyBuilder { | func (rb *resourceRuleBuilder) EndResourceRule() *validatingAdmissionPolicyBuilder { | ||||||
| 	b := rb.policyBuilder | 	b := rb.policyBuilder | ||||||
| 	if b.policy.Spec.MatchConstraints == nil { | 	if b.policy.Spec.MatchConstraints == nil { | ||||||
| 		b.policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{} | 		b.policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{} | ||||||
| 	} | 	} | ||||||
| 	b.policy.Spec.MatchConstraints.ResourceRules = append(b.policy.Spec.MatchConstraints.ResourceRules, *rb.resourceRule) | 	b.policy.Spec.MatchConstraints.ResourceRules = append(b.policy.Spec.MatchConstraints.ResourceRules, *rb.resourceRule) | ||||||
| 	return b | 	return b | ||||||
| } | } | ||||||
|  |  | ||||||
| func (b *validatingAdmissionPolicyBuilder) WithValidation(validation admissionregistrationv1beta1.Validation) *validatingAdmissionPolicyBuilder { | func (b *validatingAdmissionPolicyBuilder) WithValidation(validation admissionregistrationv1.Validation) *validatingAdmissionPolicyBuilder { | ||||||
| 	b.policy.Spec.Validations = append(b.policy.Spec.Validations, validation) | 	b.policy.Spec.Validations = append(b.policy.Spec.Validations, validation) | ||||||
| 	return b | 	return b | ||||||
| } | } | ||||||
|  |  | ||||||
| func (b *validatingAdmissionPolicyBuilder) WithVariable(variable admissionregistrationv1beta1.Variable) *validatingAdmissionPolicyBuilder { | func (b *validatingAdmissionPolicyBuilder) WithVariable(variable admissionregistrationv1.Variable) *validatingAdmissionPolicyBuilder { | ||||||
| 	b.policy.Spec.Variables = append(b.policy.Spec.Variables, variable) | 	b.policy.Spec.Variables = append(b.policy.Spec.Variables, variable) | ||||||
| 	return b | 	return b | ||||||
| } | } | ||||||
|  |  | ||||||
| func (b *validatingAdmissionPolicyBuilder) Build() *admissionregistrationv1beta1.ValidatingAdmissionPolicy { | func (b *validatingAdmissionPolicyBuilder) Build() *admissionregistrationv1.ValidatingAdmissionPolicy { | ||||||
| 	return b.policy | 	return b.policy | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -145,6 +145,9 @@ var ( | |||||||
| 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):         true, | 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):         true, | ||||||
| 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies/status"):  true, | 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies/status"):  true, | ||||||
| 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"):   true, | 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"):   true, | ||||||
|  | 		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"):              true, | ||||||
|  | 		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies/status"):       true, | ||||||
|  | 		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"):        true, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	parentResources = map[schema.GroupVersionResource]schema.GroupVersionResource{ | 	parentResources = map[schema.GroupVersionResource]schema.GroupVersionResource{ | ||||||
|   | |||||||
| @@ -65,6 +65,7 @@ var resetFieldsStatusData = map[schema.GroupVersionResource]string{ | |||||||
| 	// standard for []metav1.Condition | 	// standard for []metav1.Condition | ||||||
| 	gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | 	gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | ||||||
| 	gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):  `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | 	gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):  `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | ||||||
|  | 	gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"):       `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | ||||||
| 	gvr("networking.k8s.io", "v1alpha1", "servicecidrs"):                           `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | 	gvr("networking.k8s.io", "v1alpha1", "servicecidrs"):                           `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -156,6 +157,7 @@ var resetFieldsSpecData = map[schema.GroupVersionResource]string{ | |||||||
| 	gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"):                `{}`, | 	gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"):                `{}`, | ||||||
| 	gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`, | 	gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`, | ||||||
| 	gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):  `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`, | 	gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):  `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`, | ||||||
|  | 	gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"):       `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`, | ||||||
| } | } | ||||||
|  |  | ||||||
| // TestResetFields makes sure that fieldManager does not own fields reset by the storage strategy. | // TestResetFields makes sure that fieldManager does not own fields reset by the storage strategy. | ||||||
|   | |||||||
| @@ -58,6 +58,7 @@ var statusData = map[schema.GroupVersionResource]string{ | |||||||
| 	// standard for []metav1.Condition | 	// standard for []metav1.Condition | ||||||
| 	gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | 	gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | ||||||
| 	gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):  `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | 	gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):  `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | ||||||
|  | 	gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"):       `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, | ||||||
| } | } | ||||||
|  |  | ||||||
| const statusDefault = `{"status": {"conditions": [{"type": "MyStatus", "status":"True"}]}}` | const statusDefault = `{"status": {"conditions": [{"type": "MyStatus", "status":"True"}]}}` | ||||||
|   | |||||||
| @@ -143,6 +143,9 @@ var ( | |||||||
| 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):         true, | 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"):         true, | ||||||
| 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies/status"):  true, | 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies/status"):  true, | ||||||
| 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"):   true, | 		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"):   true, | ||||||
|  | 		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"):              true, | ||||||
|  | 		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies/status"):       true, | ||||||
|  | 		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"):        true, | ||||||
| 		// transient resource exemption | 		// transient resource exemption | ||||||
| 		gvr("authentication.k8s.io", "v1", "selfsubjectreviews"):       true, | 		gvr("authentication.k8s.io", "v1", "selfsubjectreviews"):       true, | ||||||
| 		gvr("authentication.k8s.io", "v1beta1", "selfsubjectreviews"):  true, | 		gvr("authentication.k8s.io", "v1beta1", "selfsubjectreviews"):  true, | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -339,6 +339,16 @@ func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionRes | |||||||
| 			Stub:             `{"metadata":{"name":"hook2","creationTimestamp":null},"webhooks":[{"name":"externaladmissionhook.k8s.io","clientConfig":{"service":{"namespace":"ns","name":"n"},"caBundle":null},"rules":[{"operations":["CREATE"],"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore","sideEffects":"None","admissionReviewVersions":["v1beta1"]}]}`, | 			Stub:             `{"metadata":{"name":"hook2","creationTimestamp":null},"webhooks":[{"name":"externaladmissionhook.k8s.io","clientConfig":{"service":{"namespace":"ns","name":"n"},"caBundle":null},"rules":[{"operations":["CREATE"],"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore","sideEffects":"None","admissionReviewVersions":["v1beta1"]}]}`, | ||||||
| 			ExpectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook2", | 			ExpectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook2", | ||||||
| 		}, | 		}, | ||||||
|  | 		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): { | ||||||
|  | 			Stub:             `{"metadata":{"name":"vap1","creationTimestamp":null},"spec":{"paramKind":{"apiVersion":"test.example.com/v1","kind":"Example"},"matchConstraints":{"resourceRules": [{"resourceNames": ["fakeName"], "apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE", "UPDATE"], "resources":["deployments"]}]},"validations":[{"expression":"object.spec.replicas <= params.maxReplicas","message":"Too many replicas"}]}}`, | ||||||
|  | 			ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1", | ||||||
|  | 			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"), | ||||||
|  | 		}, | ||||||
|  | 		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"): { | ||||||
|  | 			Stub:             `{"metadata":{"name":"pb1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com","parameterNotFoundAction":"Deny"},"validationActions":["Deny"]}}`, | ||||||
|  | 			ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1", | ||||||
|  | 			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"), | ||||||
|  | 		}, | ||||||
| 		// -- | 		// -- | ||||||
|  |  | ||||||
| 		// k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1 | 		// k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1 | ||||||
| @@ -354,13 +364,13 @@ func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionRes | |||||||
|  |  | ||||||
| 		// k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1 | 		// k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1 | ||||||
| 		gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): { | 		gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): { | ||||||
| 			Stub:             `{"metadata":{"name":"vap1","creationTimestamp":null},"spec":{"paramKind":{"apiVersion":"test.example.com/v1","kind":"Example"},"matchConstraints":{"resourceRules": [{"resourceNames": ["fakeName"], "apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE", "UPDATE"], "resources":["deployments"]}]},"validations":[{"expression":"object.spec.replicas <= params.maxReplicas","message":"Too many replicas"}]}}`, | 			Stub:             `{"metadata":{"name":"vap1a1","creationTimestamp":null},"spec":{"paramKind":{"apiVersion":"test.example.com/v1","kind":"Example"},"matchConstraints":{"resourceRules": [{"resourceNames": ["fakeName"], "apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE", "UPDATE"], "resources":["deployments"]}]},"validations":[{"expression":"object.spec.replicas <= params.maxReplicas","message":"Too many replicas"}]}}`, | ||||||
| 			ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1", | 			ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1a1", | ||||||
| 			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"), | 			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"), | ||||||
| 		}, | 		}, | ||||||
| 		gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): { | 		gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): { | ||||||
| 			Stub:             `{"metadata":{"name":"pb1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com"},"validationActions":["Deny"]}}`, | 			Stub:             `{"metadata":{"name":"pb1a1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com"},"validationActions":["Deny"]}}`, | ||||||
| 			ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1", | 			ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1a1", | ||||||
| 			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"), | 			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"), | ||||||
| 		}, | 		}, | ||||||
| 		// -- | 		// -- | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 cici37
					cici37