From 64dc32af9ec1c485a8c6fab5d0caacea8452df40 Mon Sep 17 00:00:00 2001 From: Ekaterina Kazakova Date: Wed, 13 Nov 2024 22:40:45 +0400 Subject: [PATCH] [e2e] Find and validate templates for testing --- test/e2e/e2e_suite_test.go | 8 +- test/e2e/managedcluster/constants.go | 9 +- test/e2e/managedcluster/managedcluster.go | 33 +++-- test/e2e/managedcluster/providervalidator.go | 6 +- .../resources/aws-hosted-cp.yaml.tpl | 2 +- .../resources/aws-standalone-cp.yaml.tpl | 2 +- .../resources/azure-hosted-cp.yaml.tpl | 2 +- .../resources/azure-standalone-cp.yaml.tpl | 2 +- .../resources/vsphere-hosted-cp.yaml.tpl | 2 +- .../resources/vsphere-standalone-cp.yaml.tpl | 2 +- test/e2e/provider_aws_test.go | 23 +++- test/e2e/provider_azure_test.go | 22 ++- test/e2e/provider_vsphere_test.go | 20 ++- test/objects/templatechain/templatechain.go | 2 +- test/templates/templates.go | 84 +++++++++++- test/templates/templates_test.go | 125 ++++++++++++++++++ 16 files changed, 303 insertions(+), 41 deletions(-) create mode 100644 test/templates/templates_test.go diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index cc1311104..967ebd4f1 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -34,6 +34,7 @@ import ( hmc "github.com/Mirantis/hmc/api/v1alpha1" internalutils "github.com/Mirantis/hmc/internal/utils" + "github.com/Mirantis/hmc/test/e2e/config" "github.com/Mirantis/hmc/test/e2e/kubeclient" "github.com/Mirantis/hmc/test/e2e/managedcluster" "github.com/Mirantis/hmc/test/templates" @@ -50,13 +51,16 @@ func TestE2E(t *testing.T) { var clusterTemplates map[string][]hmc.AvailableUpgrade var _ = BeforeSuite(func() { + err := config.Parse() + Expect(err).NotTo(HaveOccurred()) + GinkgoT().Setenv(managedcluster.EnvVarNamespace, internalutils.DefaultSystemNamespace) ctx := context.Background() By("building and deploying the controller-manager") cmd := exec.Command("make", "kind-deploy") - _, err := utils.Run(cmd) + _, err = utils.Run(cmd) Expect(err).NotTo(HaveOccurred()) cmd = exec.Command("make", "test-apply") _, err = utils.Run(cmd) @@ -153,7 +157,7 @@ func validateController(kc *kubeclient.KubeClient, labelSelector, name string) e // templateBy wraps a Ginkgo By with a block describing the template being // tested. -func templateBy(t managedcluster.Template, description string) { +func templateBy(t managedcluster.TemplateType, description string) { GinkgoHelper() By(fmt.Sprintf("[%s] %s", t, description)) } diff --git a/test/e2e/managedcluster/constants.go b/test/e2e/managedcluster/constants.go index 4f18a7832..d6809f071 100644 --- a/test/e2e/managedcluster/constants.go +++ b/test/e2e/managedcluster/constants.go @@ -16,10 +16,11 @@ package managedcluster const ( // Common - EnvVarManagedClusterName = "MANAGED_CLUSTER_NAME" - EnvVarControlPlaneNumber = "CONTROL_PLANE_NUMBER" - EnvVarWorkerNumber = "WORKER_NUMBER" - EnvVarNamespace = "NAMESPACE" + EnvVarManagedClusterName = "MANAGED_CLUSTER_NAME" + EnvVarManagedClusterTemplate = "MANAGED_CLUSTER_TEMPLATE" + EnvVarControlPlaneNumber = "CONTROL_PLANE_NUMBER" + EnvVarWorkerNumber = "WORKER_NUMBER" + EnvVarNamespace = "NAMESPACE" // EnvVarNoCleanup disables After* cleanup in provider specs to allow for // debugging of test failures. EnvVarNoCleanup = "NO_CLEANUP" diff --git a/test/e2e/managedcluster/managedcluster.go b/test/e2e/managedcluster/managedcluster.go index 8600140da..4a7092e0f 100644 --- a/test/e2e/managedcluster/managedcluster.go +++ b/test/e2e/managedcluster/managedcluster.go @@ -43,15 +43,15 @@ const ( Namespace = "default" ) -type Template string +type TemplateType string const ( - TemplateAWSStandaloneCP Template = "aws-standalone-cp" - TemplateAWSHostedCP Template = "aws-hosted-cp" - TemplateAzureHostedCP Template = "azure-hosted-cp" - TemplateAzureStandaloneCP Template = "azure-standalone-cp" - TemplateVSphereStandaloneCP Template = "vsphere-standalone-cp" - TemplateVSphereHostedCP Template = "vsphere-hosted-cp" + TemplateAWSStandaloneCP TemplateType = "aws-standalone-cp" + TemplateAWSHostedCP TemplateType = "aws-hosted-cp" + TemplateAzureHostedCP TemplateType = "azure-hosted-cp" + TemplateAzureStandaloneCP TemplateType = "azure-standalone-cp" + TemplateVSphereStandaloneCP TemplateType = "vsphere-standalone-cp" + TemplateVSphereHostedCP TemplateType = "vsphere-hosted-cp" ) //go:embed resources/aws-standalone-cp.yaml.tpl @@ -86,7 +86,7 @@ func GetProviderLabel(provider ProviderType) string { return fmt.Sprintf("%s=%s", providerLabel, provider) } -func setClusterName(templateName Template) { +func setClusterName(templateType TemplateType) { var generatedName string mcName := os.Getenv(EnvVarManagedClusterName) @@ -94,27 +94,32 @@ func setClusterName(templateName Template) { mcName = "e2e-test-" + uuid.New().String()[:8] } - providerName := strings.Split(string(templateName), "-")[0] + providerName := strings.Split(string(templateType), "-")[0] // Append the provider name to the cluster name to ensure uniqueness between // different deployed ManagedClusters. generatedName = fmt.Sprintf("%s-%s", mcName, providerName) - if strings.Contains(string(templateName), "hosted") { + if strings.Contains(string(templateType), "hosted") { generatedName = fmt.Sprintf("%s-%s", mcName, "hosted") } GinkgoT().Setenv(EnvVarManagedClusterName, generatedName) } +func setTemplate(templateName string) { + GinkgoT().Setenv(EnvVarManagedClusterTemplate, templateName) +} + // GetUnstructured returns an unstructured ManagedCluster object based on the // provider and template. -func GetUnstructured(templateName Template) *unstructured.Unstructured { +func GetUnstructured(templateType TemplateType, templateName string) *unstructured.Unstructured { GinkgoHelper() - setClusterName(templateName) + setClusterName(templateType) + setTemplate(templateName) var managedClusterTemplateBytes []byte - switch templateName { + switch templateType { case TemplateAWSStandaloneCP: managedClusterTemplateBytes = awsStandaloneCPManagedClusterTemplateBytes case TemplateAWSHostedCP: @@ -137,7 +142,7 @@ func GetUnstructured(templateName Template) *unstructured.Unstructured { case TemplateAzureStandaloneCP: managedClusterTemplateBytes = azureStandaloneCPManagedClusterTemplateBytes default: - Fail(fmt.Sprintf("Unsupported template: %s", templateName)) + Fail(fmt.Sprintf("Unsupported template type: %s", templateType)) } managedClusterConfigBytes, err := envsubst.Bytes(managedClusterTemplateBytes) diff --git a/test/e2e/managedcluster/providervalidator.go b/test/e2e/managedcluster/providervalidator.go index 3e658087d..d7a82cf75 100644 --- a/test/e2e/managedcluster/providervalidator.go +++ b/test/e2e/managedcluster/providervalidator.go @@ -27,8 +27,8 @@ import ( // validate a provider's resources. Some providers do not support all of the // resources that can potentially be validated. type ProviderValidator struct { - // Template is the name of the template being validated. - template Template + // Template is the type of the template being validated. + template TemplateType // Namespace is the namespace of the cluster to validate. namespace string // ClusterName is the name of the cluster to validate. @@ -48,7 +48,7 @@ const ( ValidationActionDelete ValidationAction = "delete" ) -func NewProviderValidator(template Template, namespace, clusterName string, action ValidationAction) *ProviderValidator { +func NewProviderValidator(template TemplateType, namespace, clusterName string, action ValidationAction) *ProviderValidator { var ( resourcesToValidate map[string]resourceValidationFunc resourceOrder []string diff --git a/test/e2e/managedcluster/resources/aws-hosted-cp.yaml.tpl b/test/e2e/managedcluster/resources/aws-hosted-cp.yaml.tpl index b8758c9ab..b8108cce9 100644 --- a/test/e2e/managedcluster/resources/aws-hosted-cp.yaml.tpl +++ b/test/e2e/managedcluster/resources/aws-hosted-cp.yaml.tpl @@ -3,7 +3,7 @@ kind: ManagedCluster metadata: name: ${MANAGED_CLUSTER_NAME} spec: - template: aws-hosted-cp-0-0-2 + template: ${MANAGED_CLUSTER_TEMPLATE} credential: ${AWS_CLUSTER_IDENTITY}-cred config: clusterIdentity: diff --git a/test/e2e/managedcluster/resources/aws-standalone-cp.yaml.tpl b/test/e2e/managedcluster/resources/aws-standalone-cp.yaml.tpl index 8d2ceab31..ed09f8080 100644 --- a/test/e2e/managedcluster/resources/aws-standalone-cp.yaml.tpl +++ b/test/e2e/managedcluster/resources/aws-standalone-cp.yaml.tpl @@ -3,7 +3,7 @@ kind: ManagedCluster metadata: name: ${MANAGED_CLUSTER_NAME} spec: - template: aws-standalone-cp-0-0-2 + template: ${MANAGED_CLUSTER_TEMPLATE} credential: ${AWS_CLUSTER_IDENTITY}-cred config: clusterIdentity: diff --git a/test/e2e/managedcluster/resources/azure-hosted-cp.yaml.tpl b/test/e2e/managedcluster/resources/azure-hosted-cp.yaml.tpl index 7cbe61b71..5474ea82b 100644 --- a/test/e2e/managedcluster/resources/azure-hosted-cp.yaml.tpl +++ b/test/e2e/managedcluster/resources/azure-hosted-cp.yaml.tpl @@ -4,7 +4,7 @@ metadata: name: ${MANAGED_CLUSTER_NAME} namespace: ${NAMESPACE} spec: - template: azure-hosted-cp-0-0-2 + template: ${MANAGED_CLUSTER_TEMPLATE} credential: ${AZURE_CLUSTER_IDENTITY}-cred config: location: "${AZURE_REGION}" diff --git a/test/e2e/managedcluster/resources/azure-standalone-cp.yaml.tpl b/test/e2e/managedcluster/resources/azure-standalone-cp.yaml.tpl index 7f1083a83..a68891ce0 100644 --- a/test/e2e/managedcluster/resources/azure-standalone-cp.yaml.tpl +++ b/test/e2e/managedcluster/resources/azure-standalone-cp.yaml.tpl @@ -4,7 +4,7 @@ metadata: name: ${MANAGED_CLUSTER_NAME} namespace: ${NAMESPACE} spec: - template: azure-standalone-cp-0-0-2 + template: ${MANAGED_CLUSTER_TEMPLATE} credential: ${AZURE_CLUSTER_IDENTITY}-cred config: controlPlaneNumber: 1 diff --git a/test/e2e/managedcluster/resources/vsphere-hosted-cp.yaml.tpl b/test/e2e/managedcluster/resources/vsphere-hosted-cp.yaml.tpl index 03a201cce..42b5efc7c 100644 --- a/test/e2e/managedcluster/resources/vsphere-hosted-cp.yaml.tpl +++ b/test/e2e/managedcluster/resources/vsphere-hosted-cp.yaml.tpl @@ -3,7 +3,7 @@ kind: ManagedCluster metadata: name: ${MANAGED_CLUSTER_NAME} spec: - template: vsphere-hosted-cp-0-0-2 + template: ${MANAGED_CLUSTER_TEMPLATE} credential: ${VSPHERE_CLUSTER_IDENTITY}-cred config: controlPlaneNumber: ${CONTROL_PLANE_NUMBER:=1} diff --git a/test/e2e/managedcluster/resources/vsphere-standalone-cp.yaml.tpl b/test/e2e/managedcluster/resources/vsphere-standalone-cp.yaml.tpl index 47c7dc538..95a77c9e1 100644 --- a/test/e2e/managedcluster/resources/vsphere-standalone-cp.yaml.tpl +++ b/test/e2e/managedcluster/resources/vsphere-standalone-cp.yaml.tpl @@ -3,7 +3,7 @@ kind: ManagedCluster metadata: name: ${MANAGED_CLUSTER_NAME} spec: - template: vsphere-standalone-cp-0-0-2 + template: ${MANAGED_CLUSTER_TEMPLATE} credential: ${VSPHERE_CLUSTER_IDENTITY}-cred config: controlPlaneNumber: ${CONTROL_PLANE_NUMBER:=1} diff --git a/test/e2e/provider_aws_test.go b/test/e2e/provider_aws_test.go index 883a8ee08..5b2ba9568 100644 --- a/test/e2e/provider_aws_test.go +++ b/test/e2e/provider_aws_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/gomega" internalutils "github.com/Mirantis/hmc/internal/utils" + "github.com/Mirantis/hmc/test/e2e/config" "github.com/Mirantis/hmc/test/e2e/kubeclient" "github.com/Mirantis/hmc/test/e2e/managedcluster" "github.com/Mirantis/hmc/test/e2e/managedcluster/aws" @@ -43,9 +44,22 @@ var _ = Describe("AWS Templates", Label("provider:cloud", "provider:aws"), Order hostedDeleteFunc func() error kubecfgDeleteFunc func() error clusterName string + + testingConfig config.ProviderTestingConfig ) BeforeAll(func() { + By("get testing configuration") + testingConfig = config.Config[config.TestingProviderAWS] + + By("find and validate templates") + err := templates.Set(&testingConfig.Standalone, clusterTemplates, managedcluster.TemplateAWSStandaloneCP) + Expect(err).NotTo(HaveOccurred()) + err = templates.Set(&testingConfig.Hosted, clusterTemplates, managedcluster.TemplateAWSHostedCP) + Expect(err).NotTo(HaveOccurred()) + + _, _ = fmt.Fprintf(GinkgoWriter, "Final AWS testing configuration:\n%s\n", testingConfig.String()) + By("providing cluster identity") kc = kubeclient.NewFromLocal(internalutils.DefaultSystemNamespace) ci := clusteridentity.New(kc, managedcluster.ProviderAWS, managedcluster.Namespace) @@ -81,8 +95,9 @@ var _ = Describe("AWS Templates", Label("provider:cloud", "provider:aws"), Order // hosting the hosted cluster. GinkgoT().Setenv(managedcluster.EnvVarAWSInstanceType, "t3.xlarge") - templateBy(managedcluster.TemplateAWSStandaloneCP, "creating a ManagedCluster") - sd := managedcluster.GetUnstructured(managedcluster.TemplateAWSStandaloneCP) + templateBy(managedcluster.TemplateAWSStandaloneCP, fmt.Sprintf("creating a ManagedCluster with %s template", testingConfig.Standalone.Template)) + sd := managedcluster.GetUnstructured(managedcluster.TemplateAWSStandaloneCP, testingConfig.Standalone.Template) + clusterName = sd.GetName() standaloneDeleteFunc = kc.CreateManagedCluster(context.Background(), sd, managedcluster.Namespace) @@ -138,8 +153,8 @@ var _ = Describe("AWS Templates", Label("provider:cloud", "provider:aws"), Order // cluster. aws.PopulateHostedTemplateVars(context.Background(), kc, clusterName) - templateBy(managedcluster.TemplateAWSHostedCP, "creating a ManagedCluster") - hd := managedcluster.GetUnstructured(managedcluster.TemplateAWSHostedCP) + templateBy(managedcluster.TemplateAWSHostedCP, fmt.Sprintf("creating a ManagedCluster with %s template", testingConfig.Hosted.Template)) + hd := managedcluster.GetUnstructured(managedcluster.TemplateAWSHostedCP, testingConfig.Hosted.Template) hdName := hd.GetName() // Deploy the hosted cluster on top of the standalone cluster. diff --git a/test/e2e/provider_azure_test.go b/test/e2e/provider_azure_test.go index 7ca1bb13d..b2d81a755 100644 --- a/test/e2e/provider_azure_test.go +++ b/test/e2e/provider_azure_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/gomega" internalutils "github.com/Mirantis/hmc/internal/utils" + "github.com/Mirantis/hmc/test/e2e/config" "github.com/Mirantis/hmc/test/e2e/kubeclient" "github.com/Mirantis/hmc/test/e2e/managedcluster" "github.com/Mirantis/hmc/test/e2e/managedcluster/azure" @@ -44,9 +45,22 @@ var _ = Context("Azure Templates", Label("provider:cloud", "provider:azure"), Or kubecfgDeleteFunc func() error hostedKubecfgDeleteFunc func() error sdName string + + testingConfig config.ProviderTestingConfig ) BeforeAll(func() { + By("get testing configuration") + testingConfig = config.Config[config.TestingProviderAzure] + + By("find and validate templates") + err := templates.Set(&testingConfig.Standalone, clusterTemplates, managedcluster.TemplateAzureStandaloneCP) + Expect(err).NotTo(HaveOccurred()) + err = templates.Set(&testingConfig.Hosted, clusterTemplates, managedcluster.TemplateAzureHostedCP) + Expect(err).NotTo(HaveOccurred()) + + _, _ = fmt.Fprintf(GinkgoWriter, "Final Azure testing configuration:\n%s\n", testingConfig.String()) + By("ensuring Azure credentials are set") kc = kubeclient.NewFromLocal(internalutils.DefaultSystemNamespace) ci := clusteridentity.New(kc, managedcluster.ProviderAzure, managedcluster.Namespace) @@ -81,8 +95,8 @@ var _ = Context("Azure Templates", Label("provider:cloud", "provider:azure"), Or }) It("should work with an Azure provider", func() { - templateBy(managedcluster.TemplateAzureStandaloneCP, "creating a ManagedCluster") - sd := managedcluster.GetUnstructured(managedcluster.TemplateAzureStandaloneCP) + templateBy(managedcluster.TemplateAzureStandaloneCP, fmt.Sprintf("creating a ManagedCluster with %s template", testingConfig.Standalone.Template)) + sd := managedcluster.GetUnstructured(managedcluster.TemplateAzureStandaloneCP, testingConfig.Standalone.Template) sdName = sd.GetName() standaloneDeleteFunc := kc.CreateManagedCluster(context.Background(), sd, managedcluster.Namespace) @@ -103,7 +117,7 @@ var _ = Context("Azure Templates", Label("provider:cloud", "provider:azure"), Or // setup environment variables for deploying the hosted template (subnet name, etc) azure.SetAzureEnvironmentVariables(sdName, kc) - hd := managedcluster.GetUnstructured(managedcluster.TemplateAzureHostedCP) + hd := managedcluster.GetUnstructured(managedcluster.TemplateAzureHostedCP, testingConfig.Hosted.Template) hdName := hd.GetName() var kubeCfgPath string @@ -136,7 +150,7 @@ var _ = Context("Azure Templates", Label("provider:cloud", "provider:azure"), Or By("Create default storage class for azure-disk CSI driver") azure.CreateDefaultStorageClass(standaloneClient) - templateBy(managedcluster.TemplateAzureHostedCP, "creating a ManagedCluster") + templateBy(managedcluster.TemplateAzureHostedCP, fmt.Sprintf("creating a ManagedCluster with %s template", testingConfig.Hosted.Template)) hostedDeleteFunc = standaloneClient.CreateManagedCluster(context.Background(), hd, managedcluster.Namespace) templateBy(managedcluster.TemplateAzureHostedCP, "Patching AzureCluster to ready") diff --git a/test/e2e/provider_vsphere_test.go b/test/e2e/provider_vsphere_test.go index 7cec432a4..9cf9bc0ca 100644 --- a/test/e2e/provider_vsphere_test.go +++ b/test/e2e/provider_vsphere_test.go @@ -16,6 +16,7 @@ package e2e import ( "context" + "fmt" "os" "time" @@ -23,10 +24,12 @@ import ( . "github.com/onsi/gomega" internalutils "github.com/Mirantis/hmc/internal/utils" + "github.com/Mirantis/hmc/test/e2e/config" "github.com/Mirantis/hmc/test/e2e/kubeclient" "github.com/Mirantis/hmc/test/e2e/managedcluster" "github.com/Mirantis/hmc/test/e2e/managedcluster/clusteridentity" "github.com/Mirantis/hmc/test/e2e/managedcluster/vsphere" + "github.com/Mirantis/hmc/test/templates" ) var _ = Context("vSphere Templates", Label("provider:onprem", "provider:vsphere"), Ordered, func() { @@ -35,9 +38,22 @@ var _ = Context("vSphere Templates", Label("provider:onprem", "provider:vsphere" deleteFunc func() error clusterName string err error + + testingConfig config.ProviderTestingConfig ) BeforeAll(func() { + By("get testing configuration") + testingConfig = config.Config[config.TestingProviderVsphere] + + By("find and validate templates") + err := templates.Set(&testingConfig.Standalone, clusterTemplates, managedcluster.TemplateVSphereStandaloneCP) + Expect(err).NotTo(HaveOccurred()) + err = templates.Set(&testingConfig.Hosted, clusterTemplates, managedcluster.TemplateVSphereHostedCP) + Expect(err).NotTo(HaveOccurred()) + + _, _ = fmt.Fprintf(GinkgoWriter, "Final Vsphere testing configuration:\n%s\n", testingConfig.String()) + By("ensuring that env vars are set correctly") vsphere.CheckEnv() By("creating kube client") @@ -80,8 +96,8 @@ var _ = Context("vSphere Templates", Label("provider:onprem", "provider:vsphere" }) It("should deploy standalone managed cluster", func() { - By("creating a managed cluster") - d := managedcluster.GetUnstructured(managedcluster.TemplateVSphereStandaloneCP) + By(fmt.Sprintf("creating a managed cluster with %s template", testingConfig.Standalone.Template)) + d := managedcluster.GetUnstructured(managedcluster.TemplateVSphereStandaloneCP, testingConfig.Standalone.Template) clusterName = d.GetName() deleteFunc = kc.CreateManagedCluster(context.Background(), d, managedcluster.Namespace) diff --git a/test/objects/templatechain/templatechain.go b/test/objects/templatechain/templatechain.go index ac3296008..187820732 100644 --- a/test/objects/templatechain/templatechain.go +++ b/test/objects/templatechain/templatechain.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package templatemanagement +package templatechain import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/templates/templates.go b/test/templates/templates.go index 586120874..ba61007c0 100644 --- a/test/templates/templates.go +++ b/test/templates/templates.go @@ -17,6 +17,9 @@ package templates import ( "context" "fmt" + "slices" + "sort" + "strings" "time" . "github.com/onsi/ginkgo/v2" @@ -28,6 +31,7 @@ import ( hmc "github.com/Mirantis/hmc/api/v1alpha1" internalutils "github.com/Mirantis/hmc/internal/utils" + "github.com/Mirantis/hmc/test/e2e/config" "github.com/Mirantis/hmc/test/e2e/managedcluster" ) @@ -114,8 +118,86 @@ func checkClusterTemplates(ctx context.Context, client crclient.Client, namespac gvk := hmc.GroupVersion.WithKind(hmc.ClusterTemplateKind) template.SetGroupVersionKind(gvk) if err := client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: templateName}, template); err != nil { - return fmt.Errorf("failed to get ClusterTemplate %s/%s: %w", namespace, template.Name, err) + return fmt.Errorf("failed to get ClusterTemplate %s/%s: %w", namespace, templateName, err) } } return nil } + +func Set(testingConfig *config.ClusterTestingConfig, clusterTemplates map[string][]hmc.AvailableUpgrade, templateType managedcluster.TemplateType) error { + templates := filterByType(clusterTemplates, templateType) + if len(templates) == 0 { + return fmt.Errorf("no Template with the %s type is supported", templateType) + } + + // Find and validate templates for cluster deployment testing + if !testingConfig.Upgrade { + if testingConfig.Template == "" { + testingConfig.Template = templates[0] + } else if !slices.Contains(templates, testingConfig.Template) { + return fmt.Errorf("invalid templates configuration. Template %s is not in the list of supported templates", testingConfig.Template) + } + return nil + } + + // Find and validate templates for cluster upgrade testing + if testingConfig.Template != "" { + // Template should have available upgrades + availableUpgrades := clusterTemplates[testingConfig.Template] + if len(availableUpgrades) == 0 { + return fmt.Errorf("invalid templates configuration. No upgrades are available from the Template %s", testingConfig.Template) + } + // Template should be in the list of supported + if !slices.Contains(templates, testingConfig.Template) { + return fmt.Errorf("invalid templates configuration. Template %s is not in the list of supported templates", testingConfig.Template) + } + if testingConfig.UpgradeTemplate != "" { + // UpgradeTemplate should be available + if !slices.Contains(availableUpgrades, hmc.AvailableUpgrade{Name: testingConfig.UpgradeTemplate}) { + return fmt.Errorf("invalid templates configuration. Template %s is not available for the upgrade from %s", testingConfig.UpgradeTemplate, testingConfig.Template) + } + } else { + // Find latest available template for the upgrade + sort.Slice(availableUpgrades, func(i, j int) bool { + return availableUpgrades[i].Name < availableUpgrades[j].Name + }) + testingConfig.UpgradeTemplate = availableUpgrades[len(availableUpgrades)-1].Name + } + return nil + } + + // find template with available upgrades + template := "" + upgradeTemplate := "" + for _, templateName := range templates { + template = templateName + for _, au := range clusterTemplates[template] { + if upgradeTemplate < au.Name { + upgradeTemplate = au.Name + } + } + if template != "" && upgradeTemplate != "" { + break + } + } + if template == "" || upgradeTemplate == "" { + return fmt.Errorf("invalid templates configuration. No %s templates are available for the upgrade", templateType) + } + testingConfig.Template = template + testingConfig.UpgradeTemplate = upgradeTemplate + + return nil +} + +func filterByType(clusterTemplates map[string][]hmc.AvailableUpgrade, templateType managedcluster.TemplateType) []string { + var templates []string + for template := range clusterTemplates { + if strings.HasPrefix(template, string(templateType)) { + templates = append(templates, template) + } + } + sort.Slice(templates, func(i, j int) bool { + return templates[i] > templates[j] + }) + return templates +} diff --git a/test/templates/templates_test.go b/test/templates/templates_test.go new file mode 100644 index 000000000..a648b478e --- /dev/null +++ b/test/templates/templates_test.go @@ -0,0 +1,125 @@ +// Copyright 2024 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package templates + +import ( + "fmt" + "testing" + + . "github.com/onsi/gomega" + + hmc "github.com/Mirantis/hmc/api/v1alpha1" + "github.com/Mirantis/hmc/test/e2e/config" + "github.com/Mirantis/hmc/test/e2e/managedcluster" +) + +func Test_Set(t *testing.T) { + templates := map[string][]hmc.AvailableUpgrade{ + "aws-standalone-cp-0-0-1": { + {Name: "aws-standalone-cp-0-0-3"}, + {Name: "aws-standalone-cp-0-0-2"}, + }, + "aws-standalone-cp-0-0-3": {}, + "aws-standalone-cp-0-0-2": {}, + "aws-hosted-cp-0-0-1": { + {Name: "aws-hosted-cp-0-0-4"}, + {Name: "aws-hosted-cp-0-0-2"}, + }, + "aws-hosted-cp-0-0-4": {}, + "aws-hosted-cp-0-0-2": {}, + "azure-standalone-cp-0-0-1": { + {Name: "azure-standalone-cp-0-0-2"}, + }, + "azure-hosted-cp-0-0-1": { + {Name: "azure-hosted-cp-0-0-2"}, + }, + "vsphere-standalone-cp-0-0-1": { + {Name: "vsphere-standalone-cp-0-0-2"}, + }, + "vsphere-hosted-cp-0-0-1": {}, + } + for _, tt := range []struct { + title string + config config.ClusterTestingConfig + clusterTemplates map[string][]hmc.AvailableUpgrade + templateType managedcluster.TemplateType + expectedConfig config.ClusterTestingConfig + expectedErr error + }{ + { + title: "no templates of the provided type supported", + config: config.ClusterTestingConfig{Template: "aws-unsupported-cp-0-0-1"}, + templateType: managedcluster.TemplateType("aws-unsupported-cp"), + expectedConfig: config.ClusterTestingConfig{Template: "aws-unsupported-cp-0-0-1"}, + expectedErr: fmt.Errorf("no Template with the aws-unsupported-cp type is supported"), + }, + { + title: "provided template is not supported", + config: config.ClusterTestingConfig{Template: "aws-hosted-cp-0-0-6"}, + templateType: managedcluster.TemplateAWSHostedCP, + expectedConfig: config.ClusterTestingConfig{Template: "aws-hosted-cp-0-0-6"}, + expectedErr: fmt.Errorf("invalid templates configuration. Template aws-hosted-cp-0-0-6 is not in the list of supported templates"), + }, + { + title: "template is provided and valid", + config: config.ClusterTestingConfig{Template: "aws-hosted-cp-0-0-1"}, + templateType: managedcluster.TemplateAWSHostedCP, + expectedConfig: config.ClusterTestingConfig{Template: "aws-hosted-cp-0-0-1"}, + }, + { + title: "should find latest template for aws-hosted-cp", + config: config.ClusterTestingConfig{}, + templateType: managedcluster.TemplateAWSHostedCP, + expectedConfig: config.ClusterTestingConfig{Template: "aws-hosted-cp-0-0-4"}, + }, + { + title: "upgrade: the template is provided but no upgrades are available", + config: config.ClusterTestingConfig{Upgrade: true, Template: "vsphere-hosted-cp-0-0-1"}, + templateType: managedcluster.TemplateVSphereHostedCP, + expectedConfig: config.ClusterTestingConfig{Upgrade: true, Template: "vsphere-hosted-cp-0-0-1"}, + expectedErr: fmt.Errorf("invalid templates configuration. No upgrades are available from the Template vsphere-hosted-cp-0-0-1"), + }, + { + title: "upgrade: template and upgradeTemplate are provided but is not available for the upgrade", + config: config.ClusterTestingConfig{Upgrade: true, Template: "vsphere-standalone-cp-0-0-1", UpgradeTemplate: "vsphere-standalone-cp-0-0-5"}, + templateType: managedcluster.TemplateVSphereStandaloneCP, + expectedConfig: config.ClusterTestingConfig{Upgrade: true, Template: "vsphere-standalone-cp-0-0-1", UpgradeTemplate: "vsphere-standalone-cp-0-0-5"}, + expectedErr: fmt.Errorf("invalid templates configuration. Template vsphere-standalone-cp-0-0-5 is not available for the upgrade from vsphere-standalone-cp-0-0-1"), + }, + { + title: "upgrade: templates are provided and valid", + config: config.ClusterTestingConfig{Upgrade: true, Template: "aws-hosted-cp-0-0-1", UpgradeTemplate: "aws-hosted-cp-0-0-2"}, + templateType: managedcluster.TemplateAWSHostedCP, + expectedConfig: config.ClusterTestingConfig{Upgrade: true, Template: "aws-hosted-cp-0-0-1", UpgradeTemplate: "aws-hosted-cp-0-0-2"}, + }, + { + title: "upgrade: should find latest template with available upgrades", + config: config.ClusterTestingConfig{Upgrade: true}, + templateType: managedcluster.TemplateAWSHostedCP, + expectedConfig: config.ClusterTestingConfig{Upgrade: true, Template: "aws-hosted-cp-0-0-1", UpgradeTemplate: "aws-hosted-cp-0-0-4"}, + }, + } { + t.Run(tt.title, func(t *testing.T) { + g := NewWithT(t) + err := Set(&tt.config, templates, tt.templateType) + if tt.expectedErr != nil { + g.Expect(err).To(MatchError(tt.expectedErr)) + } else { + g.Expect(err).To(Succeed()) + } + g.Expect(tt.expectedConfig).To(Equal(tt.config)) + }) + } +}