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