mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
Add webhook admission conversion test
This commit is contained in:
parent
9469fc0a71
commit
8c194ea615
@ -148,6 +148,15 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type webhookOptions struct {
|
||||||
|
// phase indicates whether this is a mutating or validating webhook
|
||||||
|
phase string
|
||||||
|
// converted indicates if this webhook makes use of matchPolicy:equivalent and expects conversion.
|
||||||
|
// if true, recordGVR and expectGVK are mapped through gvrToConvertedGVR/gvrToConvertedGVK.
|
||||||
|
// if false, recordGVR and expectGVK are compared directly to the admission review.
|
||||||
|
converted bool
|
||||||
|
}
|
||||||
|
|
||||||
type holder struct {
|
type holder struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
|
|
||||||
@ -164,7 +173,14 @@ type holder struct {
|
|||||||
expectOptionsGVK schema.GroupVersionKind
|
expectOptionsGVK schema.GroupVersionKind
|
||||||
expectOptions bool
|
expectOptions bool
|
||||||
|
|
||||||
recorded map[string]*v1beta1.AdmissionRequest
|
// gvrToConvertedGVR maps the GVR submitted to the API server to the expected GVR when converted to the webhook-recognized resource.
|
||||||
|
// When a converted request is recorded, gvrToConvertedGVR[recordGVR] is compared to the GVR seen by the webhook.
|
||||||
|
gvrToConvertedGVR map[metav1.GroupVersionResource]metav1.GroupVersionResource
|
||||||
|
// gvrToConvertedGVR maps the GVR submitted to the API server to the expected GVK when converted to the webhook-recognized resource.
|
||||||
|
// When a converted request is recorded, gvrToConvertedGVR[expectGVK] is compared to the GVK seen by the webhook.
|
||||||
|
gvrToConvertedGVK map[metav1.GroupVersionResource]schema.GroupVersionKind
|
||||||
|
|
||||||
|
recorded map[webhookOptions]*v1beta1.AdmissionRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *holder) reset(t *testing.T) {
|
func (h *holder) reset(t *testing.T) {
|
||||||
@ -180,9 +196,13 @@ func (h *holder) reset(t *testing.T) {
|
|||||||
h.expectOldObject = false
|
h.expectOldObject = false
|
||||||
h.expectOptionsGVK = schema.GroupVersionKind{}
|
h.expectOptionsGVK = schema.GroupVersionKind{}
|
||||||
h.expectOptions = false
|
h.expectOptions = false
|
||||||
h.recorded = map[string]*v1beta1.AdmissionRequest{
|
|
||||||
mutation: nil,
|
// Set up the recorded map with nil records for all combinations
|
||||||
validation: nil,
|
h.recorded = map[webhookOptions]*v1beta1.AdmissionRequest{}
|
||||||
|
for _, phase := range []string{mutation, validation} {
|
||||||
|
for _, converted := range []bool{true, false} {
|
||||||
|
h.recorded[webhookOptions{phase: phase, converted: converted}] = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (h *holder) expect(gvr schema.GroupVersionResource, gvk, optionsGVK schema.GroupVersionKind, operation v1beta1.Operation, name, namespace string, object, oldObject, options bool) {
|
func (h *holder) expect(gvr schema.GroupVersionResource, gvk, optionsGVK schema.GroupVersionKind, operation v1beta1.Operation, name, namespace string, object, oldObject, options bool) {
|
||||||
@ -202,12 +222,16 @@ func (h *holder) expect(gvr schema.GroupVersionResource, gvk, optionsGVK schema.
|
|||||||
h.expectOldObject = oldObject
|
h.expectOldObject = oldObject
|
||||||
h.expectOptionsGVK = optionsGVK
|
h.expectOptionsGVK = optionsGVK
|
||||||
h.expectOptions = options
|
h.expectOptions = options
|
||||||
h.recorded = map[string]*v1beta1.AdmissionRequest{
|
|
||||||
mutation: nil,
|
// Set up the recorded map with nil records for all combinations
|
||||||
validation: nil,
|
h.recorded = map[webhookOptions]*v1beta1.AdmissionRequest{}
|
||||||
|
for _, phase := range []string{mutation, validation} {
|
||||||
|
for _, converted := range []bool{true, false} {
|
||||||
|
h.recorded[webhookOptions{phase: phase, converted: converted}] = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (h *holder) record(phase string, request *v1beta1.AdmissionRequest) {
|
func (h *holder) record(phase string, converted bool, request *v1beta1.AdmissionRequest) {
|
||||||
h.lock.Lock()
|
h.lock.Lock()
|
||||||
defer h.lock.Unlock()
|
defer h.lock.Unlock()
|
||||||
|
|
||||||
@ -221,9 +245,16 @@ func (h *holder) record(phase string, request *v1beta1.AdmissionRequest) {
|
|||||||
if len(request.SubResource) > 0 {
|
if len(request.SubResource) > 0 {
|
||||||
resource.Resource += "/" + request.SubResource
|
resource.Resource += "/" + request.SubResource
|
||||||
}
|
}
|
||||||
if resource != h.recordGVR {
|
|
||||||
|
// See if we should record this
|
||||||
|
gvrToRecord := h.recordGVR
|
||||||
|
if converted {
|
||||||
|
// If this is a converted webhook, map to the GVR we expect the webhook to see
|
||||||
|
gvrToRecord = h.gvrToConvertedGVR[h.recordGVR]
|
||||||
|
}
|
||||||
|
if resource != gvrToRecord {
|
||||||
if debug {
|
if debug {
|
||||||
h.t.Log(resource, "!=", h.recordGVR)
|
h.t.Log(resource, "!=", gvrToRecord)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -252,22 +283,21 @@ func (h *holder) record(phase string, request *v1beta1.AdmissionRequest) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.recorded[phase] = request
|
h.recorded[webhookOptions{phase: phase, converted: converted}] = request
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *holder) verify(t *testing.T) {
|
func (h *holder) verify(t *testing.T) {
|
||||||
h.lock.Lock()
|
h.lock.Lock()
|
||||||
defer h.lock.Unlock()
|
defer h.lock.Unlock()
|
||||||
|
|
||||||
if err := h.verifyRequest(h.recorded[mutation]); err != nil {
|
for options, value := range h.recorded {
|
||||||
t.Errorf("mutation error: %v", err)
|
if err := h.verifyRequest(options.converted, value); err != nil {
|
||||||
}
|
t.Errorf("phase:%v, converted:%v error: %v", options.phase, options.converted, err)
|
||||||
if err := h.verifyRequest(h.recorded[validation]); err != nil {
|
}
|
||||||
t.Errorf("validation error: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *holder) verifyRequest(request *v1beta1.AdmissionRequest) error {
|
func (h *holder) verifyRequest(converted bool, request *v1beta1.AdmissionRequest) error {
|
||||||
// Check if current resource should be exempted from Admission processing
|
// Check if current resource should be exempted from Admission processing
|
||||||
if admissionExemptResources[gvr(h.recordGVR.Group, h.recordGVR.Version, h.recordGVR.Resource)] {
|
if admissionExemptResources[gvr(h.recordGVR.Group, h.recordGVR.Version, h.recordGVR.Resource)] {
|
||||||
if request == nil {
|
if request == nil {
|
||||||
@ -281,7 +311,7 @@ func (h *holder) verifyRequest(request *v1beta1.AdmissionRequest) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if h.expectObject {
|
if h.expectObject {
|
||||||
if err := h.verifyObject(request.Object.Object); err != nil {
|
if err := h.verifyObject(converted, request.Object.Object); err != nil {
|
||||||
return fmt.Errorf("object error: %v", err)
|
return fmt.Errorf("object error: %v", err)
|
||||||
}
|
}
|
||||||
} else if request.Object.Object != nil {
|
} else if request.Object.Object != nil {
|
||||||
@ -289,7 +319,7 @@ func (h *holder) verifyRequest(request *v1beta1.AdmissionRequest) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if h.expectOldObject {
|
if h.expectOldObject {
|
||||||
if err := h.verifyObject(request.OldObject.Object); err != nil {
|
if err := h.verifyObject(converted, request.OldObject.Object); err != nil {
|
||||||
return fmt.Errorf("old object error: %v", err)
|
return fmt.Errorf("old object error: %v", err)
|
||||||
}
|
}
|
||||||
} else if request.OldObject.Object != nil {
|
} else if request.OldObject.Object != nil {
|
||||||
@ -307,12 +337,16 @@ func (h *holder) verifyRequest(request *v1beta1.AdmissionRequest) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *holder) verifyObject(obj runtime.Object) error {
|
func (h *holder) verifyObject(converted bool, obj runtime.Object) error {
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return fmt.Errorf("no object sent")
|
return fmt.Errorf("no object sent")
|
||||||
}
|
}
|
||||||
if obj.GetObjectKind().GroupVersionKind() != h.expectGVK {
|
expectGVK := h.expectGVK
|
||||||
return fmt.Errorf("expected %#v, got %#v", h.expectGVK, obj.GetObjectKind().GroupVersionKind())
|
if converted {
|
||||||
|
expectGVK = h.gvrToConvertedGVK[h.recordGVR]
|
||||||
|
}
|
||||||
|
if obj.GetObjectKind().GroupVersionKind() != expectGVK {
|
||||||
|
return fmt.Errorf("expected %#v, got %#v", expectGVK, obj.GetObjectKind().GroupVersionKind())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -330,7 +364,11 @@ func (h *holder) verifyOptions(options runtime.Object) error {
|
|||||||
// TestWebhookV1beta1 tests communication between API server and webhook process.
|
// TestWebhookV1beta1 tests communication between API server and webhook process.
|
||||||
func TestWebhookV1beta1(t *testing.T) {
|
func TestWebhookV1beta1(t *testing.T) {
|
||||||
// holder communicates expectations to webhooks, and results from webhooks
|
// holder communicates expectations to webhooks, and results from webhooks
|
||||||
holder := &holder{t: t}
|
holder := &holder{
|
||||||
|
t: t,
|
||||||
|
gvrToConvertedGVR: map[metav1.GroupVersionResource]metav1.GroupVersionResource{},
|
||||||
|
gvrToConvertedGVK: map[metav1.GroupVersionResource]schema.GroupVersionKind{},
|
||||||
|
}
|
||||||
|
|
||||||
// set up webhook server
|
// set up webhook server
|
||||||
roots := x509.NewCertPool()
|
roots := x509.NewCertPool()
|
||||||
@ -343,8 +381,10 @@ func TestWebhookV1beta1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
webhookMux := http.NewServeMux()
|
webhookMux := http.NewServeMux()
|
||||||
webhookMux.Handle("/"+mutation, newWebhookHandler(t, holder, mutation))
|
webhookMux.Handle("/"+mutation, newWebhookHandler(t, holder, mutation, false))
|
||||||
webhookMux.Handle("/"+validation, newWebhookHandler(t, holder, validation))
|
webhookMux.Handle("/convert/"+mutation, newWebhookHandler(t, holder, mutation, true))
|
||||||
|
webhookMux.Handle("/"+validation, newWebhookHandler(t, holder, validation, false))
|
||||||
|
webhookMux.Handle("/convert/"+validation, newWebhookHandler(t, holder, validation, true))
|
||||||
webhookServer := httptest.NewUnstartedServer(webhookMux)
|
webhookServer := httptest.NewUnstartedServer(webhookMux)
|
||||||
webhookServer.TLS = &tls.Config{
|
webhookServer.TLS = &tls.Config{
|
||||||
RootCAs: roots,
|
RootCAs: roots,
|
||||||
@ -382,12 +422,6 @@ func TestWebhookV1beta1(t *testing.T) {
|
|||||||
if _, err := client.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testNamespace}}); err != nil {
|
if _, err := client.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testNamespace}}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := createV1beta1MutationWebhook(client, webhookServer.URL+"/"+mutation); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := createV1beta1ValidationWebhook(client, webhookServer.URL+"/"+validation); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gather resources to test
|
// gather resources to test
|
||||||
dynamicClient, err := dynamic.NewForConfig(clientConfig)
|
dynamicClient, err := dynamic.NewForConfig(clientConfig)
|
||||||
@ -445,6 +479,42 @@ func TestWebhookV1beta1(t *testing.T) {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// map unqualified resource names to the fully qualified resource we will expect to be converted to
|
||||||
|
// Note: this only works because there are no overlapping resource names in-process that are not co-located
|
||||||
|
convertedResources := map[string]schema.GroupVersionResource{}
|
||||||
|
// build the webhook rules enumerating the specific group/version/resources we want
|
||||||
|
convertedRules := []admissionv1beta1.RuleWithOperations{}
|
||||||
|
for _, gvr := range gvrsToTest {
|
||||||
|
metaGVR := metav1.GroupVersionResource{Group: gvr.Group, Version: gvr.Version, Resource: gvr.Resource}
|
||||||
|
|
||||||
|
convertedGVR, ok := convertedResources[gvr.Resource]
|
||||||
|
if !ok {
|
||||||
|
// this is the first time we've seen this resource
|
||||||
|
// record the fully qualified resource we expect
|
||||||
|
convertedGVR = gvr
|
||||||
|
convertedResources[gvr.Resource] = gvr
|
||||||
|
// add an admission rule indicating we can receive this version
|
||||||
|
convertedRules = append(convertedRules, admissionv1beta1.RuleWithOperations{
|
||||||
|
Operations: []admissionv1beta1.OperationType{admissionv1beta1.OperationAll},
|
||||||
|
Rule: admissionv1beta1.Rule{APIGroups: []string{gvr.Group}, APIVersions: []string{gvr.Version}, Resources: []string{gvr.Resource}},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// record the expected resource and kind
|
||||||
|
holder.gvrToConvertedGVR[metaGVR] = metav1.GroupVersionResource{Group: convertedGVR.Group, Version: convertedGVR.Version, Resource: convertedGVR.Resource}
|
||||||
|
holder.gvrToConvertedGVK[metaGVR] = schema.GroupVersionKind{Group: resourcesByGVR[convertedGVR].Group, Version: resourcesByGVR[convertedGVR].Version, Kind: resourcesByGVR[convertedGVR].Kind}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createV1beta1MutationWebhook(client, webhookServer.URL+"/"+mutation, webhookServer.URL+"/convert/"+mutation, convertedRules); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := createV1beta1ValidationWebhook(client, webhookServer.URL+"/"+validation, webhookServer.URL+"/convert/"+validation, convertedRules); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the webhook to establish
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
// Test admission on all resources, subresources, and verbs
|
// Test admission on all resources, subresources, and verbs
|
||||||
for _, gvr := range gvrsToTest {
|
for _, gvr := range gvrsToTest {
|
||||||
resource := resourcesByGVR[gvr]
|
resource := resourcesByGVR[gvr]
|
||||||
@ -1043,7 +1113,7 @@ func testNoPruningCustomFancy(c *testContext) {
|
|||||||
// utility methods
|
// utility methods
|
||||||
//
|
//
|
||||||
|
|
||||||
func newWebhookHandler(t *testing.T, holder *holder, phase string) http.Handler {
|
func newWebhookHandler(t *testing.T, holder *holder, phase string, converted bool) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
data, err := ioutil.ReadAll(r.Body)
|
data, err := ioutil.ReadAll(r.Body)
|
||||||
@ -1101,7 +1171,7 @@ func newWebhookHandler(t *testing.T, holder *holder, phase string) http.Handler
|
|||||||
|
|
||||||
if review.Request.UserInfo.Username == testClientUsername {
|
if review.Request.UserInfo.Username == testClientUsername {
|
||||||
// only record requests originating from this integration test's client
|
// only record requests originating from this integration test's client
|
||||||
holder.record(phase, review.Request)
|
holder.record(phase, converted, review.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
review.Response = &v1beta1.AdmissionResponse{
|
review.Response = &v1beta1.AdmissionResponse{
|
||||||
@ -1211,46 +1281,74 @@ func shouldTestResourceVerb(gvr schema.GroupVersionResource, resource metav1.API
|
|||||||
// webhook registration helpers
|
// webhook registration helpers
|
||||||
//
|
//
|
||||||
|
|
||||||
func createV1beta1ValidationWebhook(client clientset.Interface, endpoint string) error {
|
func createV1beta1ValidationWebhook(client clientset.Interface, endpoint, convertedEndpoint string, convertedRules []admissionv1beta1.RuleWithOperations) error {
|
||||||
fail := admissionv1beta1.Fail
|
fail := admissionv1beta1.Fail
|
||||||
|
equivalent := admissionv1beta1.Equivalent
|
||||||
// Attaching Admission webhook to API server
|
// Attaching Admission webhook to API server
|
||||||
_, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&admissionv1beta1.ValidatingWebhookConfiguration{
|
_, err := client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Create(&admissionv1beta1.ValidatingWebhookConfiguration{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "admission.integration.test"},
|
ObjectMeta: metav1.ObjectMeta{Name: "admission.integration.test"},
|
||||||
Webhooks: []admissionv1beta1.Webhook{{
|
Webhooks: []admissionv1beta1.Webhook{
|
||||||
Name: "admission.integration.test",
|
{
|
||||||
ClientConfig: admissionv1beta1.WebhookClientConfig{
|
Name: "admission.integration.test",
|
||||||
URL: &endpoint,
|
ClientConfig: admissionv1beta1.WebhookClientConfig{
|
||||||
CABundle: localhostCert,
|
URL: &endpoint,
|
||||||
|
CABundle: localhostCert,
|
||||||
|
},
|
||||||
|
Rules: []admissionv1beta1.RuleWithOperations{{
|
||||||
|
Operations: []admissionv1beta1.OperationType{admissionv1beta1.OperationAll},
|
||||||
|
Rule: admissionv1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*/*"}},
|
||||||
|
}},
|
||||||
|
FailurePolicy: &fail,
|
||||||
|
AdmissionReviewVersions: []string{"v1beta1"},
|
||||||
},
|
},
|
||||||
Rules: []admissionv1beta1.RuleWithOperations{{
|
{
|
||||||
Operations: []admissionv1beta1.OperationType{admissionv1beta1.OperationAll},
|
Name: "admission.integration.testconversion",
|
||||||
Rule: admissionv1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*/*"}},
|
ClientConfig: admissionv1beta1.WebhookClientConfig{
|
||||||
}},
|
URL: &convertedEndpoint,
|
||||||
FailurePolicy: &fail,
|
CABundle: localhostCert,
|
||||||
AdmissionReviewVersions: []string{"v1beta1"},
|
},
|
||||||
}},
|
Rules: convertedRules,
|
||||||
|
FailurePolicy: &fail,
|
||||||
|
MatchPolicy: &equivalent,
|
||||||
|
AdmissionReviewVersions: []string{"v1beta1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func createV1beta1MutationWebhook(client clientset.Interface, endpoint string) error {
|
func createV1beta1MutationWebhook(client clientset.Interface, endpoint, convertedEndpoint string, convertedRules []admissionv1beta1.RuleWithOperations) error {
|
||||||
fail := admissionv1beta1.Fail
|
fail := admissionv1beta1.Fail
|
||||||
|
equivalent := admissionv1beta1.Equivalent
|
||||||
// Attaching Mutation webhook to API server
|
// Attaching Mutation webhook to API server
|
||||||
_, err := client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&admissionv1beta1.MutatingWebhookConfiguration{
|
_, err := client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&admissionv1beta1.MutatingWebhookConfiguration{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "mutation.integration.test"},
|
ObjectMeta: metav1.ObjectMeta{Name: "mutation.integration.test"},
|
||||||
Webhooks: []admissionv1beta1.Webhook{{
|
Webhooks: []admissionv1beta1.Webhook{
|
||||||
Name: "mutation.integration.test",
|
{
|
||||||
ClientConfig: admissionv1beta1.WebhookClientConfig{
|
Name: "mutation.integration.test",
|
||||||
URL: &endpoint,
|
ClientConfig: admissionv1beta1.WebhookClientConfig{
|
||||||
CABundle: localhostCert,
|
URL: &endpoint,
|
||||||
|
CABundle: localhostCert,
|
||||||
|
},
|
||||||
|
Rules: []admissionv1beta1.RuleWithOperations{{
|
||||||
|
Operations: []admissionv1beta1.OperationType{admissionv1beta1.OperationAll},
|
||||||
|
Rule: admissionv1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*/*"}},
|
||||||
|
}},
|
||||||
|
FailurePolicy: &fail,
|
||||||
|
AdmissionReviewVersions: []string{"v1beta1"},
|
||||||
},
|
},
|
||||||
Rules: []admissionv1beta1.RuleWithOperations{{
|
{
|
||||||
Operations: []admissionv1beta1.OperationType{admissionv1beta1.OperationAll},
|
Name: "mutation.integration.testconversion",
|
||||||
Rule: admissionv1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*/*"}},
|
ClientConfig: admissionv1beta1.WebhookClientConfig{
|
||||||
}},
|
URL: &convertedEndpoint,
|
||||||
FailurePolicy: &fail,
|
CABundle: localhostCert,
|
||||||
AdmissionReviewVersions: []string{"v1beta1"},
|
},
|
||||||
}},
|
Rules: convertedRules,
|
||||||
|
FailurePolicy: &fail,
|
||||||
|
MatchPolicy: &equivalent,
|
||||||
|
AdmissionReviewVersions: []string{"v1beta1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user