k8s.io/apiserver@v0.31.1/pkg/admission/plugin/webhook/predicates/namespace/matcher_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package namespace_test 18 19 import ( 20 "reflect" 21 "testing" 22 23 registrationv1 "k8s.io/api/admissionregistration/v1" 24 corev1 "k8s.io/api/core/v1" 25 "k8s.io/apimachinery/pkg/api/errors" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/labels" 28 "k8s.io/apimachinery/pkg/runtime/schema" 29 "k8s.io/apiserver/pkg/admission" 30 "k8s.io/apiserver/pkg/admission/plugin/webhook" 31 "k8s.io/apiserver/pkg/admission/plugin/webhook/predicates/namespace" 32 ) 33 34 type fakeNamespaceLister struct { 35 namespaces map[string]*corev1.Namespace 36 } 37 38 func (f fakeNamespaceLister) List(selector labels.Selector) (ret []*corev1.Namespace, err error) { 39 return nil, nil 40 } 41 func (f fakeNamespaceLister) Get(name string) (*corev1.Namespace, error) { 42 ns, ok := f.namespaces[name] 43 if ok { 44 return ns, nil 45 } 46 return nil, errors.NewNotFound(corev1.Resource("namespaces"), name) 47 } 48 49 func TestGetNamespaceLabels(t *testing.T) { 50 namespace1Labels := map[string]string{ 51 "runlevel": "1", 52 } 53 namespace1 := corev1.Namespace{ 54 ObjectMeta: metav1.ObjectMeta{ 55 Name: "1", 56 Labels: namespace1Labels, 57 }, 58 } 59 namespace2Labels := map[string]string{ 60 "runlevel": "2", 61 } 62 namespace2 := corev1.Namespace{ 63 ObjectMeta: metav1.ObjectMeta{ 64 Name: "2", 65 Labels: namespace2Labels, 66 }, 67 } 68 namespaceLister := fakeNamespaceLister{map[string]*corev1.Namespace{ 69 "1": &namespace1, 70 }, 71 } 72 73 tests := []struct { 74 name string 75 attr admission.Attributes 76 expectedLabels map[string]string 77 }{ 78 { 79 name: "request is for creating namespace, the labels should be from the object itself", 80 attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, "", namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), 81 expectedLabels: namespace2Labels, 82 }, 83 { 84 name: "request is for updating namespace, the labels should be from the new object", 85 attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace2.Name, namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Update, &metav1.UpdateOptions{}, false, nil), 86 expectedLabels: namespace2Labels, 87 }, 88 { 89 name: "request is for deleting namespace, the labels should be from the cache", 90 attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace1.Name, namespace1.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Delete, &metav1.DeleteOptions{}, false, nil), 91 expectedLabels: namespace1Labels, 92 }, 93 { 94 name: "request is for namespace/finalizer", 95 attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "namespaces"}, "finalizers", admission.Create, &metav1.CreateOptions{}, false, nil), 96 expectedLabels: namespace1Labels, 97 }, 98 { 99 name: "request is for pod", 100 attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "pods"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), 101 expectedLabels: namespace1Labels, 102 }, 103 } 104 matcher := namespace.Matcher{ 105 NamespaceLister: namespaceLister, 106 } 107 for _, tt := range tests { 108 actualLabels, err := matcher.GetNamespaceLabels(tt.attr) 109 if err != nil { 110 t.Error(err) 111 } 112 if !reflect.DeepEqual(actualLabels, tt.expectedLabels) { 113 t.Errorf("expected labels to be %#v, got %#v", tt.expectedLabels, actualLabels) 114 } 115 } 116 } 117 118 func TestNotExemptClusterScopedResource(t *testing.T) { 119 hook := ®istrationv1.ValidatingWebhook{ 120 NamespaceSelector: &metav1.LabelSelector{}, 121 } 122 attr := admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "mock-name", schema.GroupVersionResource{Version: "v1", Resource: "nodes"}, "", admission.Create, &metav1.CreateOptions{}, false, nil) 123 matcher := namespace.Matcher{} 124 matches, err := matcher.MatchNamespaceSelector(webhook.NewValidatingWebhookAccessor("mock-hook", "mock-cfg", hook), attr) 125 if err != nil { 126 t.Fatal(err) 127 } 128 if !matches { 129 t.Errorf("cluster scoped resources (but not a namespace) should not be exempted from webhooks") 130 } 131 }