Skip to content

Commit

Permalink
Merge pull request #2014 from STRRL/webhook-warning
Browse files Browse the repository at this point in the history
⚠️ feat: new features about support warning with webhook
  • Loading branch information
k8s-ci-robot committed Apr 19, 2023
2 parents 3d915df + b2a9552 commit 1c2a7c9
Show file tree
Hide file tree
Showing 8 changed files with 396 additions and 202 deletions.
17 changes: 9 additions & 8 deletions examples/builtins/validatingwebhook.go
Expand Up @@ -24,6 +24,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"

logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// +kubebuilder:webhook:path=/validate-v1-pod,mutating=false,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=vpod.kb.io
Expand All @@ -32,34 +33,34 @@ import (
type podValidator struct{}

// validate admits a pod if a specific annotation exists.
func (v *podValidator) validate(ctx context.Context, obj runtime.Object) error {
func (v *podValidator) validate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
log := logf.FromContext(ctx)
pod, ok := obj.(*corev1.Pod)
if !ok {
return fmt.Errorf("expected a Pod but got a %T", obj)
return nil, fmt.Errorf("expected a Pod but got a %T", obj)
}

log.Info("Validating Pod")
key := "example-mutating-admission-webhook"
anno, found := pod.Annotations[key]
if !found {
return fmt.Errorf("missing annotation %s", key)
return nil, fmt.Errorf("missing annotation %s", key)
}
if anno != "foo" {
return fmt.Errorf("annotation %s did not have value %q", key, "foo")
return nil, fmt.Errorf("annotation %s did not have value %q", key, "foo")
}

return nil
return nil, nil
}

func (v *podValidator) ValidateCreate(ctx context.Context, obj runtime.Object) error {
func (v *podValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
return v.validate(ctx, obj)
}

func (v *podValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error {
func (v *podValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
return v.validate(ctx, newObj)
}

func (v *podValidator) ValidateDelete(ctx context.Context, obj runtime.Object) error {
func (v *podValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
return v.validate(ctx, obj)
}
23 changes: 12 additions & 11 deletions examples/crd/pkg/resource.go
Expand Up @@ -24,6 +24,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// ChaosPodSpec defines the desired state of ChaosPod
Expand Down Expand Up @@ -66,41 +67,41 @@ type ChaosPodList struct {
var _ webhook.Validator = &ChaosPod{}

// ValidateCreate implements webhookutil.validator so a webhook will be registered for the type
func (c *ChaosPod) ValidateCreate() error {
func (c *ChaosPod) ValidateCreate() (admission.Warnings, error) {
log.Info("validate create", "name", c.Name)

if c.Spec.NextStop.Before(&metav1.Time{Time: time.Now()}) {
return fmt.Errorf(".spec.nextStop must be later than current time")
return nil, fmt.Errorf(".spec.nextStop must be later than current time")
}
return nil
return nil, nil
}

// ValidateUpdate implements webhookutil.validator so a webhook will be registered for the type
func (c *ChaosPod) ValidateUpdate(old runtime.Object) error {
func (c *ChaosPod) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
log.Info("validate update", "name", c.Name)

if c.Spec.NextStop.Before(&metav1.Time{Time: time.Now()}) {
return fmt.Errorf(".spec.nextStop must be later than current time")
return nil, fmt.Errorf(".spec.nextStop must be later than current time")
}

oldC, ok := old.(*ChaosPod)
if !ok {
return fmt.Errorf("expect old object to be a %T instead of %T", oldC, old)
return nil, fmt.Errorf("expect old object to be a %T instead of %T", oldC, old)
}
if c.Spec.NextStop.After(oldC.Spec.NextStop.Add(time.Hour)) {
return fmt.Errorf("it is not allowed to delay.spec.nextStop for more than 1 hour")
return nil, fmt.Errorf("it is not allowed to delay.spec.nextStop for more than 1 hour")
}
return nil
return nil, nil
}

// ValidateDelete implements webhookutil.validator so a webhook will be registered for the type
func (c *ChaosPod) ValidateDelete() error {
func (c *ChaosPod) ValidateDelete() (admission.Warnings, error) {
log.Info("validate delete", "name", c.Name)

if c.Spec.NextStop.Before(&metav1.Time{Time: time.Now()}) {
return fmt.Errorf(".spec.nextStop must be later than current time")
return nil, fmt.Errorf(".spec.nextStop must be later than current time")
}
return nil
return nil, nil
}

// +kubebuilder:webhook:path=/mutate-chaosapps-metamagical-io-v1-chaospod,mutating=true,failurePolicy=fail,groups=chaosapps.metamagical.io,resources=chaospods,verbs=create;update,versions=v1,name=mchaospod.kb.io
Expand Down
72 changes: 36 additions & 36 deletions pkg/builder/webhook_test.go
Expand Up @@ -749,39 +749,39 @@ func (*TestValidatorList) DeepCopyObject() runtime.Object { return nil }

var _ admission.Validator = &TestValidator{}

func (v *TestValidator) ValidateCreate() error {
func (v *TestValidator) ValidateCreate() (admission.Warnings, error) {
if v.Panic {
panic("fake panic test")
}
if v.Replica < 0 {
return errors.New("number of replica should be greater than or equal to 0")
return nil, errors.New("number of replica should be greater than or equal to 0")
}
return nil
return nil, nil
}

func (v *TestValidator) ValidateUpdate(old runtime.Object) error {
func (v *TestValidator) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
if v.Panic {
panic("fake panic test")
}
if v.Replica < 0 {
return errors.New("number of replica should be greater than or equal to 0")
return nil, errors.New("number of replica should be greater than or equal to 0")
}
if oldObj, ok := old.(*TestValidator); !ok {
return fmt.Errorf("the old object is expected to be %T", oldObj)
return nil, fmt.Errorf("the old object is expected to be %T", oldObj)
} else if v.Replica < oldObj.Replica {
return fmt.Errorf("new replica %v should not be fewer than old replica %v", v.Replica, oldObj.Replica)
return nil, fmt.Errorf("new replica %v should not be fewer than old replica %v", v.Replica, oldObj.Replica)
}
return nil
return nil, nil
}

func (v *TestValidator) ValidateDelete() error {
func (v *TestValidator) ValidateDelete() (admission.Warnings, error) {
if v.Panic {
panic("fake panic test")
}
if v.Replica > 0 {
return errors.New("number of replica should be less than or equal to 0 to delete")
return nil, errors.New("number of replica should be less than or equal to 0 to delete")
}
return nil
return nil, nil
}

// TestDefaultValidator.
Expand Down Expand Up @@ -824,25 +824,25 @@ func (dv *TestDefaultValidator) Default() {

var _ admission.Validator = &TestDefaultValidator{}

func (dv *TestDefaultValidator) ValidateCreate() error {
func (dv *TestDefaultValidator) ValidateCreate() (admission.Warnings, error) {
if dv.Replica < 0 {
return errors.New("number of replica should be greater than or equal to 0")
return nil, errors.New("number of replica should be greater than or equal to 0")
}
return nil
return nil, nil
}

func (dv *TestDefaultValidator) ValidateUpdate(old runtime.Object) error {
func (dv *TestDefaultValidator) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
if dv.Replica < 0 {
return errors.New("number of replica should be greater than or equal to 0")
return nil, errors.New("number of replica should be greater than or equal to 0")
}
return nil
return nil, nil
}

func (dv *TestDefaultValidator) ValidateDelete() error {
func (dv *TestDefaultValidator) ValidateDelete() (admission.Warnings, error) {
if dv.Replica > 0 {
return errors.New("number of replica should be less than or equal to 0 to delete")
return nil, errors.New("number of replica should be less than or equal to 0 to delete")
}
return nil
return nil, nil
}

// TestCustomDefaulter.
Expand Down Expand Up @@ -872,59 +872,59 @@ var _ admission.CustomDefaulter = &TestCustomDefaulter{}

type TestCustomValidator struct{}

func (*TestCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) error {
func (*TestCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
logf.FromContext(ctx).Info("Validating object")
req, err := admission.RequestFromContext(ctx)
if err != nil {
return fmt.Errorf("expected admission.Request in ctx: %w", err)
return nil, fmt.Errorf("expected admission.Request in ctx: %w", err)
}
if req.Kind.Kind != testValidatorKind {
return fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
return nil, fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
}

v := obj.(*TestValidator) //nolint:ifshort
if v.Replica < 0 {
return errors.New("number of replica should be greater than or equal to 0")
return nil, errors.New("number of replica should be greater than or equal to 0")
}
return nil
return nil, nil
}

func (*TestCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error {
func (*TestCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
logf.FromContext(ctx).Info("Validating object")
req, err := admission.RequestFromContext(ctx)
if err != nil {
return fmt.Errorf("expected admission.Request in ctx: %w", err)
return nil, fmt.Errorf("expected admission.Request in ctx: %w", err)
}
if req.Kind.Kind != testValidatorKind {
return fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
return nil, fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
}

v := newObj.(*TestValidator)
old := oldObj.(*TestValidator)
if v.Replica < 0 {
return errors.New("number of replica should be greater than or equal to 0")
return nil, errors.New("number of replica should be greater than or equal to 0")
}
if v.Replica < old.Replica {
return fmt.Errorf("new replica %v should not be fewer than old replica %v", v.Replica, old.Replica)
return nil, fmt.Errorf("new replica %v should not be fewer than old replica %v", v.Replica, old.Replica)
}
return nil
return nil, nil
}

func (*TestCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) error {
func (*TestCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
logf.FromContext(ctx).Info("Validating object")
req, err := admission.RequestFromContext(ctx)
if err != nil {
return fmt.Errorf("expected admission.Request in ctx: %w", err)
return nil, fmt.Errorf("expected admission.Request in ctx: %w", err)
}
if req.Kind.Kind != testValidatorKind {
return fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
return nil, fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
}

v := obj.(*TestValidator) //nolint:ifshort
if v.Replica > 0 {
return errors.New("number of replica should be less than or equal to 0 to delete")
return nil, errors.New("number of replica should be less than or equal to 0 to delete")
}
return nil
return nil, nil
}

var _ admission.CustomValidator = &TestCustomValidator{}
18 changes: 0 additions & 18 deletions pkg/webhook/admission/admissiontest/doc.go

This file was deleted.

66 changes: 0 additions & 66 deletions pkg/webhook/admission/admissiontest/util.go

This file was deleted.

0 comments on commit 1c2a7c9

Please sign in to comment.