From eeea4e10fe867676e8e6f3124c2201cc38fc0c60 Mon Sep 17 00:00:00 2001 From: Pankti Shah <58618433+panktishah26@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:44:29 -0700 Subject: [PATCH] 1. Validates Cloudstack template name and kubernetes version from the controller side and waits for both to match for further reconciliation. (#6728) 2. Since we have seperated ETCD and CP reconciliation, it waits for ETCD to be ready before marking ControlPlaneReady to true. 3. From the CLI side during management cluster upgrade, waits for Cluster FailureMessage to be nil before waiting for other condition to met. --- pkg/cluster/config.go | 4 +- pkg/cluster/wait.go | 31 ++-- pkg/cluster/wait_test.go | 110 ++++++++++++ pkg/clustermanager/applier.go | 10 ++ pkg/clustermanager/applier_test.go | 17 ++ pkg/controller/clusters/status.go | 26 ++- pkg/controller/clusters/status_test.go | 167 ++++++++++++++++-- pkg/providers/cloudstack/controlplane_test.go | 2 +- .../cloudstack/reconciler/reconciler_test.go | 7 +- .../cloudstack/testdata/cluster_main.yaml | 6 +- .../cluster_main_with_cp_node_labels.yaml | 6 +- .../cluster_main_with_node_labels.yaml | 6 +- .../expected_results_main_autoscaling_md.yaml | 2 +- .../testdata/expected_results_main_cp.yaml | 4 +- .../testdata/expected_results_main_md.yaml | 2 +- ...lts_main_no_machinetemplate_update_cp.yaml | 4 +- ...lts_main_no_machinetemplate_update_md.yaml | 2 +- .../expected_results_main_node_labels_cp.yaml | 4 +- .../expected_results_main_node_labels_md.yaml | 2 +- .../expected_results_resourceids_cp.yaml | 4 +- pkg/providers/cloudstack/validator.go | 20 +++ pkg/providers/cloudstack/validator_test.go | 26 ++- 22 files changed, 409 insertions(+), 53 deletions(-) diff --git a/pkg/cluster/config.go b/pkg/cluster/config.go index 4772c4297b4d..46d3e008e395 100644 --- a/pkg/cluster/config.go +++ b/pkg/cluster/config.go @@ -202,8 +202,8 @@ func (c *Config) ChildObjects() []kubernetes.Object { // ClusterAndChildren returns all kubernetes objects in the cluster Config. // It's equivalent to appending the Cluster to the result of ChildObjects. func (c *Config) ClusterAndChildren() []kubernetes.Object { - objs := c.ChildObjects() - return append(objs, c.Cluster) + objs := []kubernetes.Object{c.Cluster} + return append(objs, c.ChildObjects()...) } func appendIfNotNil(objs []kubernetes.Object, elems ...kubernetes.Object) []kubernetes.Object { diff --git a/pkg/cluster/wait.go b/pkg/cluster/wait.go index 70fb20542d87..1bec3167c0fc 100644 --- a/pkg/cluster/wait.go +++ b/pkg/cluster/wait.go @@ -17,6 +17,26 @@ import ( // or the retrier timeouts. If observedGeneration is not equal to generation, // the condition is considered false regardless of the status value. func WaitForCondition(ctx context.Context, client kubernetes.Reader, cluster *anywherev1.Cluster, retrier *retrier.Retrier, conditionType anywherev1.ConditionType) error { + return WaitFor(ctx, client, cluster, retrier, func(c *anywherev1.Cluster) error { + condition := conditions.Get(c, conditionType) + if condition == nil { + return fmt.Errorf("cluster doesn't yet have condition %s", conditionType) + } + + if condition.Status != corev1.ConditionTrue { + return fmt.Errorf("cluster condition %s is %s: %s", conditionType, condition.Status, condition.Message) + } + return nil + }) +} + +// Matcher matches the given condition. +type Matcher func(*anywherev1.Cluster) error + +// WaitFor gets the cluster object from the client +// checks for generation and observedGeneration condition +// matches condition and returns error if the condition is not met. +func WaitFor(ctx context.Context, client kubernetes.Reader, cluster *anywherev1.Cluster, retrier *retrier.Retrier, matcher Matcher) error { return retrier.Retry(func() error { c := &anywherev1.Cluster{} @@ -35,15 +55,6 @@ func WaitForCondition(ctx context.Context, client kubernetes.Reader, cluster *an return fmt.Errorf("cluster generation (%d) and observedGeneration (%d) differ", generation, observedGeneration) } - condition := conditions.Get(c, conditionType) - if condition == nil { - return fmt.Errorf("cluster doesn't yet have condition %s", conditionType) - } - - if condition.Status != corev1.ConditionTrue { - return fmt.Errorf("cluster condition %s is %s: %s", conditionType, condition.Status, condition.Message) - } - - return nil + return matcher(c) }) } diff --git a/pkg/cluster/wait_test.go b/pkg/cluster/wait_test.go index 7526beef2171..fa1532f9767c 100644 --- a/pkg/cluster/wait_test.go +++ b/pkg/cluster/wait_test.go @@ -2,6 +2,7 @@ package cluster_test import ( "context" + "fmt" "testing" . "github.com/onsi/gomega" @@ -153,3 +154,112 @@ func TestWaitForCondition(t *testing.T) { }) } } + +func TestWaitFor(t *testing.T) { + testCases := []struct { + name string + clusterInput, currentCluster *anywherev1.Cluster + retrier *retrier.Retrier + matcher func(_ *anywherev1.Cluster) error + wantErr string + }{ + { + name: "cluster does not exist", + clusterInput: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-c", + Namespace: "my-n", + }, + }, + currentCluster: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-c", + Namespace: "default", + }, + }, + retrier: retrier.NewWithMaxRetries(1, 0), + matcher: func(_ *anywherev1.Cluster) error { + return nil + }, + wantErr: "clusters.anywhere.eks.amazonaws.com \"my-c\" not found", + }, + { + name: "cluster namespace not provided", + clusterInput: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-c", + }, + }, + currentCluster: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-c", + Namespace: "eksa-namespace", + }, + }, + retrier: retrier.NewWithMaxRetries(1, 0), + matcher: func(_ *anywherev1.Cluster) error { + return nil + }, + wantErr: "clusters.anywhere.eks.amazonaws.com \"my-c\" not found", + }, + { + name: "observed generation not updated", + clusterInput: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-c", + Namespace: "my-n", + }, + }, + currentCluster: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-c", + Namespace: "my-n", + Generation: 5, + }, + Status: anywherev1.ClusterStatus{ + ObservedGeneration: 4, + }, + }, + retrier: retrier.NewWithMaxRetries(1, 0), + matcher: func(_ *anywherev1.Cluster) error { + return nil + }, + wantErr: "cluster generation (5) and observedGeneration (4) differ", + }, + { + name: "matcher return error", + clusterInput: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-c", + Namespace: "my-n", + }, + }, + currentCluster: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-c", + Namespace: "my-n", + }, + }, + retrier: retrier.NewWithMaxRetries(1, 0), + matcher: func(_ *anywherev1.Cluster) error { + return fmt.Errorf("error") + }, + wantErr: "error", + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + g := NewWithT(t) + client := test.NewFakeKubeClient(tt.currentCluster) + + gotErr := cluster.WaitFor(ctx, client, tt.clusterInput, tt.retrier, tt.matcher) + if tt.wantErr != "" { + g.Expect(gotErr).To(MatchError(tt.wantErr)) + } else { + g.Expect(gotErr).NotTo(HaveOccurred()) + } + }) + } +} diff --git a/pkg/clustermanager/applier.go b/pkg/clustermanager/applier.go index 3247303ccd0d..cdda11d14d72 100644 --- a/pkg/clustermanager/applier.go +++ b/pkg/clustermanager/applier.go @@ -2,6 +2,7 @@ package clustermanager import ( "context" + "fmt" "math" "time" @@ -129,6 +130,15 @@ func (a Applier) Run(ctx context.Context, spec *cluster.Spec, managementCluster waitStartTime := time.Now() retry := a.retrierForWait(waitStartTime) + if err := cluster.WaitFor(ctx, client, spec.Cluster, retrier.New(5*time.Second), func(c *anywherev1.Cluster) error { + if c.Status.FailureMessage != nil && *c.Status.FailureMessage != "" { + return fmt.Errorf("cluster has an error: %s", *c.Status.FailureMessage) + } + return nil + }); err != nil { + return fmt.Errorf("cluster has a validation error that doesn't seem transient: %s", err) + } + a.log.V(3).Info("Waiting for control plane to be ready") if err := cluster.WaitForCondition(ctx, client, spec.Cluster, retry, anywherev1.ControlPlaneReadyCondition); err != nil { return errors.Wrapf(err, "waiting for cluster's control plane to be ready") diff --git a/pkg/clustermanager/applier_test.go b/pkg/clustermanager/applier_test.go index 0710887a8cfe..a02df9a7a94d 100644 --- a/pkg/clustermanager/applier_test.go +++ b/pkg/clustermanager/applier_test.go @@ -54,6 +54,11 @@ func (a *applierTest) buildClient(objs ...kubernetes.Object) { a.clientFactory.EXPECT().BuildClientFromKubeconfig(a.mgmtCluster.KubeconfigFile).Return(a.client, nil) } +func (a *applierTest) updateFailureMessage(c *anywherev1.Cluster, err string) { + c.Status.FailureMessage = ptr.String(err) + a.Expect(a.client.Update(a.ctx, c)).To(Succeed()) +} + func (a *applierTest) markCPReady(c *anywherev1.Cluster) { conditions.MarkTrue(c, anywherev1.ControlPlaneReadyCondition) a.Expect(a.client.Update(a.ctx, c)).To(Succeed()) @@ -173,6 +178,18 @@ func TestApplierRunErrorApplying(t *testing.T) { tt.Expect(a.Run(tt.ctx, tt.spec, tt.mgmtCluster)).To(MatchError(ContainSubstring("applying cluster spec"))) } +func TestApplierRunFailureMessage(t *testing.T) { + tt := newApplierTest(t) + tt.buildClient(tt.spec.ClusterAndChildren()...) + tt.updateFailureMessage(tt.spec.Cluster, "error") + tt.startFakeController() + a := clustermanager.NewApplier(tt.log, tt.clientFactory, + clustermanager.WithApplierRetryBackOff(time.Millisecond), + ) + + tt.Expect(a.Run(tt.ctx, tt.spec, tt.mgmtCluster)).To(MatchError(ContainSubstring("cluster has a validation error that doesn't seem transient"))) +} + func TestApplierRunControlPlaneNotReady(t *testing.T) { tt := newApplierTest(t) tt.buildClient() diff --git a/pkg/controller/clusters/status.go b/pkg/controller/clusters/status.go index b38fbb8ad12d..88f7ebb32240 100644 --- a/pkg/controller/clusters/status.go +++ b/pkg/controller/clusters/status.go @@ -3,6 +3,7 @@ package clusters import ( "context" + etcdv1 "github.com/aws/etcdadm-controller/api/v1beta1" "github.com/pkg/errors" v1 "k8s.io/api/core/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -22,8 +23,21 @@ func UpdateClusterStatusForControlPlane(ctx context.Context, client client.Clien return errors.Wrapf(err, "getting kubeadmcontrolplane") } + var etcdadmCluster *etcdv1.EtcdadmCluster + if cluster.Spec.ExternalEtcdConfiguration != nil { + capiCluster, err := controller.GetCAPICluster(ctx, client, cluster) + if err != nil { + return errors.Wrap(err, "getting capi cluster") + } + + etcdadmCluster, err = getEtcdadmCluster(ctx, client, capiCluster) + if err != nil { + return errors.Wrap(err, "reading etcdadm cluster") + } + } + updateControlPlaneInitializedCondition(cluster, kcp) - updateControlPlaneReadyCondition(cluster, kcp) + updateConditionsForEtcdAndControlPlane(cluster, kcp, etcdadmCluster) return nil } @@ -68,6 +82,16 @@ func UpdateClusterStatusForCNI(ctx context.Context, cluster *anywherev1.Cluster) } } +// updateConditionsForEtcdAndControlPlane updates the ControlPlaneReady condition if etcdadm cluster is not ready. +func updateConditionsForEtcdAndControlPlane(cluster *anywherev1.Cluster, kcp *controlplanev1.KubeadmControlPlane, etcdadmCluster *etcdv1.EtcdadmCluster) { + // Make sure etcd cluster is ready before marking ControlPlaneReady status to true + if cluster.Spec.ExternalEtcdConfiguration != nil && !etcdadmClusterReady(etcdadmCluster) { + conditions.MarkFalse(cluster, anywherev1.ControlPlaneReadyCondition, anywherev1.RollingUpgradeInProgress, clusterv1.ConditionSeverityInfo, "Etcd is not ready") + return + } + updateControlPlaneReadyCondition(cluster, kcp) +} + // updateControlPlaneReadyCondition updates the ControlPlaneReady condition, after checking the state of the control plane // in the cluster. func updateControlPlaneReadyCondition(cluster *anywherev1.Cluster, kcp *controlplanev1.KubeadmControlPlane) { diff --git a/pkg/controller/clusters/status_test.go b/pkg/controller/clusters/status_test.go index 57a5ea0f4405..f49ab0186da8 100644 --- a/pkg/controller/clusters/status_test.go +++ b/pkg/controller/clusters/status_test.go @@ -2,9 +2,13 @@ package clusters_test import ( "context" + "fmt" "testing" + etcdv1 "github.com/aws/etcdadm-controller/api/v1beta1" . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" @@ -27,17 +31,21 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { g := NewWithT(t) tests := []struct { - name string - kcp *controlplanev1.KubeadmControlPlane - controlPlaneCount int - conditions []anywherev1.Condition - wantCondition *anywherev1.Condition + name string + kcp *controlplanev1.KubeadmControlPlane + controlPlaneCount int + conditions []anywherev1.Condition + wantCondition *anywherev1.Condition + externalEtcdCount int + externalEtcdCluster *etcdv1.EtcdadmCluster }{ { - name: "kcp is nil", - kcp: nil, - controlPlaneCount: 1, - conditions: []anywherev1.Condition{}, + name: "kcp is nil", + kcp: nil, + controlPlaneCount: 1, + conditions: []anywherev1.Condition{}, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: "ControlPlaneInitialized", Status: "False", @@ -63,6 +71,8 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { Status: "True", }, }, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneInitializedCondition, Status: "True", @@ -74,7 +84,9 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { kcp.ObjectMeta.Generation = 1 kcp.Status.ObservedGeneration = 0 }), - controlPlaneCount: 1, + controlPlaneCount: 1, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneInitializedCondition, Status: "False", @@ -93,8 +105,10 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { }, } }), - controlPlaneCount: 1, - conditions: []anywherev1.Condition{}, + controlPlaneCount: 1, + conditions: []anywherev1.Condition{}, + externalEtcdCluster: nil, + externalEtcdCount: 0, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneInitializedCondition, Status: "False", @@ -113,8 +127,10 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { }, } }), - controlPlaneCount: 1, - conditions: []anywherev1.Condition{}, + controlPlaneCount: 1, + conditions: []anywherev1.Condition{}, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneInitializedCondition, Status: "True", @@ -133,6 +149,8 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { Message: controlPlaneInitalizationInProgressReason, }, }, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Status: "False", @@ -155,6 +173,8 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { Status: "True", }, }, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Status: "True", @@ -173,6 +193,8 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { Status: "True", }, }, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Status: "False", @@ -194,12 +216,14 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { } }), controlPlaneCount: 3, + externalEtcdCount: 0, conditions: []anywherev1.Condition{ { Type: anywherev1.ControlPlaneInitializedCondition, Status: "True", }, }, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Status: "False", @@ -223,12 +247,14 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { } }), controlPlaneCount: 1, + externalEtcdCount: 0, conditions: []anywherev1.Condition{ { Type: anywherev1.ControlPlaneInitializedCondition, Status: "True", }, }, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Status: "False", @@ -253,12 +279,14 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { } }), controlPlaneCount: 3, + externalEtcdCount: 0, conditions: []anywherev1.Condition{ { Type: anywherev1.ControlPlaneInitializedCondition, Status: "True", }, }, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Status: "False", @@ -288,6 +316,8 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { Status: "True", }, }, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Status: "False", @@ -324,6 +354,8 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { Status: "True", }, }, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Reason: anywherev1.ControlPlaneComponentsUnhealthyReason, @@ -353,11 +385,91 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { Status: "True", }, }, + externalEtcdCount: 0, + externalEtcdCluster: nil, wantCondition: &anywherev1.Condition{ Type: anywherev1.ControlPlaneReadyCondition, Status: "True", }, }, + { + name: "with external etcd ready", + kcp: test.KubeadmControlPlane(func(kcp *controlplanev1.KubeadmControlPlane) { + kcp.Status.Replicas = 3 + kcp.Status.ReadyReplicas = 3 + kcp.Status.UpdatedReplicas = 3 + + kcp.Status.Conditions = []clusterv1.Condition{ + { + Type: clusterv1.ReadyCondition, + Status: "True", + }, + } + }), + controlPlaneCount: 3, + conditions: []anywherev1.Condition{ + { + Type: anywherev1.ControlPlaneInitializedCondition, + Status: "True", + }, + }, + externalEtcdCount: 1, + externalEtcdCluster: &etcdv1.EtcdadmCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster-etcd", + Namespace: constants.EksaSystemNamespace, + Generation: 2, + }, + Status: etcdv1.EtcdadmClusterStatus{ + Ready: true, + ObservedGeneration: 2, + }, + }, + wantCondition: &anywherev1.Condition{ + Type: anywherev1.ControlPlaneReadyCondition, + Status: "True", + }, + }, + { + name: "with external etcd not ready", + kcp: test.KubeadmControlPlane(func(kcp *controlplanev1.KubeadmControlPlane) { + kcp.Status.Replicas = 3 + kcp.Status.ReadyReplicas = 3 + kcp.Status.UpdatedReplicas = 3 + + kcp.Status.Conditions = []clusterv1.Condition{ + { + Type: clusterv1.ReadyCondition, + Status: "True", + }, + } + }), + controlPlaneCount: 3, + conditions: []anywherev1.Condition{ + { + Type: anywherev1.ControlPlaneInitializedCondition, + Status: "True", + }, + }, + externalEtcdCount: 1, + externalEtcdCluster: &etcdv1.EtcdadmCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster-etcd", + Namespace: constants.EksaSystemNamespace, + Generation: 2, + }, + Status: etcdv1.EtcdadmClusterStatus{ + ObservedGeneration: 2, + }, + }, + wantCondition: &anywherev1.Condition{ + Type: anywherev1.ControlPlaneReadyCondition, + Reason: anywherev1.RollingUpgradeInProgress, + Severity: clusterv1.ConditionSeverityInfo, + Message: "Etcd is not ready", + Status: "False", + }, + }, } for _, tt := range tests { @@ -367,6 +479,7 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { cluster.Name = "test-cluster" cluster.Namespace = constants.EksaSystemNamespace cluster.Spec.ControlPlaneConfiguration.Count = tt.controlPlaneCount + cluster.Status.Conditions = tt.conditions objs := []runtime.Object{} @@ -377,6 +490,31 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { tt.kcp.Namespace = cluster.Namespace objs = append(objs, tt.kcp) } + if tt.externalEtcdCount > 0 { + cluster.Spec.ExternalEtcdConfiguration = &anywherev1.ExternalEtcdConfiguration{ + Count: tt.externalEtcdCount, + MachineGroupRef: &anywherev1.Ref{ + Name: fmt.Sprintf("%s-etcd", cluster.Name), + }, + } + capiCluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: cluster.Name, + Namespace: constants.EksaSystemNamespace, + }, + Spec: clusterv1.ClusterSpec{ + ManagedExternalEtcdRef: &corev1.ObjectReference{ + Kind: "EtcdadmCluster", + Name: fmt.Sprintf("%s-etcd", cluster.Name), + }, + }, + } + tt.externalEtcdCluster.Name = fmt.Sprintf("%s-etcd", cluster.Name) + tt.externalEtcdCluster.Namespace = cluster.Namespace + + objs = append(objs, capiCluster) + objs = append(objs, tt.externalEtcdCluster) + } client = fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() @@ -385,7 +523,6 @@ func TestUpdateClusterStatusForControlPlane(t *testing.T) { condition := conditions.Get(cluster, tt.wantCondition.Type) g.Expect(condition).ToNot(BeNil()) - g.Expect(condition.Type).To(Equal(tt.wantCondition.Type)) g.Expect(condition.Severity).To(Equal(tt.wantCondition.Severity)) g.Expect(condition.Status).To(Equal(tt.wantCondition.Status)) diff --git a/pkg/providers/cloudstack/controlplane_test.go b/pkg/providers/cloudstack/controlplane_test.go index 78d2bdfa111f..13c9b629bb70 100644 --- a/pkg/providers/cloudstack/controlplane_test.go +++ b/pkg/providers/cloudstack/controlplane_test.go @@ -607,7 +607,7 @@ func cloudstackMachineTemplate(name string) *cloudstackv1.CloudStackMachineTempl Template: cloudstackv1.CloudStackMachineTemplateResource{ Spec: cloudstackv1.CloudStackMachineSpec{ Template: cloudstackv1.CloudStackResourceIdentifier{ - Name: "centos7-k8s-118", + Name: "kubernetes_1_21", }, Offering: cloudstackv1.CloudStackResourceIdentifier{ Name: "m4-large", diff --git a/pkg/providers/cloudstack/reconciler/reconciler_test.go b/pkg/providers/cloudstack/reconciler/reconciler_test.go index 9862ebd44c2f..fd2eeb2124f6 100644 --- a/pkg/providers/cloudstack/reconciler/reconciler_test.go +++ b/pkg/providers/cloudstack/reconciler/reconciler_test.go @@ -54,11 +54,12 @@ func TestReconcilerReconcileSuccess(t *testing.T) { remoteClient := env.Client() spec := tt.buildSpec() - tt.ipValidator.EXPECT().ValidateControlPlaneIP(tt.ctx, logger, spec).Return(controller.Result{}, nil) + tt.ipValidator.EXPECT().ValidateControlPlaneIP(tt.ctx, logger, tt.buildSpec()).Return(controller.Result{}, nil) tt.remoteClientRegistry.EXPECT().GetClient( tt.ctx, client.ObjectKey{Name: "workload-cluster", Namespace: constants.EksaSystemNamespace}, ).Return(remoteClient, nil).Times(1) - tt.cniReconciler.EXPECT().Reconcile(tt.ctx, logger, remoteClient, tt.buildSpec()) + + tt.cniReconciler.EXPECT().Reconcile(tt.ctx, logger, remoteClient, spec) ctrl := gomock.NewController(t) validator := cloudstack.NewMockProviderValidator(ctrl) tt.validatorRegistry.EXPECT().Get(tt.execConfig).Return(validator, nil).Times(1) @@ -587,6 +588,7 @@ func newReconcilerTest(t testing.TB) *reconcilerTest { machineConfigCP := machineConfig(func(m *anywherev1.CloudStackMachineConfig) { m.Name = "cp-machine-config" + m.Spec.Template.Name = "kubernetes-1-22" m.Spec.Users = append(m.Spec.Users, anywherev1.UserConfiguration{ Name: "user", @@ -595,6 +597,7 @@ func newReconcilerTest(t testing.TB) *reconcilerTest { }) machineConfigWN := machineConfig(func(m *anywherev1.CloudStackMachineConfig) { m.Name = "worker-machine-config" + m.Spec.Template.Name = "kubernetes-1-22" m.Spec.Users = append(m.Spec.Users, anywherev1.UserConfiguration{ Name: "user", diff --git a/pkg/providers/cloudstack/testdata/cluster_main.yaml b/pkg/providers/cloudstack/testdata/cluster_main.yaml index 9c908a09a31d..90f6b308d37f 100644 --- a/pkg/providers/cloudstack/testdata/cluster_main.yaml +++ b/pkg/providers/cloudstack/testdata/cluster_main.yaml @@ -65,7 +65,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" @@ -90,7 +90,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" @@ -118,7 +118,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" diff --git a/pkg/providers/cloudstack/testdata/cluster_main_with_cp_node_labels.yaml b/pkg/providers/cloudstack/testdata/cluster_main_with_cp_node_labels.yaml index aa9d214b73ab..9b10683fbc9c 100644 --- a/pkg/providers/cloudstack/testdata/cluster_main_with_cp_node_labels.yaml +++ b/pkg/providers/cloudstack/testdata/cluster_main_with_cp_node_labels.yaml @@ -64,7 +64,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" @@ -87,7 +87,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" @@ -115,7 +115,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" diff --git a/pkg/providers/cloudstack/testdata/cluster_main_with_node_labels.yaml b/pkg/providers/cloudstack/testdata/cluster_main_with_node_labels.yaml index 44e0acb298dc..e4b04a2b6edb 100644 --- a/pkg/providers/cloudstack/testdata/cluster_main_with_node_labels.yaml +++ b/pkg/providers/cloudstack/testdata/cluster_main_with_node_labels.yaml @@ -64,7 +64,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" @@ -89,7 +89,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" @@ -114,7 +114,7 @@ spec: sshAuthorizedKeys: # The key below was manually generated and not used in any production systems - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" template: - name: "centos7-k8s-118" + name: "kubernetes_1_21" diskOffering: name: "Small" mountPath: "/data-small" diff --git a/pkg/providers/cloudstack/testdata/expected_results_main_autoscaling_md.yaml b/pkg/providers/cloudstack/testdata/expected_results_main_autoscaling_md.yaml index 2dcf5cc5f701..a4c30a6cd046 100644 --- a/pkg/providers/cloudstack/testdata/expected_results_main_autoscaling_md.yaml +++ b/pkg/providers/cloudstack/testdata/expected_results_main_autoscaling_md.yaml @@ -124,7 +124,7 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- diff --git a/pkg/providers/cloudstack/testdata/expected_results_main_cp.yaml b/pkg/providers/cloudstack/testdata/expected_results_main_cp.yaml index d2d800eb17b1..b263a9ffe180 100644 --- a/pkg/providers/cloudstack/testdata/expected_results_main_cp.yaml +++ b/pkg/providers/cloudstack/testdata/expected_results_main_cp.yaml @@ -454,7 +454,7 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta3 @@ -485,6 +485,6 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- diff --git a/pkg/providers/cloudstack/testdata/expected_results_main_md.yaml b/pkg/providers/cloudstack/testdata/expected_results_main_md.yaml index ee8e536461a8..2dd502dc8dad 100644 --- a/pkg/providers/cloudstack/testdata/expected_results_main_md.yaml +++ b/pkg/providers/cloudstack/testdata/expected_results_main_md.yaml @@ -121,7 +121,7 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- diff --git a/pkg/providers/cloudstack/testdata/expected_results_main_no_machinetemplate_update_cp.yaml b/pkg/providers/cloudstack/testdata/expected_results_main_no_machinetemplate_update_cp.yaml index 8cf21491d2d3..ad20ae970a3e 100644 --- a/pkg/providers/cloudstack/testdata/expected_results_main_no_machinetemplate_update_cp.yaml +++ b/pkg/providers/cloudstack/testdata/expected_results_main_no_machinetemplate_update_cp.yaml @@ -454,7 +454,7 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta3 @@ -485,6 +485,6 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- diff --git a/pkg/providers/cloudstack/testdata/expected_results_main_no_machinetemplate_update_md.yaml b/pkg/providers/cloudstack/testdata/expected_results_main_no_machinetemplate_update_md.yaml index 28016d6d5d05..bc0ddda31c11 100644 --- a/pkg/providers/cloudstack/testdata/expected_results_main_no_machinetemplate_update_md.yaml +++ b/pkg/providers/cloudstack/testdata/expected_results_main_no_machinetemplate_update_md.yaml @@ -121,7 +121,7 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- diff --git a/pkg/providers/cloudstack/testdata/expected_results_main_node_labels_cp.yaml b/pkg/providers/cloudstack/testdata/expected_results_main_node_labels_cp.yaml index dffe68bb5770..eee190b5d66e 100644 --- a/pkg/providers/cloudstack/testdata/expected_results_main_node_labels_cp.yaml +++ b/pkg/providers/cloudstack/testdata/expected_results_main_node_labels_cp.yaml @@ -440,7 +440,7 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta3 @@ -470,6 +470,6 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- diff --git a/pkg/providers/cloudstack/testdata/expected_results_main_node_labels_md.yaml b/pkg/providers/cloudstack/testdata/expected_results_main_node_labels_md.yaml index e15084a54bdc..62855c097298 100644 --- a/pkg/providers/cloudstack/testdata/expected_results_main_node_labels_md.yaml +++ b/pkg/providers/cloudstack/testdata/expected_results_main_node_labels_md.yaml @@ -107,7 +107,7 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- diff --git a/pkg/providers/cloudstack/testdata/expected_results_resourceids_cp.yaml b/pkg/providers/cloudstack/testdata/expected_results_resourceids_cp.yaml index b5548a21b311..fd2905dd0169 100644 --- a/pkg/providers/cloudstack/testdata/expected_results_resourceids_cp.yaml +++ b/pkg/providers/cloudstack/testdata/expected_results_resourceids_cp.yaml @@ -454,7 +454,7 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta3 @@ -485,6 +485,6 @@ spec: name: m4-large sshKey: "" template: - name: centos7-k8s-118 + name: kubernetes_1_21 --- diff --git a/pkg/providers/cloudstack/validator.go b/pkg/providers/cloudstack/validator.go index 04f5c26cedf0..ee65d17a2103 100644 --- a/pkg/providers/cloudstack/validator.go +++ b/pkg/providers/cloudstack/validator.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strings" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -135,6 +136,9 @@ func (v *Validator) ValidateClusterMachineConfigs(ctx context.Context, clusterSp if err := v.validateMachineConfig(ctx, clusterSpec.CloudStackDatacenter, machineConfig); err != nil { return fmt.Errorf("machine config %s validation failed: %v", machineConfig.Name, err) } + if err := v.validateTemplateMatchesKubernetesVersion(ctx, machineConfig, clusterSpec); err != nil { + return fmt.Errorf("machine config %s validation failed: %v", machineConfig.Name, err) + } } logger.MarkPass("Validated cluster Machine Configs") @@ -190,6 +194,22 @@ func (v *Validator) validateMachineConfig(ctx context.Context, datacenterConfig return nil } +func (v *Validator) validateTemplateMatchesKubernetesVersion(ctx context.Context, machineConfig *anywherev1.CloudStackMachineConfig, spec *cluster.Spec) error { + // Replace 1.23, 1-23, 1_23 to 123 in the template name string. + templateReplacer := strings.NewReplacer("-", "", ".", "", "_", "") + templateName := templateReplacer.Replace(machineConfig.Spec.Template.Name) + // Replace 1-23 to 123 in the kubernetesversion string. + replacer := strings.NewReplacer(".", "") + kubernetesVersion := replacer.Replace(string(spec.Cluster.Spec.KubernetesVersion)) + // This will return an error if the template name does not contain specified kubernetes version. + // For ex if the kubernetes version is 1.23, + // the template name should include 1.23 or 1-23, 1_23 or 123 i.e. kubernetes-1-23-eks in the string. + if !strings.Contains(templateName, kubernetesVersion) { + return fmt.Errorf("invalid template: cluster kubernetes version is %s but template for machineconfig %s is %s. If the kubernetes version is 1.23, the template name should include 1.23, 1_23, 1-23 or 123", string(spec.Cluster.Spec.KubernetesVersion), machineConfig.Name, machineConfig.Spec.Template.Name) + } + return nil +} + // ValidateSecretsUnchanged checks the secret to see if it has not been changed. func (v *Validator) ValidateSecretsUnchanged(ctx context.Context, cluster *types.Cluster, execConfig *decoder.CloudStackExecConfig, client ProviderKubectlClient) error { for _, profile := range execConfig.Profiles { diff --git a/pkg/providers/cloudstack/validator_test.go b/pkg/providers/cloudstack/validator_test.go index f122199fceda..9e8a3989426e 100644 --- a/pkg/providers/cloudstack/validator_test.go +++ b/pkg/providers/cloudstack/validator_test.go @@ -38,7 +38,7 @@ func (n *DummyNetClient) DialTimeout(network, address string, timeout time.Durat } var testTemplate = v1alpha1.CloudStackResourceIdentifier{ - Name: "centos7-k8s-118", + Name: "kubernetes_1_21", } var testOffering = v1alpha1.CloudStackResourceIdentifier{ @@ -276,6 +276,7 @@ func TestValidateMachineConfigsHappyCase(t *testing.T) { func TestValidateCloudStackMachineConfig(t *testing.T) { ctx := context.Background() cmk := mocks.NewMockProviderCmkClient(gomock.NewController(t)) + config, err := cluster.ParseConfigFromFile(path.Join(testDataDir, testClusterConfigMainFilename)) if err != nil { t.Fatalf("unable to get machine configs from file: %v", err) @@ -305,6 +306,29 @@ func TestValidateCloudStackMachineConfig(t *testing.T) { } } +func TestValidateTemplateMatchesKubernetesVersionError(t *testing.T) { + ctx := context.Background() + cmk := mocks.NewMockProviderCmkClient(gomock.NewController(t)) + clusterSpec := test.NewFullClusterSpec(t, path.Join(testDataDir, testClusterConfigMainFilename)) + config, err := cluster.ParseConfigFromFile(path.Join(testDataDir, testClusterConfigMainFilename)) + if err != nil { + t.Fatalf("unable to get machine configs from file: %v", err) + } + machineConfigs := config.CloudStackMachineConfigs + if err != nil { + t.Fatalf("unable to get machine configs from file %s", testClusterConfigMainFilename) + } + clusterSpec.Cluster.Spec.KubernetesVersion = "1.22" + validator := NewValidator(cmk, &DummyNetClient{}, true) + + for _, machineConfig := range machineConfigs { + err := validator.validateTemplateMatchesKubernetesVersion(ctx, machineConfig, clusterSpec) + if err == nil { + t.Fatalf("failed to validate CloudStackMachineConfig: %v", err) + } + } +} + func TestValidateMachineConfigsWithAffinity(t *testing.T) { ctx := context.Background() cmk := mocks.NewMockProviderCmkClient(gomock.NewController(t))