@@ -97,7 +97,10 @@ func (webhook *Cluster) Default(ctx context.Context, obj runtime.Object) error {
97
97
return apierrors .NewInternalError (errors .Wrapf (err , "Cluster %s can't be defaulted. ClusterClass %s can not be retrieved" , cluster .Name , cluster .Spec .Topology .Class ))
98
98
}
99
99
100
- allErrs = append (allErrs , DefaultVariables (cluster , clusterClass )... )
100
+ // Doing both defaulting and validating here prevents a race condition where the ClusterClass could be
101
+ // different in the defaulting and validating webhook.
102
+ allErrs = append (allErrs , DefaultAndValidateVariables (cluster , clusterClass )... )
103
+
101
104
if len (allErrs ) > 0 {
102
105
return apierrors .NewInvalid (clusterv1 .GroupVersion .WithKind ("Cluster" ).GroupKind (), cluster .Name , allErrs )
103
106
}
@@ -256,7 +259,7 @@ func (webhook *Cluster) validateTopology(ctx context.Context, oldCluster, newClu
256
259
}
257
260
if clusterClassPollErr == nil {
258
261
// If there's no error validate the Cluster based on the ClusterClass.
259
- allErrs = append (allErrs , ValidateClusterForClusterClass (newCluster , clusterClass , fldPath )... )
262
+ allErrs = append (allErrs , ValidateClusterForClusterClass (newCluster , clusterClass )... )
260
263
}
261
264
if oldCluster != nil { // On update
262
265
// The ClusterClass must exist to proceed with update validation. Return an error if the ClusterClass was
@@ -453,6 +456,29 @@ func validateCIDRBlocks(fldPath *field.Path, cidrs []string) field.ErrorList {
453
456
return allErrs
454
457
}
455
458
459
+ // DefaultAndValidateVariables defaults and validates variables in the Cluster and MachineDeployment topologies based
460
+ // on the definitions in the ClusterClass.
461
+ func DefaultAndValidateVariables (cluster * clusterv1.Cluster , clusterClass * clusterv1.ClusterClass ) field.ErrorList {
462
+ var allErrs field.ErrorList
463
+ allErrs = append (allErrs , DefaultVariables (cluster , clusterClass )... )
464
+
465
+ // Variables must be validated in the defaulting webhook. Variable definitions are stored in the ClusterClass status
466
+ // and are patched in the ClusterClass reconcile.
467
+ allErrs = append (allErrs , variables .ValidateClusterVariables (cluster .Spec .Topology .Variables , clusterClass .Status .Variables ,
468
+ field .NewPath ("spec" , "topology" , "variables" ))... )
469
+ if cluster .Spec .Topology .Workers != nil {
470
+ for i , md := range cluster .Spec .Topology .Workers .MachineDeployments {
471
+ // Continue if there are no variable overrides.
472
+ if md .Variables == nil || len (md .Variables .Overrides ) == 0 {
473
+ continue
474
+ }
475
+ allErrs = append (allErrs , variables .ValidateMachineDeploymentVariables (md .Variables .Overrides , clusterClass .Status .Variables ,
476
+ field .NewPath ("spec" , "topology" , "workers" , "machineDeployments" ).Index (i ).Child ("variables" , "overrides" ))... )
477
+ }
478
+ }
479
+ return allErrs
480
+ }
481
+
456
482
// DefaultVariables defaults variables in the Cluster based on information in the ClusterClass.
457
483
func DefaultVariables (cluster * clusterv1.Cluster , clusterClass * clusterv1.ClusterClass ) field.ErrorList {
458
484
var allErrs field.ErrorList
@@ -489,7 +515,7 @@ func DefaultVariables(cluster *clusterv1.Cluster, clusterClass *clusterv1.Cluste
489
515
}
490
516
491
517
// ValidateClusterForClusterClass uses information in the ClusterClass to validate the Cluster.
492
- func ValidateClusterForClusterClass (cluster * clusterv1.Cluster , clusterClass * clusterv1.ClusterClass , fldPath * field. Path ) field.ErrorList {
518
+ func ValidateClusterForClusterClass (cluster * clusterv1.Cluster , clusterClass * clusterv1.ClusterClass ) field.ErrorList {
493
519
var allErrs field.ErrorList
494
520
if cluster == nil {
495
521
return field.ErrorList {field .InternalError (field .NewPath ("" ), errors .New ("Cluster can not be nil" ))}
@@ -499,24 +525,8 @@ func ValidateClusterForClusterClass(cluster *clusterv1.Cluster, clusterClass *cl
499
525
}
500
526
allErrs = append (allErrs , check .MachineDeploymentTopologiesAreValidAndDefinedInClusterClass (cluster , clusterClass )... )
501
527
502
- // validate the MachineHealthChecks defined in the cluster topology
528
+ // Validate the MachineHealthChecks defined in the cluster topology.
503
529
allErrs = append (allErrs , validateMachineHealthChecks (cluster , clusterClass )... )
504
-
505
- // Check if the variables defined in the ClusterClass are valid.
506
- allErrs = append (allErrs , variables .ValidateClusterVariables (cluster .Spec .Topology .Variables , clusterClass .Status .Variables ,
507
- fldPath .Child ("variables" ))... )
508
-
509
- if cluster .Spec .Topology .Workers != nil {
510
- for i , md := range cluster .Spec .Topology .Workers .MachineDeployments {
511
- // Continue if there are no variable overrides.
512
- if md .Variables == nil || len (md .Variables .Overrides ) == 0 {
513
- continue
514
- }
515
- allErrs = append (allErrs , variables .ValidateMachineDeploymentVariables (md .Variables .Overrides , clusterClass .Status .Variables ,
516
- fldPath .Child ("workers" , "machineDeployments" ).Index (i ).Child ("variables" , "overrides" ))... )
517
- }
518
- }
519
-
520
530
return allErrs
521
531
}
522
532
0 commit comments