Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/webhooks/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ func DefaultAndValidateVariables(ctx context.Context, cluster, oldCluster *clust
oldMDVariables map[string][]clusterv1.ClusterVariable
oldMPVariables map[string][]clusterv1.ClusterVariable
)
if oldCluster != nil {
if oldCluster != nil && oldCluster.Spec.Topology != nil {
oldClusterVariables = oldCluster.Spec.Topology.Variables
if oldCluster.Spec.Topology.ControlPlane.Variables != nil {
oldCPOverrides = oldCluster.Spec.Topology.ControlPlane.Variables.Overrides
Expand Down
46 changes: 46 additions & 0 deletions internal/webhooks/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
utilfeature "k8s.io/component-base/featuregate/testing"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -1358,6 +1359,51 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) {
}
}

func TestClusterDefaultAndValidateVariables_OldClusterWithoutTopology(t *testing.T) {
// Regression test: adding topology to an existing cluster without topology should not panic.
utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)

g := NewWithT(t)

clusterClass := builder.ClusterClass(metav1.NamespaceDefault, "class1").
WithStatusVariables(clusterv1.ClusterClassStatusVariable{
Name: "location",
Definitions: []clusterv1.ClusterClassStatusVariableDefinition{
{
Required: true,
From: clusterv1.VariableDefinitionFromInline,
Schema: clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Type: "string",
Default: &apiextensionsv1.JSON{Raw: []byte(`"us-east"`)},
},
},
},
},
}).
Build()
conditions.MarkTrue(clusterClass, clusterv1.ClusterClassVariablesReconciledCondition)

// Old cluster exists but has NO topology (Spec.Topology == nil).
oldCluster := builder.Cluster(metav1.NamespaceDefault, "cluster1").Build()
g.Expect(oldCluster.Spec.Topology).To(BeNil())

// New cluster adds topology.
newCluster := builder.Cluster(metav1.NamespaceDefault, "cluster1").
WithTopology(builder.ClusterTopology().
WithClass("class1").
WithVersion("v1.22.2").
Build()).
Build()

// DefaultAndValidateVariables should not panic when oldCluster.Spec.Topology is nil.
var errs field.ErrorList
g.Expect(func() {
Comment thread
srm6867 marked this conversation as resolved.
errs = DefaultAndValidateVariables(ctx, newCluster, oldCluster, clusterClass)
}).ToNot(Panic())
g.Expect(errs).To(BeEmpty())
}

func TestClusterDefaultTopologyVersion(t *testing.T) {
// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to set Cluster.Topologies.
// Enabling the feature flag temporarily for this test.
Expand Down
Loading