@@ -49,6 +49,12 @@ type Validator struct {
49
49
decoder * admission.Decoder
50
50
}
51
51
52
+ type request struct {
53
+ obj * unstructured.Unstructured
54
+ oldObj * unstructured.Unstructured
55
+ op k8sadm.Operation
56
+ }
57
+
52
58
func (v * Validator ) Handle (ctx context.Context , req admission.Request ) admission.Response {
53
59
log := v .Log .WithValues ("resource" , req .Resource , "ns" , req .Namespace , "nm" , req .Name , "op" , req .Operation , "user" , req .UserInfo .Username )
54
60
@@ -74,29 +80,13 @@ func (v *Validator) Handle(ctx context.Context, req admission.Request) admission
74
80
return webhooks .Allow ("HNC SA" )
75
81
}
76
82
77
- // Decode the old and new object, if we expect them to exist ("old" won't exist for creations,
78
- // while "new" won't exist for deletions).
79
- inst := & unstructured.Unstructured {}
80
- oldInst := & unstructured.Unstructured {}
81
- if req .Operation != k8sadm .Delete {
82
- if err := v .decoder .Decode (req , inst ); err != nil {
83
- log .Error (err , "Couldn't decode req.Object" , "raw" , req .Object )
84
- return webhooks .Deny (metav1 .StatusReasonBadRequest , err .Error ())
85
- }
86
- }
87
- if req .Operation != k8sadm .Create {
88
- // See issue #688 and #889
89
- if req .Operation == k8sadm .Delete && req .OldObject .Raw == nil {
90
- return webhooks .Allow ("cannot validate deletions in K8s 1.14" )
91
- }
92
- if err := v .decoder .DecodeRaw (req .OldObject , oldInst ); err != nil {
93
- log .Error (err , "Couldn't decode req.OldObject" , "raw" , req .OldObject )
94
- return webhooks .Deny (metav1 .StatusReasonBadRequest , err .Error ())
95
- }
83
+ decoded , err := v .decodeRequest (log , req )
84
+ if err != nil {
85
+ return webhooks .Deny (metav1 .StatusReasonBadRequest , err .Error ())
96
86
}
97
87
98
88
// Run the actual logic.
99
- resp := v .handle (ctx , req . Operation , inst , oldInst )
89
+ resp := v .handle (ctx , decoded )
100
90
if ! resp .Allowed {
101
91
log .Info ("Denied" , "code" , resp .Result .Code , "reason" , resp .Result .Reason , "message" , resp .Result .Message )
102
92
} else {
@@ -115,7 +105,10 @@ func (v *Validator) isPropagateType(gvk metav1.GroupVersionKind) bool {
115
105
116
106
// handle implements the non-webhook-y businesss logic of this validator, allowing it to be more
117
107
// easily unit tested (ie without constructing an admission.Request, setting up user infos, etc).
118
- func (v * Validator ) handle (ctx context.Context , op k8sadm.Operation , inst , oldInst * unstructured.Unstructured ) admission.Response {
108
+ func (v * Validator ) handle (ctx context.Context , req * request ) admission.Response {
109
+ inst := req .obj
110
+ oldInst := req .oldObj
111
+
119
112
// Find out if the object was/is inherited, and where it's inherited from.
120
113
oldSource , oldInherited := metadata .GetLabel (oldInst , api .LabelInheritedFrom )
121
114
newSource , newInherited := metadata .GetLabel (inst , api .LabelInheritedFrom )
@@ -152,7 +145,7 @@ func (v *Validator) handle(ctx context.Context, op k8sadm.Operation, inst, oldIn
152
145
return webhooks .Allow ("source object" )
153
146
}
154
147
// This is a propagated object.
155
- return v .handleInherited (ctx , op , newSource , oldSource , inst , oldInst )
148
+ return v .handleInherited (ctx , req , newSource , oldSource )
156
149
}
157
150
158
151
func validateSelectorAnnot (inst * unstructured.Unstructured ) string {
@@ -242,7 +235,11 @@ func validateNoneSelectorChange(inst, oldInst *unstructured.Unstructured) error
242
235
return err
243
236
}
244
237
245
- func (v * Validator ) handleInherited (ctx context.Context , op k8sadm.Operation , newSource , oldSource string , inst , oldInst * unstructured.Unstructured ) admission.Response {
238
+ func (v * Validator ) handleInherited (ctx context.Context , req * request , newSource , oldSource string ) admission.Response {
239
+ op := req .op
240
+ inst := req .obj
241
+ oldInst := req .oldObj
242
+
246
243
// Propagated objects cannot be created or deleted (except by the HNC SA, but the HNC SA
247
244
// never gets this far in the validation). They *can* have their statuses updated, so
248
245
// if this is an update, make sure that the canonical form of the object hasn't changed.
@@ -347,6 +344,31 @@ func (v *Validator) hasConflict(inst *unstructured.Unstructured) (bool, []string
347
344
return len (conflicts ) != 0 , conflicts
348
345
}
349
346
347
+ func (v * Validator ) decodeRequest (log logr.Logger , req admission.Request ) (* request , error ) {
348
+ // Decode the old and new object, if we expect them to exist ("old" won't exist for creations,
349
+ // while "new" won't exist for deletions).
350
+ inst := & unstructured.Unstructured {}
351
+ oldInst := & unstructured.Unstructured {}
352
+ if req .Operation != k8sadm .Delete {
353
+ if err := v .decoder .Decode (req , inst ); err != nil {
354
+ log .Error (err , "Couldn't decode req.Object" , "raw" , req .Object )
355
+ return nil , fmt .Errorf ("while decoding object: %w" , err )
356
+ }
357
+ }
358
+ if req .Operation != k8sadm .Create {
359
+ if err := v .decoder .DecodeRaw (req .OldObject , oldInst ); err != nil {
360
+ log .Error (err , "Couldn't decode req.OldObject" , "raw" , req .OldObject )
361
+ return nil , fmt .Errorf ("while decoding old object: %w" , err )
362
+ }
363
+ }
364
+
365
+ return & request {
366
+ obj : inst ,
367
+ oldObj : oldInst ,
368
+ op : req .Operation ,
369
+ }, nil
370
+ }
371
+
350
372
func (v * Validator ) InjectClient (c client.Client ) error {
351
373
v .client = c
352
374
return nil
0 commit comments