From 44a6851644cb2bfa49f5050a7e0a8961284a8183 Mon Sep 17 00:00:00 2001 From: Vidya Reddy <59590642+Vidya2606@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:28:40 -0700 Subject: [PATCH] Migrating the Azpipeline templates to Go templates (#373) --- pkg/azurePipelines/azurePipelines.go | 2 +- pkg/azurePipelines/azurePipelines_test.go | 20 +++++- pkg/fixtures/pipelines/kustomize.yaml | 68 +++++++++++++++++++ pkg/fixtures/pipelines/manifests.yaml | 60 ++++++++++++++++ pkg/fixtures/validatetemplate.go | 37 ++++++++++ .../.pipelines/azure-kubernetes-service.yaml | 25 +++---- .../.pipelines/azure-kubernetes-service.yaml | 23 ++++--- 7 files changed, 208 insertions(+), 27 deletions(-) create mode 100644 pkg/fixtures/pipelines/kustomize.yaml create mode 100644 pkg/fixtures/pipelines/manifests.yaml create mode 100644 pkg/fixtures/validatetemplate.go diff --git a/pkg/azurePipelines/azurePipelines.go b/pkg/azurePipelines/azurePipelines.go index f4defc19..c46fee1d 100644 --- a/pkg/azurePipelines/azurePipelines.go +++ b/pkg/azurePipelines/azurePipelines.go @@ -125,7 +125,7 @@ func (p *AzurePipelines) CreatePipelineFiles(deployType string, draftConfig *con return fmt.Errorf("error applying default variables: %w", err) } - if err := osutil.CopyDir(p.pipelineTemplates, srcDir, p.dest, draftConfig, templateWriter); err != nil { + if err := osutil.CopyDirWithTemplates(p.pipelineTemplates, srcDir, p.dest, draftConfig, templateWriter); err != nil { return fmt.Errorf("error copying pipeline files: %w", err) } diff --git a/pkg/azurePipelines/azurePipelines_test.go b/pkg/azurePipelines/azurePipelines_test.go index 7e781083..798d7f4b 100644 --- a/pkg/azurePipelines/azurePipelines_test.go +++ b/pkg/azurePipelines/azurePipelines_test.go @@ -2,6 +2,7 @@ package azurePipelines import ( "fmt" + "github.com/Azure/draft/pkg/fixtures" "os" "testing" @@ -32,7 +33,7 @@ func TestCreatePipelines(t *testing.T) { deployType: "kustomize", shouldError: false, setConfig: func(dc *config.DraftConfig) { - dc.SetVariable("KUSTOMIZEPATH", "test/kustomize/overlays/production") + dc.SetVariable("KUSTOMIZEPATH", "kustomize/overlays/production") }, }, { @@ -40,7 +41,7 @@ func TestCreatePipelines(t *testing.T) { deployType: "manifests", shouldError: false, setConfig: func(dc *config.DraftConfig) { - dc.SetVariable("PIPELINENAME", "some-other-name") + dc.SetVariable("PIPELINENAME", "testPipeline") }, }, { @@ -95,6 +96,19 @@ func TestCreatePipelines(t *testing.T) { assert.Nil(t, err) _, err = os.Stat(pipelineFilePath) assert.Nil(t, err) + + // Read the generated content + generatedContent, err := os.ReadFile(pipelineFilePath) + assert.Nil(t, err) + + // Validate against the fixture file + fixturePath := fmt.Sprintf("../fixtures/pipelines/%s.yaml", tt.deployType) + if _, err := os.Stat(fixturePath); os.IsNotExist(err) { + t.Fatalf("Fixture file does not exist at path: %s", fixturePath) + } + + err = fixtures.ValidateContentAgainstFixture(generatedContent, fixturePath) + assert.Nil(t, err) } err = os.RemoveAll(tempDir) @@ -148,7 +162,7 @@ func newDraftConfig() *config.DraftConfig { { Name: "MANIFESTPATH", Default: config.BuilderVarDefault{ - Value: "manifests", + Value: "test/manifests", }, }, { diff --git a/pkg/fixtures/pipelines/kustomize.yaml b/pkg/fixtures/pipelines/kustomize.yaml new file mode 100644 index 00000000..ae60918f --- /dev/null +++ b/pkg/fixtures/pipelines/kustomize.yaml @@ -0,0 +1,68 @@ +# Azure Kubernetes Service (AKS) pipeline with Kustomize +# Build and push image to Azure Container Registry; Deploy to Azure Kubernetes Service cluster + +variables: + armServiceConnection: testServiceConnection + azureContainerRegistry: testACR + containerName: testContainer + acrRg: testACRRG + clusterRg: testRG + clusterName: testCluster + kustomizePath: kustomize/overlays/production + namespace: testNamespace + tag: "$(Build.BuildId)" + vmImageName: "ubuntu-latest" + +trigger: + - main + +name: testPipeline + +stages: + - stage: BuildAndPush + displayName: Build stage + jobs: + - job: BuildAndPush + displayName: Build and push image + pool: + vmImage: $(vmImageName) + steps: + - task: AzureCLI@2 + displayName: Build and push image to Azure Container Registry + inputs: + azureSubscription: $(armServiceConnection) + scriptType: "bash" + scriptLocation: "inlineScript" + inlineScript: | + az acr build --image $1.azurecr.io/$2:$3 --registry $1 -g $4 . + arguments: "$(azureContainerRegistry) $(containerName) $(tag) $(acrRg)" + + - stage: Deploy + displayName: Deploy stage + dependsOn: BuildAndPush + jobs: + - job: Deploy + displayName: Deploy to AKS using Kustomize + pool: + vmImage: $(vmImageName) + steps: + - task: KubernetesManifest@1 + displayName: Bake Kustomize manifests + inputs: + action: 'bake' + kustomizationPath: $(kustomizePath) + renderType: 'kustomize' + name: 'bake' + + - task: KubernetesManifest@1 + displayName: Deploy baked manifests to Kubernetes cluster + inputs: + action: 'deploy' + connectionType: 'azureResourceManager' + azureSubscriptionConnection: $(armServiceConnection) + azureResourceGroup: $(clusterRg) + kubernetesCluster: $(clusterName) + namespace: $(namespace) + manifests: $(bake.manifestsBundle) + containers: | + $(azureContainerRegistry).azurecr.io/$(containerName):$(tag) diff --git a/pkg/fixtures/pipelines/manifests.yaml b/pkg/fixtures/pipelines/manifests.yaml new file mode 100644 index 00000000..754cef97 --- /dev/null +++ b/pkg/fixtures/pipelines/manifests.yaml @@ -0,0 +1,60 @@ +# Azure Kubernetes Service pipeline +# Build and push image to Azure Container Registry; Deploy to Azure Kubernetes Service cluster + +variables: + armServiceConnection: testServiceConnection + azureContainerRegistry: testACR + containerName: testContainer + clusterRg: testRG + acrRg: testACRRG + clusterName: testCluster + manifestPath: test/manifests + namespace: testNamespace + tag: "$(Build.BuildId)" + vmImageName: "ubuntu-latest" + +name: testPipeline + +trigger: + - main + +stages: + - stage: BuildAndPush + displayName: Build stage + jobs: + - job: BuildAndPush + displayName: Build and push image + pool: + vmImage: $(vmImageName) + steps: + - task: AzureCLI@2 + displayName: Build and push image to Azure Container Registry + inputs: + azureSubscription: $(armServiceConnection) + scriptType: "bash" + scriptLocation: "inlineScript" + inlineScript: | + az acr build --image $1.azurecr.io/$2:$3 --registry $1 -g $4 . + arguments: "$(azureContainerRegistry) $(containerName) $(tag) $(acrRg)" + + - stage: Deploy + displayName: Deploy stage + dependsOn: BuildAndPush + jobs: + - job: Deploy + displayName: Deploy to AKS + pool: + vmImage: $(vmImageName) + steps: + - task: KubernetesManifest@1 + displayName: Deploy to Kubernetes cluster + inputs: + action: "deploy" + connectionType: "azureResourceManager" + azureSubscriptionConnection: $(armServiceConnection) + azureResourceGroup: $(clusterRg) + kubernetesCluster: $(clusterName) + manifests: $(manifestPath) + namespace: $(namespace) + containers: | + $(azureContainerRegistry).azurecr.io/$(containerName):$(tag) diff --git a/pkg/fixtures/validatetemplate.go b/pkg/fixtures/validatetemplate.go new file mode 100644 index 00000000..b6149a00 --- /dev/null +++ b/pkg/fixtures/validatetemplate.go @@ -0,0 +1,37 @@ +package fixtures + +import ( + "embed" + "errors" + "fmt" + "os" + "regexp" + "strings" +) + +//go:embed pipelines/* +var pipelines embed.FS + +func ValidateContentAgainstFixture(generatedContent []byte, fixturePath string) error { + fullFixturePath := fmt.Sprintf("%s", fixturePath) + + // Read the fixture content + fixtureContent, err := os.ReadFile(fullFixturePath) + if err != nil { + return fmt.Errorf("failed to read fixture: %w", err) + } + + if normalizeWhitespace(fixtureContent) != normalizeWhitespace(generatedContent) { + return errors.New("generated content does not match fixture") + } + + return nil +} + +func normalizeWhitespace(content []byte) string { + s := string(content) + re := regexp.MustCompile(`\r?\n`) + s = re.ReplaceAllString(s, "\n") + re = regexp.MustCompile(`\s+`) + return strings.TrimSpace(re.ReplaceAllString(s, " ")) +} diff --git a/template/azurePipelines/kustomize/.pipelines/azure-kubernetes-service.yaml b/template/azurePipelines/kustomize/.pipelines/azure-kubernetes-service.yaml index 5910a833..f307aaed 100644 --- a/template/azurePipelines/kustomize/.pipelines/azure-kubernetes-service.yaml +++ b/template/azurePipelines/kustomize/.pipelines/azure-kubernetes-service.yaml @@ -2,22 +2,22 @@ # Build and push image to Azure Container Registry; Deploy to Azure Kubernetes Service cluster variables: - armServiceConnection: {{ARMSERVICECONNECTION}} - azureContainerRegistry: {{AZURECONTAINERREGISTRY}} - containerName: {{CONTAINERNAME}} - acrRg: {{ACRRESOURCEGROUP}} - clusterRg: {{CLUSTERRESOURCEGROUP}} - clusterName: {{CLUSTERNAME}} - kustomizePath: {{KUSTOMIZEPATH}} - namespace: {{NAMESPACE}} + armServiceConnection: {{.ARMSERVICECONNECTION}} + azureContainerRegistry: {{.AZURECONTAINERREGISTRY}} + containerName: {{.CONTAINERNAME}} + acrRg: {{.ACRRESOURCEGROUP}} + clusterRg: {{.CLUSTERRESOURCEGROUP}} + clusterName: {{.CLUSTERNAME}} + kustomizePath: {{.KUSTOMIZEPATH}} + namespace: {{.NAMESPACE}} tag: "$(Build.BuildId)" vmImageName: "ubuntu-latest" trigger: - - {{BRANCHNAME}} - -name: {{PIPELINENAME}} + - {{.BRANCHNAME}} +name: {{.PIPELINENAME}} +{{` stages: - stage: BuildAndPush displayName: Build stage @@ -65,4 +65,5 @@ stages: namespace: $(namespace) manifests: $(bake.manifestsBundle) containers: | - $(azureContainerRegistry).azurecr.io/$(containerName):$(tag) \ No newline at end of file + $(azureContainerRegistry).azurecr.io/$(containerName):$(tag) +`}} \ No newline at end of file diff --git a/template/azurePipelines/manifests/.pipelines/azure-kubernetes-service.yaml b/template/azurePipelines/manifests/.pipelines/azure-kubernetes-service.yaml index 45c06f8f..10ef1d38 100644 --- a/template/azurePipelines/manifests/.pipelines/azure-kubernetes-service.yaml +++ b/template/azurePipelines/manifests/.pipelines/azure-kubernetes-service.yaml @@ -2,22 +2,22 @@ # Build and push image to Azure Container Registry; Deploy to Azure Kubernetes Service cluster variables: - armServiceConnection: {{ARMSERVICECONNECTION}} - azureContainerRegistry: {{AZURECONTAINERREGISTRY}} - containerName: {{CONTAINERNAME}} - clusterRg: {{CLUSTERRESOURCEGROUP}} - acrRg: {{ACRRESOURCEGROUP}} - clusterName: {{CLUSTERNAME}} - manifestPath: {{MANIFESTPATH}} - namespace: {{NAMESPACE}} + armServiceConnection: {{.ARMSERVICECONNECTION}} + azureContainerRegistry: {{.AZURECONTAINERREGISTRY}} + containerName: {{.CONTAINERNAME}} + clusterRg: {{.CLUSTERRESOURCEGROUP}} + acrRg: {{.ACRRESOURCEGROUP}} + clusterName: {{.CLUSTERNAME}} + manifestPath: {{.MANIFESTPATH}} + namespace: {{.NAMESPACE}} tag: "$(Build.BuildId)" vmImageName: "ubuntu-latest" -name: {{PIPELINENAME}} +name: {{.PIPELINENAME}} trigger: - - {{BRANCHNAME}} - + - {{.BRANCHNAME}} +{{` stages: - stage: BuildAndPush displayName: Build stage @@ -58,3 +58,4 @@ stages: namespace: $(namespace) containers: | $(azureContainerRegistry).azurecr.io/$(containerName):$(tag) +`}} \ No newline at end of file