diff --git a/tools/testing/kata-webhook/main.go b/tools/testing/kata-webhook/main.go index 8e040d60df..bdf2fe2a18 100644 --- a/tools/testing/kata-webhook/main.go +++ b/tools/testing/kata-webhook/main.go @@ -10,6 +10,7 @@ import ( "fmt" "net/http" "os" + "regexp" "strings" corev1 "k8s.io/api/core/v1" @@ -44,6 +45,11 @@ func annotatePodMutator(_ context.Context, ar *kwhmodel.AdmissionReview, obj met fmt.Println("blacklisted namespace: ", ar.Namespace) return &kwhmutating.MutatorResult{}, nil } + // Check if we are only mutating pods in specific namespaces using the regular expression. + if whPolicy.nsOnlyRegexp != nil && !whPolicy.nsOnlyRegexp.MatchString(ar.Namespace) { + fmt.Println("namespace doesn't match re-only-namespaces: ", ar.Namespace) + return &kwhmutating.MutatorResult{}, nil + } // We cannot support --net=host in Kata // https://github.com/kata-containers/documentation/blob/master/Limitations.md#docker---nethost @@ -84,13 +90,15 @@ func annotatePodMutator(_ context.Context, ar *kwhmodel.AdmissionReview, obj met } type config struct { - certFile string - keyFile string - nsBlacklist string + certFile string + keyFile string + nsBlacklist string + nsOnlyRegexp string } type policy struct { - nsBlacklist map[string]bool + nsBlacklist map[string]bool + nsOnlyRegexp *regexp.Regexp } var whPolicy *policy @@ -102,6 +110,7 @@ func initFlags() *config { fl.StringVar(&cfg.certFile, "tls-cert-file", "", "TLS certificate file") fl.StringVar(&cfg.keyFile, "tls-key-file", "", "TLS key file") fl.StringVar(&cfg.nsBlacklist, "exclude-namespaces", "", "Comma separated namespace blacklist") + fl.StringVar(&cfg.nsOnlyRegexp, "only-namespaces-regexp", "", "Regexp namespace filter applied after --exclude-namespaces") fl.Parse(os.Args[1:]) return cfg @@ -122,6 +131,15 @@ func main() { } } + if cfg.nsOnlyRegexp != "" { + var err error + whPolicy.nsOnlyRegexp, err = regexp.Compile(cfg.nsOnlyRegexp) + if err != nil { + fmt.Fprintf(os.Stderr, "error compiling regular expression: %s", err) + os.Exit(1) + } + } + // Create our mutator mt := kwhmutating.MutatorFunc(annotatePodMutator) diff --git a/tools/testing/kata-webhook/main_test.go b/tools/testing/kata-webhook/main_test.go new file mode 100644 index 0000000000..0378f203ad --- /dev/null +++ b/tools/testing/kata-webhook/main_test.go @@ -0,0 +1,60 @@ +// Copyright (c) 2025 Red Hat Inc. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "context" + "regexp" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + kwhmodel "github.com/slok/kubewebhook/v2/pkg/model" +) + +func TestAnnotatePodMutator(t *testing.T) { + tests := []struct { + name string + nsBlacklist map[string]bool + nsOnlyRegexp *regexp.Regexp + wantMutated bool + }{ + {"no filters", nil, nil, true}, + {"matching nsBlacklist", map[string]bool{"testing-namespace": true}, nil, false}, + {"matching nsOnlyRegexp", nil, regexp.MustCompile("^testing-.*$"), true}, + {"nonmatching nsOnlyRegexp", nil, regexp.MustCompile(".*nonexisting.*"), false}, + } + + expectedRuntimeClass := "kata" + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + whPolicy = &policy{nsBlacklist: tt.nsBlacklist, nsOnlyRegexp: tt.nsOnlyRegexp} + + pod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "testing-namespace", + }, + } + + ar := &kwhmodel.AdmissionReview{ + Namespace: "testing-namespace", + } + + result, err := annotatePodMutator(context.Background(), ar, pod) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + mutated := result.MutatedObject != nil && result.MutatedObject.(*corev1.Pod).Spec.RuntimeClassName != nil + if mutated != tt.wantMutated { + t.Errorf("expected mutation: %v, got: %v", tt.wantMutated, mutated) + } + if mutated && *result.MutatedObject.(*corev1.Pod).Spec.RuntimeClassName != expectedRuntimeClass { + t.Errorf("expected runtimeclass: %v, got %v", expectedRuntimeClass, result.MutatedObject.(*corev1.Pod).Spec.RuntimeClassName) + } + }) + } +}