@@ -134,6 +134,81 @@ func runTests(admissionReviewVersion string) {
134
134
ExpectWithOffset (1 , w .Code ).To (Equal (http .StatusNotFound ))
135
135
})
136
136
137
+ It ("should scaffold a defaulting webhook with a custom defaulter" , func () {
138
+ By ("creating a controller manager" )
139
+ m , err := manager .New (cfg , manager.Options {})
140
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
141
+
142
+ By ("registering the type in the Scheme" )
143
+ builder := scheme.Builder {GroupVersion : testDefaulterGVK .GroupVersion ()}
144
+ builder .Register (& TestDefaulter {}, & TestDefaulterList {})
145
+ err = builder .AddToScheme (m .GetScheme ())
146
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
147
+
148
+ err = WebhookManagedBy (m ).
149
+ WithDefaulter (& TestCustomDefaulter {}).
150
+ For (& TestDefaulter {}).
151
+ Complete ()
152
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
153
+ svr := m .GetWebhookServer ()
154
+ ExpectWithOffset (1 , svr ).NotTo (BeNil ())
155
+
156
+ reader := strings .NewReader (`{
157
+ "kind":"AdmissionReview",
158
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
159
+ "request":{
160
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
161
+ "kind":{
162
+ "group":"",
163
+ "version":"v1",
164
+ "kind":"TestDefaulter"
165
+ },
166
+ "resource":{
167
+ "group":"",
168
+ "version":"v1",
169
+ "resource":"testdefaulter"
170
+ },
171
+ "namespace":"default",
172
+ "operation":"CREATE",
173
+ "object":{
174
+ "replica":1
175
+ },
176
+ "oldObject":null
177
+ }
178
+ }` )
179
+
180
+ ctx , cancel := context .WithCancel (context .Background ())
181
+ cancel ()
182
+ // TODO: we may want to improve it to make it be able to inject dependencies,
183
+ // but not always try to load certs and return not found error.
184
+ err = svr .Start (ctx )
185
+ if err != nil && ! os .IsNotExist (err ) {
186
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
187
+ }
188
+
189
+ By ("sending a request to a mutating webhook path" )
190
+ path := generateMutatePath (testDefaulterGVK )
191
+ req := httptest .NewRequest ("POST" , "http://svc-name.svc-ns.svc" + path , reader )
192
+ req .Header .Add ("Content-Type" , "application/json" )
193
+ w := httptest .NewRecorder ()
194
+ svr .WebhookMux .ServeHTTP (w , req )
195
+ ExpectWithOffset (1 , w .Code ).To (Equal (http .StatusOK ))
196
+ By ("sanity checking the response contains reasonable fields" )
197
+ ExpectWithOffset (1 , w .Body ).To (ContainSubstring (`"allowed":true` ))
198
+ ExpectWithOffset (1 , w .Body ).To (ContainSubstring (`"patch":` ))
199
+ ExpectWithOffset (1 , w .Body ).To (ContainSubstring (`"code":200` ))
200
+
201
+ By ("sending a request to a validating webhook path that doesn't exist" )
202
+ path = generateValidatePath (testDefaulterGVK )
203
+ _ , err = reader .Seek (0 , 0 )
204
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
205
+ req = httptest .NewRequest ("POST" , "http://svc-name.svc-ns.svc" + path , reader )
206
+ req .Header .Add ("Content-Type" , "application/json" )
207
+ w = httptest .NewRecorder ()
208
+ svr .WebhookMux .ServeHTTP (w , req )
209
+ ExpectWithOffset (1 , w .Code ).To (Equal (http .StatusNotFound ))
210
+ })
211
+
137
212
It ("should scaffold a validating webhook if the type implements the Validator interface" , func () {
138
213
By ("creating a controller manager" )
139
214
m , err := manager .New (cfg , manager.Options {})
@@ -209,6 +284,82 @@ func runTests(admissionReviewVersion string) {
209
284
ExpectWithOffset (1 , w .Body ).To (ContainSubstring (`"code":403` ))
210
285
})
211
286
287
+ It ("should scaffold a validating webhook with a custom validator" , func () {
288
+ By ("creating a controller manager" )
289
+ m , err := manager .New (cfg , manager.Options {})
290
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
291
+
292
+ By ("registering the type in the Scheme" )
293
+ builder := scheme.Builder {GroupVersion : testValidatorGVK .GroupVersion ()}
294
+ builder .Register (& TestValidator {}, & TestValidatorList {})
295
+ err = builder .AddToScheme (m .GetScheme ())
296
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
297
+
298
+ err = WebhookManagedBy (m ).
299
+ WithValidator (& TestCustomValidator {}).
300
+ For (& TestValidator {}).
301
+ Complete ()
302
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
303
+ svr := m .GetWebhookServer ()
304
+ ExpectWithOffset (1 , svr ).NotTo (BeNil ())
305
+
306
+ reader := strings .NewReader (`{
307
+ "kind":"AdmissionReview",
308
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
309
+ "request":{
310
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
311
+ "kind":{
312
+ "group":"",
313
+ "version":"v1",
314
+ "kind":"TestValidator"
315
+ },
316
+ "resource":{
317
+ "group":"",
318
+ "version":"v1",
319
+ "resource":"testvalidator"
320
+ },
321
+ "namespace":"default",
322
+ "operation":"UPDATE",
323
+ "object":{
324
+ "replica":1
325
+ },
326
+ "oldObject":{
327
+ "replica":2
328
+ }
329
+ }
330
+ }` )
331
+
332
+ ctx , cancel := context .WithCancel (context .Background ())
333
+ cancel ()
334
+ // TODO: we may want to improve it to make it be able to inject dependencies,
335
+ // but not always try to load certs and return not found error.
336
+ err = svr .Start (ctx )
337
+ if err != nil && ! os .IsNotExist (err ) {
338
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
339
+ }
340
+
341
+ By ("sending a request to a mutating webhook path that doesn't exist" )
342
+ path := generateMutatePath (testValidatorGVK )
343
+ req := httptest .NewRequest ("POST" , "http://svc-name.svc-ns.svc" + path , reader )
344
+ req .Header .Add ("Content-Type" , "application/json" )
345
+ w := httptest .NewRecorder ()
346
+ svr .WebhookMux .ServeHTTP (w , req )
347
+ ExpectWithOffset (1 , w .Code ).To (Equal (http .StatusNotFound ))
348
+
349
+ By ("sending a request to a validating webhook path" )
350
+ path = generateValidatePath (testValidatorGVK )
351
+ _ , err = reader .Seek (0 , 0 )
352
+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
353
+ req = httptest .NewRequest ("POST" , "http://svc-name.svc-ns.svc" + path , reader )
354
+ req .Header .Add ("Content-Type" , "application/json" )
355
+ w = httptest .NewRecorder ()
356
+ svr .WebhookMux .ServeHTTP (w , req )
357
+ ExpectWithOffset (1 , w .Code ).To (Equal (http .StatusOK ))
358
+ By ("sanity checking the response contains reasonable field" )
359
+ ExpectWithOffset (1 , w .Body ).To (ContainSubstring (`"allowed":false` ))
360
+ ExpectWithOffset (1 , w .Body ).To (ContainSubstring (`"code":403` ))
361
+ })
362
+
212
363
It ("should scaffold defaulting and validating webhooks if the type implements both Defaulter and Validator interfaces" , func () {
213
364
By ("creating a controller manager" )
214
365
m , err := manager .New (cfg , manager.Options {})
@@ -537,3 +688,51 @@ func (dv *TestDefaultValidator) ValidateDelete() error {
537
688
}
538
689
return nil
539
690
}
691
+
692
+ // TestCustomDefaulter.
693
+
694
+ type TestCustomDefaulter struct {}
695
+
696
+ func (* TestCustomDefaulter ) Default (ctx context.Context , obj runtime.Object ) error {
697
+ d := obj .(* TestDefaulter ) //nolint:ifshort
698
+ if d .Replica < 2 {
699
+ d .Replica = 2
700
+ }
701
+ return nil
702
+ }
703
+
704
+ var _ admission.CustomDefaulter = & TestCustomDefaulter {}
705
+
706
+ // TestCustomValidator.
707
+
708
+ type TestCustomValidator struct {}
709
+
710
+ func (* TestCustomValidator ) ValidateCreate (ctx context.Context , obj runtime.Object ) error {
711
+ v := obj .(* TestValidator ) //nolint:ifshort
712
+ if v .Replica < 0 {
713
+ return errors .New ("number of replica should be greater than or equal to 0" )
714
+ }
715
+ return nil
716
+ }
717
+
718
+ func (* TestCustomValidator ) ValidateUpdate (ctx context.Context , oldObj , newObj runtime.Object ) error {
719
+ v := newObj .(* TestValidator )
720
+ old := oldObj .(* TestValidator ) //nolint:ifshort
721
+ if v .Replica < 0 {
722
+ return errors .New ("number of replica should be greater than or equal to 0" )
723
+ }
724
+ if v .Replica < old .Replica {
725
+ return fmt .Errorf ("new replica %v should not be fewer than old replica %v" , v .Replica , old .Replica )
726
+ }
727
+ return nil
728
+ }
729
+
730
+ func (* TestCustomValidator ) ValidateDelete (ctx context.Context , obj runtime.Object ) error {
731
+ v := obj .(* TestValidator ) //nolint:ifshort
732
+ if v .Replica > 0 {
733
+ return errors .New ("number of replica should be less than or equal to 0 to delete" )
734
+ }
735
+ return nil
736
+ }
737
+
738
+ var _ admission.CustomValidator = & TestCustomValidator {}
0 commit comments