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 }