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))