...
1
16
17 package admission
18
19 import (
20 "context"
21 "errors"
22 "fmt"
23 "net/http"
24
25 v1 "k8s.io/api/admission/v1"
26 apierrors "k8s.io/apimachinery/pkg/api/errors"
27 "k8s.io/apimachinery/pkg/runtime"
28 )
29
30
31
32 type CustomValidator interface {
33
34
35
36 ValidateCreate(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
37
38
39
40
41 ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings Warnings, err error)
42
43
44
45
46 ValidateDelete(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
47 }
48
49
50 func WithCustomValidator(scheme *runtime.Scheme, obj runtime.Object, validator CustomValidator) *Webhook {
51 return &Webhook{
52 Handler: &validatorForType{object: obj, validator: validator, decoder: NewDecoder(scheme)},
53 }
54 }
55
56 type validatorForType struct {
57 validator CustomValidator
58 object runtime.Object
59 decoder Decoder
60 }
61
62
63 func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
64 if h.decoder == nil {
65 panic("decoder should never be nil")
66 }
67 if h.validator == nil {
68 panic("validator should never be nil")
69 }
70 if h.object == nil {
71 panic("object should never be nil")
72 }
73
74 ctx = NewContextWithRequest(ctx, req)
75
76
77 obj := h.object.DeepCopyObject()
78
79 var err error
80 var warnings []string
81
82 switch req.Operation {
83 case v1.Connect:
84
85
86 case v1.Create:
87 if err := h.decoder.Decode(req, obj); err != nil {
88 return Errored(http.StatusBadRequest, err)
89 }
90
91 warnings, err = h.validator.ValidateCreate(ctx, obj)
92 case v1.Update:
93 oldObj := obj.DeepCopyObject()
94 if err := h.decoder.DecodeRaw(req.Object, obj); err != nil {
95 return Errored(http.StatusBadRequest, err)
96 }
97 if err := h.decoder.DecodeRaw(req.OldObject, oldObj); err != nil {
98 return Errored(http.StatusBadRequest, err)
99 }
100
101 warnings, err = h.validator.ValidateUpdate(ctx, oldObj, obj)
102 case v1.Delete:
103
104
105 if err := h.decoder.DecodeRaw(req.OldObject, obj); err != nil {
106 return Errored(http.StatusBadRequest, err)
107 }
108
109 warnings, err = h.validator.ValidateDelete(ctx, obj)
110 default:
111 return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation %q", req.Operation))
112 }
113
114
115 if err != nil {
116 var apiStatus apierrors.APIStatus
117 if errors.As(err, &apiStatus) {
118 return validationResponseFromStatus(false, apiStatus.Status()).WithWarnings(warnings...)
119 }
120 return Denied(err.Error()).WithWarnings(warnings...)
121 }
122
123
124 return Allowed("").WithWarnings(warnings...)
125 }
126
View as plain text