-
Notifications
You must be signed in to change notification settings - Fork 104
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactored instance validation webhook (#1207)
Summary: existing `Validator` interface was removed, we're now using the underlying `http.Handler` interface to register webhooks. This reduces glue code and prepares the foundation for upcoming KEP-20 admission webhook which will use the same interface (but will be a mutating instead of validating webhook)
- Loading branch information
Aleksey Dukhovniy
committed
Dec 19, 2019
1 parent
ff75b96
commit 366222d
Showing
6 changed files
with
104 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,75 @@ | ||
package v1beta1 | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"reflect" | ||
|
||
"k8s.io/apimachinery/pkg/runtime" | ||
"github.com/coreos/etcd/client" | ||
"k8s.io/api/admission/v1beta1" | ||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission" | ||
|
||
"github.com/kudobuilder/kudo/pkg/util/kudo" | ||
) | ||
|
||
// this forces the instance type to implement Validator interface, we'll get compile time error if it's not true anymore | ||
var _ kudo.Validator = &Instance{} | ||
type InstanceValidator struct { | ||
client client.Client | ||
decoder *admission.Decoder | ||
} | ||
|
||
// InstanceValidator validates updates to an Instance, guarding from conflicting plan executions | ||
func (v *InstanceValidator) Handle(ctx context.Context, req admission.Request) admission.Response { | ||
|
||
// ValidateCreate implements kudo.Validator (slightly tweaked interface originally from controller-runtime) | ||
// we do not enforce any rules upon creation right now | ||
func (i *Instance) ValidateCreate(req admission.Request) error { | ||
return nil | ||
switch req.Operation { | ||
// we only validate Instance Updates | ||
case v1beta1.Update: | ||
old, new := &Instance{}, &Instance{} | ||
|
||
// req.Object contains the updated object | ||
if err := v.decoder.DecodeRaw(req.Object, new); err != nil { | ||
return admission.Errored(http.StatusBadRequest, err) | ||
} | ||
|
||
// req.OldObject is populated for DELETE and UPDATE requests | ||
if err := v.decoder.DecodeRaw(req.OldObject, old); err != nil { | ||
return admission.Errored(http.StatusBadRequest, err) | ||
} | ||
|
||
if err := validateUpdate(old, new); err != nil { | ||
return admission.Denied(err.Error()) | ||
} | ||
return admission.Allowed("") | ||
default: | ||
return admission.Allowed("") | ||
} | ||
} | ||
|
||
// ValidateUpdate hook called when UPDATE operation is triggered and our admission webhook is triggered | ||
// ValidateUpdate implements kudo.Validator (slightly tweaked interface originally from controller-runtime) | ||
func (i *Instance) ValidateUpdate(old runtime.Object, req admission.Request) error { | ||
oldInstance := old.(*Instance) | ||
if i.Status.AggregatedStatus.Status.IsRunning() && specChanged(i.Spec, oldInstance.Spec) { | ||
// when updating anything else than status, there shouldn't be a running plan | ||
return fmt.Errorf("cannot update Instance %s/%s right now, there's plan %s in progress", i.Namespace, i.Name, i.Status.AggregatedStatus.ActivePlanName) | ||
func validateUpdate(old, new *Instance) error { | ||
// Disallow spec updates when a plan is in progress | ||
if old.Status.AggregatedStatus.Status.IsRunning() && specChanged(old.Spec, new.Spec) { | ||
return fmt.Errorf("cannot update Instance %s/%s right now, there's plan %s in progress", old.Namespace, old.Name, old.Status.AggregatedStatus.ActivePlanName) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func specChanged(old InstanceSpec, new InstanceSpec) bool { | ||
return !reflect.DeepEqual(old, new) | ||
} | ||
|
||
// ValidateDelete hook called when DELETE operation is triggered and our admission webhook is triggered | ||
// we don't enforce any validation on DELETE right now | ||
// ValidateDelete implements kudo.Validator (slightly tweaked interface originally from controller-runtime) | ||
func (i *Instance) ValidateDelete(req admission.Request) error { | ||
// InstanceValidator implements inject.Client. | ||
// A client will be automatically injected. | ||
|
||
// InjectClient injects the client. | ||
func (v *InstanceValidator) InjectClient(c client.Client) error { | ||
v.client = c | ||
return nil | ||
} | ||
|
||
// InstanceValidator implements admission.DecoderInjector. | ||
// A decoder will be automatically injected. | ||
|
||
// InjectDecoder injects the decoder. | ||
func (v *InstanceValidator) InjectDecoder(d *admission.Decoder) error { | ||
v.decoder = d | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.