sigs.k8s.io/controller-runtime@v0.18.2/pkg/webhook/admission/validator.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 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 // Warnings represents warning messages. 31 type Warnings []string 32 33 // Validator defines functions for validating an operation. 34 // The custom resource kind which implements this interface can validate itself. 35 // To validate the custom resource with another specific struct, use CustomValidator instead. 36 // Deprecated: Use CustomValidator instead. 37 type Validator interface { 38 runtime.Object 39 40 // ValidateCreate validates the object on creation. 41 // The optional warnings will be added to the response as warning messages. 42 // Return an error if the object is invalid. 43 ValidateCreate() (warnings Warnings, err error) 44 45 // ValidateUpdate validates the object on update. The oldObj is the object before the update. 46 // The optional warnings will be added to the response as warning messages. 47 // Return an error if the object is invalid. 48 ValidateUpdate(old runtime.Object) (warnings Warnings, err error) 49 50 // ValidateDelete validates the object on deletion. 51 // The optional warnings will be added to the response as warning messages. 52 // Return an error if the object is invalid. 53 ValidateDelete() (warnings Warnings, err error) 54 } 55 56 // ValidatingWebhookFor creates a new Webhook for validating the provided type. 57 // Deprecated: Use WithCustomValidator instead. 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 // Handle handles admission requests. 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 // Get the object in the request 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 // No validation for connect requests. 86 // TODO(vincepri): Should we validate CONNECT requests? In what cases? 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 // In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346 108 // OldObject contains the object being deleted 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 }