@@ -15,26 +15,26 @@ package envtest
15
15
16
16
import (
17
17
"context"
18
- "encoding/base64"
19
18
"fmt"
20
19
"io/ioutil"
21
20
"net"
22
21
"os"
23
22
"path/filepath"
24
23
"time"
25
24
25
+ admissionv1 "k8s.io/api/admissionregistration/v1"
26
26
apierrors "k8s.io/apimachinery/pkg/api/errors"
27
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
28
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
29
- "k8s.io/apimachinery/pkg/runtime"
30
29
"k8s.io/apimachinery/pkg/runtime/schema"
31
30
"k8s.io/apimachinery/pkg/util/sets"
32
31
"k8s.io/apimachinery/pkg/util/wait"
33
32
"k8s.io/client-go/rest"
33
+ "sigs.k8s.io/yaml"
34
+
34
35
"sigs.k8s.io/controller-runtime/pkg/client"
35
36
"sigs.k8s.io/controller-runtime/pkg/internal/testing/addr"
36
37
"sigs.k8s.io/controller-runtime/pkg/internal/testing/certs"
37
- "sigs.k8s.io/yaml"
38
38
)
39
39
40
40
// WebhookInstallOptions are the options for installing mutating or validating webhooks.
@@ -43,10 +43,10 @@ type WebhookInstallOptions struct {
43
43
Paths []string
44
44
45
45
// MutatingWebhooks is a list of MutatingWebhookConfigurations to install
46
- MutatingWebhooks []client. Object
46
+ MutatingWebhooks []admissionv1. MutatingWebhookConfiguration
47
47
48
48
// ValidatingWebhooks is a list of ValidatingWebhookConfigurations to install
49
- ValidatingWebhooks []client. Object
49
+ ValidatingWebhooks []admissionv1. ValidatingWebhookConfiguration
50
50
51
51
// IgnoreErrorIfPathMissing will ignore an error if a DirectoryPath does not exist when set to true
52
52
IgnoreErrorIfPathMissing bool
@@ -88,57 +88,27 @@ func (o *WebhookInstallOptions) ModifyWebhookDefinitions() error {
88
88
return err
89
89
}
90
90
91
- for i , unstructuredHook := range runtimeListToUnstructured (o .MutatingWebhooks ) {
92
- webhooks , found , err := unstructured .NestedSlice (unstructuredHook .Object , "webhooks" )
93
- if ! found || err != nil {
94
- return fmt .Errorf ("unexpected object, %v" , err )
95
- }
96
- for j := range webhooks {
97
- webhook , err := modifyWebhook (webhooks [j ].(map [string ]interface {}), caData , hostPort )
98
- if err != nil {
99
- return err
100
- }
101
- webhooks [j ] = webhook
102
- unstructuredHook .Object ["webhooks" ] = webhooks
103
- o .MutatingWebhooks [i ] = unstructuredHook
91
+ for i := range o .MutatingWebhooks {
92
+ for j := range o .MutatingWebhooks [i ].Webhooks {
93
+ updateClientConfig (& o .MutatingWebhooks [i ].Webhooks [j ].ClientConfig , hostPort , caData )
104
94
}
105
95
}
106
96
107
- for i , unstructuredHook := range runtimeListToUnstructured (o .ValidatingWebhooks ) {
108
- webhooks , found , err := unstructured .NestedSlice (unstructuredHook .Object , "webhooks" )
109
- if ! found || err != nil {
110
- return fmt .Errorf ("unexpected object, %v" , err )
111
- }
112
- for j := range webhooks {
113
- webhook , err := modifyWebhook (webhooks [j ].(map [string ]interface {}), caData , hostPort )
114
- if err != nil {
115
- return err
116
- }
117
- webhooks [j ] = webhook
118
- unstructuredHook .Object ["webhooks" ] = webhooks
119
- o .ValidatingWebhooks [i ] = unstructuredHook
97
+ for i := range o .ValidatingWebhooks {
98
+ for j := range o .ValidatingWebhooks [i ].Webhooks {
99
+ updateClientConfig (& o .ValidatingWebhooks [i ].Webhooks [j ].ClientConfig , hostPort , caData )
120
100
}
121
101
}
122
102
return nil
123
103
}
124
104
125
- func modifyWebhook (webhook map [string ]interface {}, caData []byte , hostPort string ) (map [string ]interface {}, error ) {
126
- clientConfig , found , err := unstructured .NestedMap (webhook , "clientConfig" )
127
- if ! found || err != nil {
128
- return nil , fmt .Errorf ("cannot find clientconfig: %v" , err )
129
- }
130
- clientConfig ["caBundle" ] = base64 .StdEncoding .EncodeToString (caData )
131
- servicePath , found , err := unstructured .NestedString (clientConfig , "service" , "path" )
132
- if found && err == nil {
133
- // we cannot use service in integration tests since we're running controller outside cluster
134
- // the intent here is that we swap out service for raw address because we don't have an actually standard kube service network.
135
- // We want to users to be able to use your standard config though
136
- url := fmt .Sprintf ("https://%s/%s" , hostPort , servicePath )
137
- clientConfig ["url" ] = url
138
- clientConfig ["service" ] = nil
105
+ func updateClientConfig (cc * admissionv1.WebhookClientConfig , hostPort string , caData []byte ) {
106
+ cc .CABundle = caData
107
+ if cc .Service != nil && cc .Service .Path != nil {
108
+ url := fmt .Sprintf ("https://%s/%s" , hostPort , * cc .Service .Path )
109
+ cc .URL = & url
110
+ cc .Service = nil
139
111
}
140
- webhook ["clientConfig" ] = clientConfig
141
- return webhook , nil
142
112
}
143
113
144
114
func (o * WebhookInstallOptions ) generateHostPort () (string , error ) {
@@ -199,12 +169,19 @@ func (o *WebhookInstallOptions) Cleanup() error {
199
169
200
170
// WaitForWebhooks waits for the Webhooks to be available through API server.
201
171
func WaitForWebhooks (config * rest.Config ,
202
- mutatingWebhooks []client. Object ,
203
- validatingWebhooks []client. Object ,
172
+ mutatingWebhooks []admissionv1. MutatingWebhookConfiguration ,
173
+ validatingWebhooks []admissionv1. ValidatingWebhookConfiguration ,
204
174
options WebhookInstallOptions ) error {
205
175
waitingFor := map [schema.GroupVersionKind ]* sets.String {}
206
176
207
- for _ , hook := range runtimeListToUnstructured (append (validatingWebhooks , mutatingWebhooks ... )) {
177
+ for _ , hook := range mutatingWebhooks {
178
+ if _ , ok := waitingFor [hook .GroupVersionKind ()]; ! ok {
179
+ waitingFor [hook .GroupVersionKind ()] = & sets.String {}
180
+ }
181
+ waitingFor [hook .GroupVersionKind ()].Insert (hook .GetName ())
182
+ }
183
+
184
+ for _ , hook := range validatingWebhooks {
208
185
if _ , ok := waitingFor [hook .GroupVersionKind ()]; ! ok {
209
186
waitingFor [hook .GroupVersionKind ()] = & sets.String {}
210
187
}
@@ -297,31 +274,33 @@ func (o *WebhookInstallOptions) setupCA() error {
297
274
return err
298
275
}
299
276
300
- func createWebhooks (config * rest.Config , mutHooks []client. Object , valHooks []client. Object ) error {
277
+ func createWebhooks (config * rest.Config , mutHooks []admissionv1. MutatingWebhookConfiguration , valHooks []admissionv1. ValidatingWebhookConfiguration ) error {
301
278
cs , err := client .New (config , client.Options {})
302
279
if err != nil {
303
280
return err
304
281
}
305
282
306
283
// Create each webhook
307
- for _ , hook := range runtimeListToUnstructured (mutHooks ) {
284
+ for _ , hook := range mutHooks {
285
+ hook := hook
308
286
log .V (1 ).Info ("installing mutating webhook" , "webhook" , hook .GetName ())
309
- if err := ensureCreated (cs , hook ); err != nil {
287
+ if err := ensureCreated (cs , & hook ); err != nil {
310
288
return err
311
289
}
312
290
}
313
- for _ , hook := range runtimeListToUnstructured (valHooks ) {
291
+ for _ , hook := range valHooks {
292
+ hook := hook
314
293
log .V (1 ).Info ("installing validating webhook" , "webhook" , hook .GetName ())
315
- if err := ensureCreated (cs , hook ); err != nil {
294
+ if err := ensureCreated (cs , & hook ); err != nil {
316
295
return err
317
296
}
318
297
}
319
298
return nil
320
299
}
321
300
322
301
// ensureCreated creates or update object if already exists in the cluster.
323
- func ensureCreated (cs client.Client , obj * unstructured. Unstructured ) error {
324
- existing := obj .DeepCopy ( )
302
+ func ensureCreated (cs client.Client , obj client. Object ) error {
303
+ existing := obj .DeepCopyObject ().(client. Object )
325
304
err := cs .Get (context .Background (), client.ObjectKey {Name : obj .GetName ()}, existing )
326
305
switch {
327
306
case apierrors .IsNotFound (err ):
@@ -364,7 +343,7 @@ func parseWebhook(options *WebhookInstallOptions) error {
364
343
365
344
// readWebhooks reads the Webhooks from files and Unmarshals them into structs
366
345
// returns slice of mutating and validating webhook configurations.
367
- func readWebhooks (path string ) ([]client. Object , []client. Object , error ) {
346
+ func readWebhooks (path string ) ([]admissionv1. MutatingWebhookConfiguration , []admissionv1. ValidatingWebhookConfiguration , error ) {
368
347
// Get the webhook files
369
348
var files []os.FileInfo
370
349
var err error
@@ -382,8 +361,8 @@ func readWebhooks(path string) ([]client.Object, []client.Object, error) {
382
361
// file extensions that may contain Webhooks
383
362
resourceExtensions := sets .NewString (".json" , ".yaml" , ".yml" )
384
363
385
- var mutHooks []client. Object
386
- var valHooks []client. Object
364
+ var mutHooks []admissionv1. MutatingWebhookConfiguration
365
+ var valHooks []admissionv1. ValidatingWebhookConfiguration
387
366
for _ , file := range files {
388
367
// Only parse allowlisted file types
389
368
if ! resourceExtensions .Has (filepath .Ext (file .Name ())) {
@@ -403,24 +382,23 @@ func readWebhooks(path string) ([]client.Object, []client.Object, error) {
403
382
}
404
383
405
384
const (
406
- admissionregv1 = "admissionregistration.k8s.io/v1"
407
- admissionregv1beta1 = "admissionregistration.k8s.io/v1beta1"
385
+ admissionregv1 = "admissionregistration.k8s.io/v1"
408
386
)
409
387
switch {
410
388
case generic .Kind == "MutatingWebhookConfiguration" :
411
- if generic .APIVersion != admissionregv1beta1 && generic . APIVersion != admissionregv1 {
412
- return nil , nil , fmt .Errorf ("only v1beta1 and v1 are supported right now for MutatingWebhookConfiguration (name: %s)" , generic .Name )
389
+ if generic .APIVersion != admissionregv1 {
390
+ return nil , nil , fmt .Errorf ("only v1 is supported right now for MutatingWebhookConfiguration (name: %s)" , generic .Name )
413
391
}
414
- hook := & unstructured. Unstructured {}
392
+ hook := admissionv1. MutatingWebhookConfiguration {}
415
393
if err := yaml .Unmarshal (doc , & hook ); err != nil {
416
394
return nil , nil , err
417
395
}
418
396
mutHooks = append (mutHooks , hook )
419
397
case generic .Kind == "ValidatingWebhookConfiguration" :
420
- if generic .APIVersion != admissionregv1beta1 && generic . APIVersion != admissionregv1 {
421
- return nil , nil , fmt .Errorf ("only v1beta1 and v1 are supported right now for ValidatingWebhookConfiguration (name: %s)" , generic .Name )
398
+ if generic .APIVersion != admissionregv1 {
399
+ return nil , nil , fmt .Errorf ("only v1 is supported right now for ValidatingWebhookConfiguration (name: %s)" , generic .Name )
422
400
}
423
- hook := & unstructured. Unstructured {}
401
+ hook := admissionv1. ValidatingWebhookConfiguration {}
424
402
if err := yaml .Unmarshal (doc , & hook ); err != nil {
425
403
return nil , nil , err
426
404
}
@@ -434,17 +412,3 @@ func readWebhooks(path string) ([]client.Object, []client.Object, error) {
434
412
}
435
413
return mutHooks , valHooks , nil
436
414
}
437
-
438
- func runtimeListToUnstructured (l []client.Object ) []* unstructured.Unstructured {
439
- res := []* unstructured.Unstructured {}
440
- for _ , obj := range l {
441
- m , err := runtime .DefaultUnstructuredConverter .ToUnstructured (obj .DeepCopyObject ())
442
- if err != nil {
443
- continue
444
- }
445
- res = append (res , & unstructured.Unstructured {
446
- Object : m ,
447
- })
448
- }
449
- return res
450
- }
0 commit comments