Skip to content

Commit

Permalink
Promote ValidatingAdmissionPolicy to GA.
Browse files Browse the repository at this point in the history
  • Loading branch information
cici37 committed Mar 6, 2024
1 parent 1e4124b commit de506ce
Show file tree
Hide file tree
Showing 52 changed files with 1,568 additions and 766 deletions.
5 changes: 1 addition & 4 deletions cmd/kube-apiserver/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ func CreateKubeAPIServerConfig(opts options.CompletedOptions) (
CloudConfigFile: opts.CloudProvider.CloudConfigFile,
}
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 {
return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err)
}
Expand All @@ -321,9 +321,6 @@ func CreateKubeAPIServerConfig(opts options.CompletedOptions) (
if err != nil {
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 {
// Use the config.GenericConfig.EgressSelector lookup to find the dialer to connect to the kubelet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ func startValidatingAdmissionPolicyStatusController(ctx context.Context, control
RestMapper: controllerContext.RESTMapper,
}
c, err := validatingadmissionpolicystatus.NewController(
controllerContext.InformerFactory.Admissionregistration().V1beta1().ValidatingAdmissionPolicies(),
controllerContext.ClientBuilder.ClientOrDie(names.ValidatingAdmissionPolicyStatusController).AdmissionregistrationV1beta1().ValidatingAdmissionPolicies(),
controllerContext.InformerFactory.Admissionregistration().V1().ValidatingAdmissionPolicies(),
controllerContext.ClientBuilder.ClientOrDie(names.ValidatingAdmissionPolicyStatusController).AdmissionregistrationV1().ValidatingAdmissionPolicies(),
typeChecker,
)

Expand Down
4 changes: 4 additions & 0 deletions pkg/api/testing/defaulting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ func TestDefaulting(t *testing.T) {
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyList"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBinding"}: {},
{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: "ValidatingWebhookConfigurationList"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfiguration"}: {},
Expand Down
24 changes: 24 additions & 0 deletions pkg/apis/admissionregistration/v1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,27 @@ func SetDefaults_ServiceReference(obj *admissionregistrationv1.ServiceReference)
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
}
}
88 changes: 88 additions & 0 deletions pkg/apis/admissionregistration/v1/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
})
}
}
28 changes: 14 additions & 14 deletions pkg/controller/validatingadmissionpolicystatus/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ import (
"fmt"
"time"

"k8s.io/api/admissionregistration/v1beta1"
"k8s.io/api/admissionregistration/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
validatingadmissionpolicy "k8s.io/apiserver/pkg/admission/plugin/policy/validating"
admissionregistrationv1beta1apply "k8s.io/client-go/applyconfigurations/admissionregistration/v1beta1"
informerv1beta1 "k8s.io/client-go/informers/admissionregistration/v1beta1"
admissionregistrationv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1"
admissionregistrationv1apply "k8s.io/client-go/applyconfigurations/admissionregistration/v1"
informerv1 "k8s.io/client-go/informers/admissionregistration/v1"
admissionregistrationv1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
Expand All @@ -40,10 +40,10 @@ const ControllerName = "validatingadmissionpolicy-status"
// 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.
type Controller struct {
policyInformer informerv1beta1.ValidatingAdmissionPolicyInformer
policyInformer informerv1.ValidatingAdmissionPolicyInformer
policyQueue workqueue.RateLimitingInterface
policySynced cache.InformerSynced
policyClient admissionregistrationv1beta1.ValidatingAdmissionPolicyInterface
policyClient admissionregistrationv1.ValidatingAdmissionPolicyInterface

// typeChecker checks the policy's expressions for type errors.
// Type of params is defined in policy.Spec.ParamsKind
Expand All @@ -66,7 +66,7 @@ func (c *Controller) Run(ctx context.Context, workers int) {
<-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{
policyInformer: policyInformer,
policyQueue: workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: ControllerName}),
Expand All @@ -89,7 +89,7 @@ func NewController(policyInformer informerv1beta1.ValidatingAdmissionPolicyInfor
}

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.
key := policy.ObjectMeta.Name
if key == "" {
Expand Down Expand Up @@ -138,24 +138,24 @@ func (c *Controller) processNextWorkItem(ctx context.Context) bool {
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 {
return nil
}
if policy.Generation <= policy.Status.ObservedGeneration {
return nil
}
warnings := c.typeChecker.Check(policy)
warningsConfig := make([]*admissionregistrationv1beta1apply.ExpressionWarningApplyConfiguration, 0, len(warnings))
warningsConfig := make([]*admissionregistrationv1apply.ExpressionWarningApplyConfiguration, 0, len(warnings))
for _, warning := range warnings {
warningsConfig = append(warningsConfig, admissionregistrationv1beta1apply.ExpressionWarning().
warningsConfig = append(warningsConfig, admissionregistrationv1apply.ExpressionWarning().
WithFieldRef(warning.FieldRef).
WithWarning(warning.Warning))
}
applyConfig := admissionregistrationv1beta1apply.ValidatingAdmissionPolicy(policy.Name).
WithStatus(admissionregistrationv1beta1apply.ValidatingAdmissionPolicyStatus().
applyConfig := admissionregistrationv1apply.ValidatingAdmissionPolicy(policy.Name).
WithStatus(admissionregistrationv1apply.ValidatingAdmissionPolicyStatus().
WithObservedGeneration(policy.Generation).
WithTypeChecking(admissionregistrationv1beta1apply.TypeChecking().
WithTypeChecking(admissionregistrationv1apply.TypeChecking().
WithExpressionWarnings(warningsConfig...)))
_, err := c.policyClient.ApplyStatus(ctx, applyConfig, metav1.ApplyOptions{FieldManager: ControllerName, Force: true})
return err
Expand Down
51 changes: 25 additions & 26 deletions pkg/controller/validatingadmissionpolicystatus/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"time"

admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
Expand All @@ -38,13 +37,13 @@ import (
func TestTypeChecking(t *testing.T) {
for _, tc := range []struct {
name string
policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy
assertFieldRef func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) // warning.fieldRef
assertWarnings func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) // warning.warning
policy *admissionregistrationv1.ValidatingAdmissionPolicy
assertFieldRef func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) // warning.fieldRef
assertWarnings func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) // warning.warning
}{
{
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",
},
Expand All @@ -54,7 +53,7 @@ func TestTypeChecking(t *testing.T) {
},
{
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
},
Expand All @@ -67,7 +66,7 @@ func TestTypeChecking(t *testing.T) {
},
{
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",
},
Expand All @@ -83,7 +82,7 @@ func TestTypeChecking(t *testing.T) {
},
{
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
},
Expand All @@ -107,8 +106,8 @@ func TestTypeChecking(t *testing.T) {
RestMapper: testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme),
}
controller, err := NewController(
informerFactory.Admissionregistration().V1beta1().ValidatingAdmissionPolicies(),
client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies(),
informerFactory.Admissionregistration().V1().ValidatingAdmissionPolicies(),
client.AdmissionregistrationV1().ValidatingAdmissionPolicies(),
typeChecker,
)
if err != nil {
Expand All @@ -120,7 +119,7 @@ func TestTypeChecking(t *testing.T) {
name := policy.Name
// wait until the typeChecking is set, which means the type checking
// 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 {
return false, err
}
Expand All @@ -143,8 +142,8 @@ func TestTypeChecking(t *testing.T) {

}

func toBe(expected ...string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) {
return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) {
func toBe(expected ...string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) {
return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) {
if len(expected) != len(warnings) {
t.Fatalf("mismatched length, expect %d, got %d", len(expected), len(warnings))
}
Expand All @@ -156,8 +155,8 @@ func toBe(expected ...string) func(warnings []admissionregistrationv1beta1.Expre
}
}

func toHaveSubstring(substrings ...string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) {
return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) {
func toHaveSubstring(substrings ...string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) {
return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) {
if len(substrings) != len(warnings) {
t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings))
}
Expand All @@ -169,8 +168,8 @@ func toHaveSubstring(substrings ...string) func(warnings []admissionregistration
}
}

func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) {
return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) {
func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) {
return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) {
if len(substrings) != len(warnings) {
t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings))
}
Expand All @@ -184,19 +183,19 @@ func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionr
}
}

func toHaveLengthOf(n int) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) {
return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) {
func toHaveLengthOf(n int) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) {
return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) {
if 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 {
policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{
ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{
func withGVRMatch(groups []string, versions []string, resources []string, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy {
policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{
ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{
{
RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{
RuleWithOperations: admissionregistrationv1.RuleWithOperations{
Operations: []admissionregistrationv1.OperationType{
"*",
},
Expand All @@ -212,13 +211,13 @@ func withGVRMatch(groups []string, versions []string, resources []string, 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
return policy
}

func makePolicy(name string) *admissionregistrationv1beta1.ValidatingAdmissionPolicy {
return &admissionregistrationv1beta1.ValidatingAdmissionPolicy{
func makePolicy(name string) *admissionregistrationv1.ValidatingAdmissionPolicy {
return &admissionregistrationv1.ValidatingAdmissionPolicy{
ObjectMeta: metav1.ObjectMeta{Name: name},
}
}
Loading

0 comments on commit de506ce

Please sign in to comment.