@@ -30,6 +30,7 @@ import (
30
30
"sigs.k8s.io/controller-runtime/pkg/predicate"
31
31
"sigs.k8s.io/controller-runtime/pkg/reconcile"
32
32
"sigs.k8s.io/controller-runtime/pkg/source"
33
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
33
34
)
34
35
35
36
// Supporting mocking out functions for testing
@@ -65,6 +66,8 @@ func ControllerManagedBy(m manager.Manager) *Builder {
65
66
// update events by *reconciling the object*.
66
67
// This is the equivalent of calling
67
68
// Watches(&source.Kind{Type: apiType}, &handler.EnqueueRequestForObject{})
69
+ // If the passed in object has implemented the admission.Defaulter interface, a MutatingWebhook will be wired for this type.
70
+ // If the passed in object has implemented the admission.Validator interface, a ValidatingWebhook will be wired for this type.
68
71
//
69
72
// Deprecated: Use For
70
73
func (blder * Builder ) ForType (apiType runtime.Object ) * Builder {
@@ -75,6 +78,8 @@ func (blder *Builder) ForType(apiType runtime.Object) *Builder {
75
78
// update events by *reconciling the object*.
76
79
// This is the equivalent of calling
77
80
// Watches(&source.Kind{Type: apiType}, &handler.EnqueueRequestForObject{})
81
+ // If the passed in object has implemented the admission.Defaulter interface, a MutatingWebhook will be wired for this type.
82
+ // If the passed in object has implemented the admission.Validator interface, a ValidatingWebhook will be wired for this type.
78
83
func (blder * Builder ) For (apiType runtime.Object ) * Builder {
79
84
blder .apiType = apiType
80
85
return blder
@@ -124,7 +129,7 @@ func (blder *Builder) WithEventFilter(p predicate.Predicate) *Builder {
124
129
return blder
125
130
}
126
131
127
- // Complete builds the Application ControllerManagedBy and returns the Manager used to start it .
132
+ // Complete builds the Application ControllerManagedBy.
128
133
func (blder * Builder ) Complete (r reconcile.Reconciler ) error {
129
134
_ , err := blder .Build (r )
130
135
return err
@@ -135,7 +140,7 @@ func (blder *Builder) Complete(r reconcile.Reconciler) error {
135
140
// Deprecated: Use Complete
136
141
func (blder * Builder ) Build (r reconcile.Reconciler ) (manager.Manager , error ) {
137
142
if r == nil {
138
- return nil , fmt .Errorf ("must call WithReconciler to set Reconciler" )
143
+ return nil , fmt .Errorf ("must provide a non-nil Reconciler" )
139
144
}
140
145
141
146
// Set the Config
@@ -153,12 +158,26 @@ func (blder *Builder) Build(r reconcile.Reconciler) (manager.Manager, error) {
153
158
return nil , err
154
159
}
155
160
161
+ // Set the Webook if needed
162
+ if err := blder .doWebhook (); err != nil {
163
+ return nil , err
164
+ }
165
+
166
+ // Set the Watch
167
+ if err := blder .doWatch (); err != nil {
168
+ return nil , err
169
+ }
170
+
171
+ return blder .mgr , nil
172
+ }
173
+
174
+ func (blder * Builder ) doWatch () error {
156
175
// Reconcile type
157
176
src := & source.Kind {Type : blder .apiType }
158
177
hdler := & handler.EnqueueRequestForObject {}
159
178
err := blder .ctrl .Watch (src , hdler , blder .predicates ... )
160
179
if err != nil {
161
- return nil , err
180
+ return err
162
181
}
163
182
164
183
// Watches the managed types
@@ -169,19 +188,18 @@ func (blder *Builder) Build(r reconcile.Reconciler) (manager.Manager, error) {
169
188
IsController : true ,
170
189
}
171
190
if err := blder .ctrl .Watch (src , hdler , blder .predicates ... ); err != nil {
172
- return nil , err
191
+ return err
173
192
}
174
193
}
175
194
176
195
// Do the watch requests
177
196
for _ , w := range blder .watchRequest {
178
197
if err := blder .ctrl .Watch (w .src , w .eventhandler , blder .predicates ... ); err != nil {
179
- return nil , err
198
+ return err
180
199
}
181
200
182
201
}
183
-
184
- return blder .mgr , nil
202
+ return nil
185
203
}
186
204
187
205
func (blder * Builder ) doConfig () error {
@@ -223,3 +241,51 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
223
241
blder .ctrl , err = newController (name , blder .mgr , controller.Options {Reconciler : r })
224
242
return err
225
243
}
244
+
245
+ func (blder * Builder ) doWebhook () error {
246
+ // Create a webhook for each type
247
+ gvk , err := apiutil .GVKForObject (blder .apiType , blder .mgr .GetScheme ())
248
+ if err != nil {
249
+ return err
250
+ }
251
+
252
+ partialPath := strings .Replace (gvk .Group , "." , "-" , - 1 ) + "-" +
253
+ gvk .Version + "-" + strings .ToLower (gvk .Kind )
254
+
255
+ // TODO: When the conversion webhook lands, we need to handle all registered versions of a given group-kind.
256
+ // A potential workflow for defaulting webhook
257
+ // 1) a bespoke (non-hub) version comes in
258
+ // 2) convert it to the hub version
259
+ // 3) do defaulting
260
+ // 4) convert it back to the same bespoke version
261
+ // 5) calculate the JSON patch
262
+ //
263
+ // A potential workflow for validating webhook
264
+ // 1) a bespoke (non-hub) version comes in
265
+ // 2) convert it to the hub version
266
+ // 3) do validation
267
+ if defaulter , isDefaulter := blder .apiType .(admission.Defaulter ); isDefaulter {
268
+ mwh := admission .DefaultingWebhookFor (defaulter )
269
+ if mwh != nil {
270
+ path := "/mutate-" + partialPath
271
+ log .Info ("Registering a mutating webhook" ,
272
+ "GVK" , gvk ,
273
+ "path" , path )
274
+
275
+ blder .mgr .GetWebhookServer ().Register (path , mwh )
276
+ }
277
+ }
278
+
279
+ if validator , isValidator := blder .apiType .(admission.Validator ); isValidator {
280
+ vwh := admission .ValidatingWebhookFor (validator )
281
+ if vwh != nil {
282
+ path := "/validate-" + partialPath
283
+ log .Info ("Registering a validating webhook" ,
284
+ "GVK" , gvk ,
285
+ "path" , path )
286
+ blder .mgr .GetWebhookServer ().Register (path , vwh )
287
+ }
288
+ }
289
+
290
+ return err
291
+ }
0 commit comments