Skip to content

Commit

Permalink
Add validation webhooks (GKE part 7)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardchen331 committed Feb 23, 2023
1 parent cb254f8 commit e219df1
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 9 deletions.
36 changes: 33 additions & 3 deletions exp/api/v1beta1/gcpmanagedcluster_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ limitations under the License.
package v1beta1

import (
"github.com/google/go-cmp/cmp"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
Expand Down Expand Up @@ -53,10 +56,37 @@ func (r *GCPManagedCluster) ValidateCreate() error {
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
func (r *GCPManagedCluster) ValidateUpdate(old runtime.Object) error {
func (r *GCPManagedCluster) ValidateUpdate(oldRaw runtime.Object) error {
gcpmanagedclusterlog.Info("validate update", "name", r.Name)

return nil
var allErrs field.ErrorList
old := oldRaw.(*GCPManagedCluster)

if !cmp.Equal(r.Spec.Project, old.Spec.Project) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "Project"),
r.Spec.Project, "field is immutable"),
)
}

if !cmp.Equal(r.Spec.Region, old.Spec.Region) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "Region"),
r.Spec.Region, "field is immutable"),
)
}

if !cmp.Equal(r.Spec.CredentialsRef, old.Spec.CredentialsRef) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "CredentialsRef"),
r.Spec.CredentialsRef, "field is immutable"),
)
}

if len(allErrs) == 0 {
return nil
}

return apierrors.NewInvalid(GroupVersion.WithKind("GCPManagedCluster").GroupKind(), r.Name, allErrs)
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
Expand Down
57 changes: 54 additions & 3 deletions exp/api/v1beta1/gcpmanagedcontrolplane_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ import (
"fmt"
"strings"

"github.com/google/go-cmp/cmp"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/validation/field"

"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/cluster-api-provider-gcp/util/hash"
Expand Down Expand Up @@ -70,15 +75,61 @@ var _ webhook.Validator = &GCPManagedControlPlane{}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (r *GCPManagedControlPlane) ValidateCreate() error {
gcpmanagedcontrolplanelog.Info("validate create", "name", r.Name)
var allErrs field.ErrorList

return nil
if len(r.Spec.ClusterName) > maxClusterNameLength {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "ClusterName"),
r.Spec.ClusterName, fmt.Sprintf("cluster name cannot have more than %d characters", maxClusterNameLength)),
)
}

if len(allErrs) == 0 {
return nil
}

return apierrors.NewInvalid(GroupVersion.WithKind("GCPManagedControlPlane").GroupKind(), r.Name, allErrs)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
func (r *GCPManagedControlPlane) ValidateUpdate(old runtime.Object) error {
func (r *GCPManagedControlPlane) ValidateUpdate(oldRaw runtime.Object) error {
gcpmanagedcontrolplanelog.Info("validate update", "name", r.Name)
var allErrs field.ErrorList
old := oldRaw.(*GCPManagedControlPlane)

if !cmp.Equal(r.Spec.ClusterName, old.Spec.ClusterName) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "ClusterName"),
r.Spec.ClusterName, "field is immutable"),
)
}

return nil
if !cmp.Equal(r.Spec.Project, old.Spec.Project) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "Project"),
r.Spec.Project, "field is immutable"),
)
}

if !cmp.Equal(r.Spec.Location, old.Spec.Location) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "Location"),
r.Spec.Location, "field is immutable"),
)
}

if !cmp.Equal(r.Spec.EnableAutopilot, old.Spec.EnableAutopilot) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "EnableAutopilot"),
r.Spec.EnableAutopilot, "field is immutable"),
)
}

if len(allErrs) == 0 {
return nil
}

return apierrors.NewInvalid(GroupVersion.WithKind("GCPManagedControlPlane").GroupKind(), r.Name, allErrs)
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
Expand Down
98 changes: 95 additions & 3 deletions exp/api/v1beta1/gcpmanagedmachinepool_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,21 @@ limitations under the License.
package v1beta1

import (
"fmt"

"github.com/google/go-cmp/cmp"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)

const (
maxNodePoolNameLength = 40
)

// log is for logging in this package.
var gcpmanagedmachinepoollog = logf.Log.WithName("gcpmanagedmachinepool-resource")

Expand All @@ -45,18 +54,101 @@ func (r *GCPManagedMachinePool) Default() {

var _ webhook.Validator = &GCPManagedMachinePool{}

func (r *GCPManagedMachinePool) validateNodeCount() field.ErrorList {
var allErrs field.ErrorList
if r.Spec.InitialNodeCount < 0 {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "InitialNodeCount"),
r.Spec.InitialNodeCount, "must be greater or equal to zero"),
)
}
if len(allErrs) == 0 {
return nil
}
return allErrs
}

func (r *GCPManagedMachinePool) validateScaling() field.ErrorList {
var allErrs field.ErrorList
if r.Spec.Scaling != nil {
minField := field.NewPath("spec", "scaling", "minCount")
maxField := field.NewPath("spec", "scaling", "maxCount")
min := r.Spec.Scaling.MinCount
max := r.Spec.Scaling.MaxCount
if min != nil {
if *min < 0 {
allErrs = append(allErrs, field.Invalid(minField, *min, "must be greater or equal zero"))
}
if *min > r.Spec.InitialNodeCount {
allErrs = append(allErrs, field.Invalid(minField, *min, fmt.Sprintf("must be less or equal to %d", r.Spec.InitialNodeCount)))
}
if max != nil && *max < *min {
allErrs = append(allErrs, field.Invalid(maxField, *max, fmt.Sprintf("must be greater than field %s", minField.String())))
}
}
if max != nil && *max < r.Spec.InitialNodeCount {
allErrs = append(allErrs, field.Invalid(maxField, *max, fmt.Sprintf("must be greater or equal to %d", r.Spec.InitialNodeCount)))
}
}
if len(allErrs) == 0 {
return nil
}
return allErrs
}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (r *GCPManagedMachinePool) ValidateCreate() error {
gcpmanagedmachinepoollog.Info("validate create", "name", r.Name)
var allErrs field.ErrorList

return nil
if len(r.Spec.NodePoolName) > maxNodePoolNameLength {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "NodePoolName"),
r.Spec.NodePoolName, fmt.Sprintf("node pool name cannot have more than %d characters", maxNodePoolNameLength)),
)
}

if errs := r.validateNodeCount(); errs != nil || len(errs) == 0 {
allErrs = append(allErrs, errs...)
}

if errs := r.validateScaling(); errs != nil || len(errs) == 0 {
allErrs = append(allErrs, errs...)
}

if len(allErrs) == 0 {
return nil
}

return apierrors.NewInvalid(GroupVersion.WithKind("GCPManagedMachinePool").GroupKind(), r.Name, allErrs)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
func (r *GCPManagedMachinePool) ValidateUpdate(old runtime.Object) error {
func (r *GCPManagedMachinePool) ValidateUpdate(oldRaw runtime.Object) error {
gcpmanagedmachinepoollog.Info("validate update", "name", r.Name)
var allErrs field.ErrorList
old := oldRaw.(*GCPManagedMachinePool)

return nil
if !cmp.Equal(r.Spec.NodePoolName, old.Spec.NodePoolName) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "NodePoolName"),
r.Spec.NodePoolName, "field is immutable"),
)
}

if errs := r.validateNodeCount(); errs != nil || len(errs) == 0 {
allErrs = append(allErrs, errs...)
}

if errs := r.validateScaling(); errs != nil || len(errs) == 0 {
allErrs = append(allErrs, errs...)
}

if len(allErrs) == 0 {
return nil
}

return apierrors.NewInvalid(GroupVersion.WithKind("GCPManagedMachinePool").GroupKind(), r.Name, allErrs)
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
Expand Down

0 comments on commit e219df1

Please sign in to comment.