...

Source file src/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go

Documentation: sigs.k8s.io/controller-runtime/pkg/webhook/admission

     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  }
   128  

View as plain text