From 1bd231124e254ac4d96eec72b533159b0088869a Mon Sep 17 00:00:00 2001 From: Kyle Squizzato Date: Fri, 23 Aug 2024 13:03:59 -0700 Subject: [PATCH] Use envsubst to templatize deployment yaml Signed-off-by: Kyle Squizzato --- .golangci.yml | 6 +-- config/dev/deployment.yaml | 26 ++++++------ go.mod | 1 + go.sum | 2 + test/deployment/deployment.go | 40 +++++-------------- test/deployment/resources/deployment.yaml.tpl | 15 +++---- test/deployment/validate_deleted.go | 2 +- test/deployment/validate_deployed.go | 5 +-- test/e2e/e2e_test.go | 6 +-- test/kubeclient/kubeclient.go | 2 +- test/utils/utils.go | 6 +-- 11 files changed, 48 insertions(+), 63 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index ca69a11f6..a6ffbedab 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -9,10 +9,10 @@ issues: # restore some of the defaults # (fill in the rest as needed) exclude-rules: - - path: "api/*" + - path: 'api/*' linters: - lll - - path: "internal/*" + - path: 'internal/*' linters: - dupl - lll @@ -21,7 +21,7 @@ linters: enable: - dupl - errcheck - - exportloopref + - copyloopvar - goconst - gocyclo - gofmt diff --git a/config/dev/deployment.yaml b/config/dev/deployment.yaml index 8d85b82a5..58ba18e32 100644 --- a/config/dev/deployment.yaml +++ b/config/dev/deployment.yaml @@ -1,17 +1,17 @@ apiVersion: hmc.mirantis.com/v1alpha1 kind: Deployment metadata: - name: bba1743d-e2e-test + name: aws-dev spec: - config: - controlPlane: - amiID: ami-0989c067ff3da4b27 - instanceType: t3.small - controlPlaneNumber: 1 - publicIP: true - region: us-west-2 - worker: - amiID: ami-0989c067ff3da4b27 - instanceType: t3.small - workersNumber: 1 - template: aws-standalone-cp + template: aws-standalone-cp + config: + region: us-east-2 + publicIP: true + controlPlaneNumber: 1 + workersNumber: 1 + controlPlane: + amiID: ami-02f3416038bdb17fb + instanceType: t3.small + worker: + amiID: ami-02f3416038bdb17fb + instanceType: t3.small diff --git a/go.mod b/go.mod index 700292020..05080d404 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/Mirantis/hmc go 1.22.0 require ( + github.com/a8m/envsubst v1.4.2 github.com/cert-manager/cert-manager v1.15.3 github.com/fluxcd/helm-controller/api v1.0.1 github.com/fluxcd/pkg/apis/meta v1.6.0 diff --git a/go.sum b/go.sum index 49526a60b..7e73c2b18 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,8 @@ github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7 github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg= +github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= diff --git a/test/deployment/deployment.go b/test/deployment/deployment.go index 5faedb169..3cbfcb361 100644 --- a/test/deployment/deployment.go +++ b/test/deployment/deployment.go @@ -22,6 +22,7 @@ import ( "os/exec" "github.com/Mirantis/hmc/test/utils" + "github.com/a8m/envsubst" "github.com/google/uuid" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -43,7 +44,7 @@ const ( ) //go:embed resources/deployment.yaml.tpl -var deploymentConfigBytes []byte +var deploymentTemplateBytes []byte // GetUnstructuredDeployment returns an unstructured deployment object based on // the provider and template. @@ -53,41 +54,22 @@ func GetUnstructuredDeployment(provider ProviderType, templateName Template) *un generatedName := uuid.New().String()[:8] + "-e2e-test" _, _ = fmt.Fprintf(GinkgoWriter, "Generated AWS cluster name: %q\n", generatedName) - var deploymentConfig map[string]interface{} - - err := yaml.Unmarshal(deploymentConfigBytes, &deploymentConfig) - Expect(err).NotTo(HaveOccurred(), "failed to unmarshal deployment config") - switch provider { case ProviderAWS: // XXX: Maybe we should just use automatic AMI selection here. amiID := getAWSAMI() - awsRegion := os.Getenv("AWS_REGION") - - // Modify the deployment config to use the generated name and the AMI. - // TODO: This should be modified to use go templating. - if metadata, ok := deploymentConfig["metadata"].(map[string]interface{}); ok { - metadata["name"] = generatedName - } else { - // Ensure we always have a metadata.name field populated. - deploymentConfig["metadata"] = map[string]interface{}{"name": generatedName} - } - if spec, ok := deploymentConfig["spec"].(map[string]interface{}); ok { - if config, ok := spec["config"].(map[string]interface{}); ok { - if awsRegion != "" { - config["region"] = awsRegion - } + Expect(os.Setenv("AMI_ID", amiID)).NotTo(HaveOccurred()) + Expect(os.Setenv("DEPLOYMENT_NAME", generatedName)).NotTo(HaveOccurred()) + Expect(os.Setenv("TEMPLATE_NAME", string(templateName))).NotTo(HaveOccurred()) - if worker, ok := config["worker"].(map[string]interface{}); ok { - worker["amiID"] = amiID - } + deploymentConfigBytes, err := envsubst.Bytes(deploymentTemplateBytes) + Expect(err).NotTo(HaveOccurred(), "failed to substitute environment variables") - if controlPlane, ok := config["controlPlane"].(map[string]interface{}); ok { - controlPlane["amiID"] = amiID - } - } - } + var deploymentConfig map[string]interface{} + + err = yaml.Unmarshal(deploymentConfigBytes, &deploymentConfig) + Expect(err).NotTo(HaveOccurred(), "failed to unmarshal deployment config") return &unstructured.Unstructured{Object: deploymentConfig} default: diff --git a/test/deployment/resources/deployment.yaml.tpl b/test/deployment/resources/deployment.yaml.tpl index 372003b58..ac10f9f84 100644 --- a/test/deployment/resources/deployment.yaml.tpl +++ b/test/deployment/resources/deployment.yaml.tpl @@ -3,15 +3,16 @@ kind: Deployment metadata: name: ${DEPLOYMENT_NAME} spec: + template: ${TEMPLATE_NAME} config: + region: ${AWS_REGION} + publicIP: ${PUBLIC_IP:=true} + controlPlaneNumber: ${CONTROL_PLANE_NUMBER:=1} + workersNumber: ${WORKERS_NUMBER:=1} controlPlane: amiID: ${AMI_ID} - instanceType: ${INSTANCE_TYPE} - controlPlaneNumber: ${CONTROL_PLANE_NUMBER} - publicIP: ${PUBLIC_IP} - region: ${AWS_REGION} + instanceType: ${INSTANCE_TYPE:=t3.small} worker: amiID: ${AMI_ID} - instanceType: ${INSTANCE_TYPE} - workersNumber: ${WORKERS_NUMBER} - template: ${TEMPLATE_NAME} + instanceType: ${INSTANCE_TYPE:=t3.small} + diff --git a/test/deployment/validate_deleted.go b/test/deployment/validate_deleted.go index 6be7b5969..ae0497939 100644 --- a/test/deployment/validate_deleted.go +++ b/test/deployment/validate_deleted.go @@ -36,7 +36,7 @@ func VerifyProviderDeleted(ctx context.Context, kc *kubeclient.KubeClient, clust // as to not move on to the next resource type until the first is resolved. // We use []string here since order is important. for _, name := range []string{"control-planes", "machinedeployments", "clusters"} { - validator, ok := resourceValidators[name] + validator, ok := deletionValidators[name] if !ok { continue } diff --git a/test/deployment/validate_deployed.go b/test/deployment/validate_deployed.go index 8aebc458c..66b3d7709 100644 --- a/test/deployment/validate_deployed.go +++ b/test/deployment/validate_deployed.go @@ -191,8 +191,7 @@ func validateCSIDriver(ctx context.Context, kc *kubeclient.KubeClient, clusterNa // Since these resourceValidationFuncs are intended to be used in // Eventually we should ensure a follow-up PVCreate is a no-op. if !apierrors.IsAlreadyExists(err) { - // XXX: Maybe we should Fail here? - return fmt.Errorf("failed to create test PVC: %w", err) + Fail(fmt.Sprintf("failed to create test PVC: %v", err)) } } @@ -228,7 +227,7 @@ func validateCSIDriver(ctx context.Context, kc *kubeclient.KubeClient, clusterNa }, metav1.CreateOptions{}) if err != nil { if !apierrors.IsAlreadyExists(err) { - return fmt.Errorf("failed to create test Pod: %w", err) + Fail(fmt.Sprintf("failed to create test Pod: %v", err)) } } diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 9645b1e72..ebec00019 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -64,7 +64,7 @@ var _ = Describe("controller", Ordered, func() { } if len(podList.Items) != 1 { - return fmt.Errorf("expected 1 controller pod, got %d", len(podList.Items)) + return fmt.Errorf("expected 1 cluster-api-controller pod, got %d", len(podList.Items)) } controllerPod := podList.Items[0] @@ -84,7 +84,7 @@ var _ = Describe("controller", Ordered, func() { return nil } - EventuallyWithOffset(1, func() error { + Eventually(func() error { err := verifyControllerUp() if err != nil { _, _ = fmt.Fprintf(GinkgoWriter, "Controller pod validation failed: %v\n", err) @@ -92,7 +92,7 @@ var _ = Describe("controller", Ordered, func() { } return nil - }(), 5*time.Minute, time.Second).Should(Succeed()) + }).WithTimeout(5 * time.Minute).WithPolling(10 * time.Second).Should(Succeed()) }) }) diff --git a/test/kubeclient/kubeclient.go b/test/kubeclient/kubeclient.go index d2521291d..dd8a7a5d1 100644 --- a/test/kubeclient/kubeclient.go +++ b/test/kubeclient/kubeclient.go @@ -262,7 +262,7 @@ func (kc *KubeClient) ListMachineDeployments( func (kc *KubeClient) ListK0sControlPlanes( ctx context.Context, clusterName string) ([]unstructured.Unstructured, error) { return kc.listResource(ctx, schema.GroupVersionResource{ - Group: "control-plane.cluster.x-k8s.io", + Group: "controlplane.cluster.x-k8s.io", Version: "v1beta1", Resource: "k0scontrolplanes", }, clusterName) diff --git a/test/utils/utils.go b/test/utils/utils.go index 613ac9605..d4cc82587 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -130,16 +130,16 @@ func ValidateConditionsTrue(unstrObj *unstructured.Unstructured) error { continue } - errorStr := fmt.Sprintf("%s: %s", c.Type, c.Reason) + errorStr := fmt.Sprintf("%s - Reason: %s", c.Type, c.Reason) if c.Message != "" { errorStr = fmt.Sprintf("%s: %s", errorStr, c.Message) } - errs = errors.Join(fmt.Errorf(errorStr), errs) + errs = errors.Join(errors.New(errorStr), errs) } if errs != nil { - return fmt.Errorf("%s %s is not ready with conditions: %w", objKind, objName, errs) + return fmt.Errorf("%s %s is not ready with conditions:\n%w", objKind, objName, errs) } return nil