@@ -17,13 +17,17 @@ limitations under the License.
1717package v1beta1
1818
1919import (
20+ "context"
21+ "fmt"
2022 "reflect"
2123
2224 apierrors "k8s.io/apimachinery/pkg/api/errors"
2325 "k8s.io/apimachinery/pkg/runtime"
2426 "k8s.io/apimachinery/pkg/util/validation/field"
27+ "sigs.k8s.io/cluster-api/util/topology"
2528 ctrl "sigs.k8s.io/controller-runtime"
2629 "sigs.k8s.io/controller-runtime/pkg/webhook"
30+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2731)
2832
2933// AzureMachineTemplateImmutableMsg ...
@@ -36,40 +40,50 @@ const (
3640func (r * AzureMachineTemplate ) SetupWebhookWithManager (mgr ctrl.Manager ) error {
3741 return ctrl .NewWebhookManagedBy (mgr ).
3842 For (r ).
43+ WithValidator (r ).
44+ WithDefaulter (r ).
3945 Complete ()
4046}
4147
4248// +kubebuilder:webhook:verbs=create;update,path=/mutate-infrastructure-cluster-x-k8s-io-v1beta1-azuremachinetemplate,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=azuremachinetemplates,versions=v1beta1,name=default.azuremachinetemplate.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
4349// +kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-azuremachinetemplate,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=azuremachinetemplates,versions=v1beta1,name=validation.azuremachinetemplate.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
4450
45- var _ webhook.Defaulter = & AzureMachineTemplate {}
46- var _ webhook.Validator = & AzureMachineTemplate {}
51+ var _ webhook.CustomDefaulter = & AzureMachineTemplate {}
52+ var _ webhook.CustomValidator = & AzureMachineTemplate {}
4753
48- // ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
49- func (r * AzureMachineTemplate ) ValidateCreate () error {
50- spec := r .Spec .Template .Spec
54+ // ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type.
55+ func (r * AzureMachineTemplate ) ValidateCreate (ctx context.Context , obj runtime.Object ) error {
56+ t := obj .(* AzureMachineTemplate )
57+ spec := t .Spec .Template .Spec
5158
5259 allErrs := ValidateAzureMachineSpec (spec )
5360
54- if r . Spec . Template . Spec .RoleAssignmentName != "" {
61+ if spec .RoleAssignmentName != "" {
5562 allErrs = append (allErrs ,
56- field .Invalid (field .NewPath ("AzureMachineTemplate" , "spec" , "template" , "spec" , "roleAssignmentName" ), r , AzureMachineTemplateRoleAssignmentNameMsg ),
63+ field .Invalid (field .NewPath ("AzureMachineTemplate" , "spec" , "template" , "spec" , "roleAssignmentName" ), t , AzureMachineTemplateRoleAssignmentNameMsg ),
5764 )
5865 }
5966
6067 if len (allErrs ) == 0 {
6168 return nil
6269 }
6370
64- return apierrors .NewInvalid (GroupVersion .WithKind ("AzureMachineTemplate" ).GroupKind (), r .Name , allErrs )
71+ return apierrors .NewInvalid (GroupVersion .WithKind ("AzureMachineTemplate" ).GroupKind (), t .Name , allErrs )
6572}
6673
6774// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
68- func (r * AzureMachineTemplate ) ValidateUpdate (oldRaw runtime.Object ) error {
75+ func (r * AzureMachineTemplate ) ValidateUpdate (ctx context. Context , oldRaw runtime. Object , newRaw runtime.Object ) error {
6976 var allErrs field.ErrorList
7077 old := oldRaw .(* AzureMachineTemplate )
78+ t := newRaw .(* AzureMachineTemplate )
7179
72- if ! reflect .DeepEqual (r .Spec .Template .Spec , old .Spec .Template .Spec ) {
80+ req , err := admission .RequestFromContext (ctx )
81+ if err != nil {
82+ return apierrors .NewBadRequest (fmt .Sprintf ("expected a admission.Request inside context: %v" , err ))
83+ }
84+
85+ if ! topology .ShouldSkipImmutabilityChecks (req , t ) &&
86+ ! reflect .DeepEqual (t .Spec .Template .Spec , old .Spec .Template .Spec ) {
7387 // The equality failure could be because of default mismatch between v1alpha3 and v1beta1. This happens because
7488 // the new object `r` will have run through the default webhooks but the old object `old` would not have so.
7589 // This means if the old object was in v1alpha3, it would not get the new defaults set in v1beta1 resulting
@@ -78,35 +92,41 @@ func (r *AzureMachineTemplate) ValidateUpdate(oldRaw runtime.Object) error {
7892
7993 // We need to set ssh key explicitly, otherwise Default() will create a new one.
8094 if old .Spec .Template .Spec .SSHPublicKey == "" {
81- old .Spec .Template .Spec .SSHPublicKey = r .Spec .Template .Spec .SSHPublicKey
95+ old .Spec .Template .Spec .SSHPublicKey = t .Spec .Template .Spec .SSHPublicKey
8296 }
8397
84- old .Default ()
98+ if err := r .Default (ctx , old ); err != nil {
99+ allErrs = append (allErrs ,
100+ field .Invalid (field .NewPath ("AzureMachineTemplate" ), r , fmt .Sprintf ("Unable to apply defaults: %v" , err )),
101+ )
102+ }
85103
86104 // if it's still not equal, return error.
87- if ! reflect .DeepEqual (r .Spec .Template .Spec , old .Spec .Template .Spec ) {
105+ if ! reflect .DeepEqual (t .Spec .Template .Spec , old .Spec .Template .Spec ) {
88106 allErrs = append (allErrs ,
89- field .Invalid (field .NewPath ("AzureMachineTemplate" , "spec" , "template" , "spec" ), r , AzureMachineTemplateImmutableMsg ),
107+ field .Invalid (field .NewPath ("AzureMachineTemplate" , "spec" , "template" , "spec" ), t , AzureMachineTemplateImmutableMsg ),
90108 )
91109 }
92110 }
93111
94112 if len (allErrs ) == 0 {
95113 return nil
96114 }
97- return apierrors .NewInvalid (GroupVersion .WithKind ("AzureMachineTemplate" ).GroupKind (), r .Name , allErrs )
115+ return apierrors .NewInvalid (GroupVersion .WithKind ("AzureMachineTemplate" ).GroupKind (), t .Name , allErrs )
98116}
99117
100118// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
101- func (r * AzureMachineTemplate ) ValidateDelete () error {
119+ func (r * AzureMachineTemplate ) ValidateDelete (ctx context. Context , obj runtime. Object ) error {
102120 return nil
103121}
104122
105123// Default implements webhookutil.defaulter so a webhook will be registered for the type.
106- func (r * AzureMachineTemplate ) Default () {
107- if err := r .Spec .Template .Spec .SetDefaultSSHPublicKey (); err != nil {
124+ func (r * AzureMachineTemplate ) Default (ctx context.Context , obj runtime.Object ) error {
125+ t := obj .(* AzureMachineTemplate )
126+ if err := t .Spec .Template .Spec .SetDefaultSSHPublicKey (); err != nil {
108127 ctrl .Log .WithName ("SetDefault" ).Error (err , "SetDefaultSSHPublicKey failed" )
109128 }
110- r .Spec .Template .Spec .SetDefaultCachingType ()
111- r .Spec .Template .Spec .SetDataDisksDefaults ()
129+ t .Spec .Template .Spec .SetDefaultCachingType ()
130+ t .Spec .Template .Spec .SetDataDisksDefaults ()
131+ return nil
112132}
0 commit comments