github.com/kotalco/kotal@v0.3.0/apis/ethereum2/v1alpha1/validator_validation_webhook.go (about)

     1  package v1alpha1
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	apierrors "k8s.io/apimachinery/pkg/api/errors"
     8  	"k8s.io/apimachinery/pkg/runtime"
     9  	"k8s.io/apimachinery/pkg/runtime/schema"
    10  	"k8s.io/apimachinery/pkg/util/validation/field"
    11  	"sigs.k8s.io/controller-runtime/pkg/webhook"
    12  	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
    13  )
    14  
    15  // +kubebuilder:webhook:verbs=create;update,path=/validate-ethereum2-kotal-io-v1alpha1-validator,mutating=false,failurePolicy=fail,groups=ethereum2.kotal.io,resources=validators,versions=v1alpha1,name=validate-ethereum2-v1alpha1-validator.kb.io,sideEffects=None,admissionReviewVersions=v1
    16  
    17  var _ webhook.Validator = &Validator{}
    18  
    19  // validate validates an Ethereum 2.0 validator client
    20  func (r *Validator) validate() field.ErrorList {
    21  	var validatorErrors field.ErrorList
    22  
    23  	// prysm requires wallet password
    24  	if r.Spec.Client == PrysmClient && r.Spec.WalletPasswordSecret == "" {
    25  		msg := "must provide walletPasswordSecret if client is prysm"
    26  		err := field.Invalid(field.NewPath("spec").Child("walletPasswordSecret"), r.Spec.WalletPasswordSecret, msg)
    27  		validatorErrors = append(validatorErrors, err)
    28  	}
    29  
    30  	if r.Spec.CertSecretName != "" && r.Spec.Client != PrysmClient {
    31  		err := field.Invalid(field.NewPath("spec").Child("certSecretName"), r.Spec.CertSecretName, fmt.Sprintf("not supported by %s client", r.Spec.Client))
    32  		validatorErrors = append(validatorErrors, err)
    33  	}
    34  
    35  	if !r.Spec.Client.SupportsVerbosityLevel(r.Spec.Logging, false) {
    36  		err := field.Invalid(field.NewPath("spec").Child("logging"), r.Spec.Logging, fmt.Sprintf("not supported by %s client", r.Spec.Client))
    37  		validatorErrors = append(validatorErrors, err)
    38  	}
    39  
    40  	// lighthouse is the only client supporting multiple beacon endpoints
    41  	if r.Spec.Client != LighthouseClient && len(r.Spec.BeaconEndpoints) > 1 {
    42  		msg := fmt.Sprintf("multiple beacon node endpoints not supported by %s client", r.Spec.Client)
    43  		err := field.Invalid(field.NewPath("spec").Child("beaconEndpoints"), strings.Join(r.Spec.BeaconEndpoints, ","), msg)
    44  		validatorErrors = append(validatorErrors, err)
    45  	}
    46  
    47  	if r.Spec.Client == LighthouseClient {
    48  		for i, keystore := range r.Spec.Keystores {
    49  			if keystore.PublicKey == "" {
    50  				msg := "keystore public key is required if client is lighthouse"
    51  				err := field.Invalid(field.NewPath("spec").Child("keystores").Index(i).Child("publicKey"), "", msg)
    52  				validatorErrors = append(validatorErrors, err)
    53  			}
    54  		}
    55  	}
    56  
    57  	return validatorErrors
    58  }
    59  
    60  // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
    61  func (r *Validator) ValidateCreate() (admission.Warnings, error) {
    62  	var allErrors field.ErrorList
    63  
    64  	validatorlog.Info("validate create", "name", r.Name)
    65  
    66  	allErrors = append(allErrors, r.validate()...)
    67  	allErrors = append(allErrors, r.Spec.Resources.ValidateCreate()...)
    68  
    69  	if len(allErrors) == 0 {
    70  		return nil, nil
    71  	}
    72  
    73  	return nil, apierrors.NewInvalid(schema.GroupKind{}, r.Name, allErrors)
    74  }
    75  
    76  // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
    77  func (r *Validator) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
    78  	var allErrors field.ErrorList
    79  	oldValidator := old.(*Validator)
    80  
    81  	validatorlog.Info("validate update", "name", r.Name)
    82  
    83  	allErrors = append(allErrors, r.validate()...)
    84  	allErrors = append(allErrors, r.Spec.Resources.ValidateUpdate(&oldValidator.Spec.Resources)...)
    85  
    86  	if oldValidator.Spec.Client != r.Spec.Client {
    87  		err := field.Invalid(field.NewPath("spec").Child("client"), r.Spec.Client, "field is immutable")
    88  		allErrors = append(allErrors, err)
    89  	}
    90  
    91  	if oldValidator.Spec.Network != r.Spec.Network {
    92  		err := field.Invalid(field.NewPath("spec").Child("network"), r.Spec.Network, "field is immutable")
    93  		allErrors = append(allErrors, err)
    94  	}
    95  
    96  	allErrors = append(allErrors, r.Spec.Resources.ValidateCreate()...)
    97  
    98  	if len(allErrors) == 0 {
    99  		return nil, nil
   100  	}
   101  
   102  	return nil, apierrors.NewInvalid(schema.GroupKind{}, r.Name, allErrors)
   103  }
   104  
   105  // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
   106  func (r *Validator) ValidateDelete() (admission.Warnings, error) {
   107  	validatorlog.Info("validate delete", "name", r.Name)
   108  
   109  	return nil, nil
   110  }