sigs.k8s.io/controller-runtime@v0.18.2/pkg/webhook/admission/decode_test.go (about) 1 /* 2 Copyright 2018 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 admission 18 19 import ( 20 . "github.com/onsi/ginkgo/v2" 21 . "github.com/onsi/gomega" 22 23 admissionv1 "k8s.io/api/admission/v1" 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/client-go/kubernetes/scheme" 29 ) 30 31 var _ = Describe("Admission Webhook Decoder", func() { 32 var decoder Decoder 33 BeforeEach(func() { 34 By("creating a new decoder for a scheme") 35 decoder = NewDecoder(scheme.Scheme) 36 Expect(decoder).NotTo(BeNil()) 37 }) 38 39 req := Request{ 40 AdmissionRequest: admissionv1.AdmissionRequest{ 41 Object: runtime.RawExtension{ 42 Raw: []byte(`{ 43 "apiVersion": "v1", 44 "kind": "Pod", 45 "metadata": { 46 "name": "foo", 47 "namespace": "default" 48 }, 49 "spec": { 50 "containers": [ 51 { 52 "image": "bar:v2", 53 "name": "bar" 54 } 55 ] 56 } 57 }`), 58 }, 59 OldObject: runtime.RawExtension{ 60 Raw: []byte(`{ 61 "apiVersion": "v1", 62 "kind": "Pod", 63 "metadata": { 64 "name": "foo", 65 "namespace": "default" 66 }, 67 "spec": { 68 "containers": [ 69 { 70 "image": "bar:v1", 71 "name": "bar" 72 } 73 ] 74 } 75 }`), 76 }, 77 }, 78 } 79 80 It("should decode a valid admission request", func() { 81 By("extracting the object from the request") 82 var actualObj corev1.Pod 83 Expect(decoder.Decode(req, &actualObj)).To(Succeed()) 84 85 By("verifying that all data is present in the object") 86 Expect(actualObj).To(Equal(corev1.Pod{ 87 TypeMeta: metav1.TypeMeta{ 88 APIVersion: "v1", 89 Kind: "Pod", 90 }, 91 ObjectMeta: metav1.ObjectMeta{ 92 Name: "foo", 93 Namespace: "default", 94 }, 95 Spec: corev1.PodSpec{ 96 Containers: []corev1.Container{ 97 {Image: "bar:v2", Name: "bar"}, 98 }, 99 }, 100 })) 101 }) 102 103 It("should decode a valid RawExtension object", func() { 104 By("decoding the RawExtension object") 105 var actualObj corev1.Pod 106 Expect(decoder.DecodeRaw(req.OldObject, &actualObj)).To(Succeed()) 107 108 By("verifying that all data is present in the object") 109 Expect(actualObj).To(Equal(corev1.Pod{ 110 TypeMeta: metav1.TypeMeta{ 111 APIVersion: "v1", 112 Kind: "Pod", 113 }, 114 ObjectMeta: metav1.ObjectMeta{ 115 Name: "foo", 116 Namespace: "default", 117 }, 118 Spec: corev1.PodSpec{ 119 Containers: []corev1.Container{ 120 {Image: "bar:v1", Name: "bar"}, 121 }, 122 }, 123 })) 124 }) 125 126 // NOTE: This will only pass if a GVK is provided. An unstructered object without a GVK may succeed 127 // in decoding to an alternate type. 128 It("should fail to decode if the object in the request doesn't match the passed-in type", func() { 129 By("trying to extract a pod from the quest into a node") 130 Expect(decoder.Decode(req, &corev1.Node{})).NotTo(Succeed()) 131 132 By("trying to extract a pod in RawExtension format into a node") 133 Expect(decoder.DecodeRaw(req.OldObject, &corev1.Node{})).NotTo(Succeed()) 134 }) 135 136 It("should be able to decode into an unstructured object", func() { 137 By("decoding the request into an unstructured object") 138 var target unstructured.Unstructured 139 Expect(decoder.Decode(req, &target)).To(Succeed()) 140 141 By("sanity-checking the metadata on the output object") 142 Expect(target.Object["metadata"]).To(Equal(map[string]interface{}{ 143 "name": "foo", 144 "namespace": "default", 145 })) 146 147 By("decoding the RawExtension object into an unstructured object") 148 var target2 unstructured.Unstructured 149 Expect(decoder.DecodeRaw(req.Object, &target2)).To(Succeed()) 150 151 By("sanity-checking the metadata on the output object") 152 Expect(target2.Object["metadata"]).To(Equal(map[string]interface{}{ 153 "name": "foo", 154 "namespace": "default", 155 })) 156 }) 157 158 req2 := Request{ 159 AdmissionRequest: admissionv1.AdmissionRequest{ 160 Operation: "CREATE", 161 Object: runtime.RawExtension{ 162 Raw: []byte(`{ 163 "metadata": { 164 "name": "foo", 165 "namespace": "default" 166 }, 167 "spec": { 168 "containers": [ 169 { 170 "image": "bar:v2", 171 "name": "bar" 172 } 173 ] 174 } 175 }`), 176 }, 177 OldObject: runtime.RawExtension{ 178 Object: nil, 179 }, 180 }, 181 } 182 183 It("should decode a valid admission request without GVK", func() { 184 By("extracting the object from the request") 185 var target3 unstructured.Unstructured 186 Expect(decoder.DecodeRaw(req2.Object, &target3)).To(Succeed()) 187 }) 188 })