diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..c59c2cfdd3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + + - package-ecosystem: nuget + directory: /Webapp/SDAF + schedule: + interval: daily + + - package-ecosystem: npm + directory: /Webapp + schedule: + interval: daily diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..563a959494 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,78 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: ["development"] + pull_request: + # The branches below must be a subset of the branches above + branches: ["development"] + schedule: + - cron: "0 0 * * 1" + +permissions: + contents: read + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["csharp", "javascript", "python"] + # CodeQL supports [ $supported-codeql-languages ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Harden Runner + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000000..21a469b132 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,27 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 + with: + egress-policy: audit + + - name: 'Checkout Repository' + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: 'Dependency Review' + uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0 diff --git a/.github/workflows/github-actions-ansible-lint.yml b/.github/workflows/github-actions-ansible-lint.yml index c83f78bd56..012a32458f 100644 --- a/.github/workflows/github-actions-ansible-lint.yml +++ b/.github/workflows/github-actions-ansible-lint.yml @@ -1,15 +1,23 @@ name: Ansible Lint on: [push, pull_request] +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 + with: + egress-policy: audit + - name: Checkout the code - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - name: Setup Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 #v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b #v5.3.0 with: python-version: '3.x' diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index df1d38fcd7..8199da873e 100644 --- a/.github/workflows/ossf-scorecard.yml +++ b/.github/workflows/ossf-scorecard.yml @@ -31,13 +31,18 @@ jobs: # actions: readhttps://github.com/hdamecharla/sap-automation-kimforss/tree/main steps: + - name: Harden Runner + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 + with: + egress-policy: audit + - name: "Checkout code" - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif @@ -59,7 +64,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: SARIF file path: results.sarif @@ -68,6 +73,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 with: sarif_file: results.sarif diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml new file mode 100644 index 0000000000..fca33c0f12 --- /dev/null +++ b/.github/workflows/trivy.yml @@ -0,0 +1,43 @@ +--- +name: trivy + +on: + pull_request: + types: [ 'opened', 'reopened', 'synchronize' ] + merge_group: + workflow_dispatch: + + +permissions: + actions: read + contents: read + security-events: write + +jobs: + build: + name: 'trivy scan' + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 + with: + egress-policy: audit + + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Run Trivy vulnerability scanner (file system) + uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # 0.29.0 + with: + scan-type: 'fs' + ignore-unfixed: true + scan-ref: . + format: 'sarif' + scanners: 'vuln,secret,config' + output: report-fs.sarif + + - name: Upload Trivy report (fs) GitHub Security + uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + with: + sarif_file: report-fs.sarif + category: 'fs' diff --git a/.gitignore b/.gitignore index 26704c04c8..2178936c15 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,40 @@ Importer/SDAF SDU Importer/SDAFSDUImporter/bin __pycache__/ __pycache__ *.pyc + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..66d4c9be50 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,22 @@ +repos: +- repo: https://github.com/gitleaks/gitleaks + rev: v8.16.3 + hooks: + - id: gitleaks +- repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shellcheck +- repo: https://github.com/pre-commit/mirrors-eslint + rev: v8.38.0 + hooks: + - id: eslint +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace +- repo: https://github.com/pylint-dev/pylint + rev: v2.17.2 + hooks: + - id: pylint diff --git a/Webapp/SDAF/.config/dotnet-tools.json b/Webapp/SDAF/.config/dotnet-tools.json index 2e65f8701e..17c1a84c64 100644 --- a/Webapp/SDAF/.config/dotnet-tools.json +++ b/Webapp/SDAF/.config/dotnet-tools.json @@ -9,10 +9,10 @@ ] }, "dotnet-ef": { - "version": "7.0.0", + "version": "9.0.0", "commands": [ "dotnet-ef" ] } } -} \ No newline at end of file +} diff --git a/Webapp/SDAF/Controllers/ArmclientController.cs b/Webapp/SDAF/Controllers/ArmclientController.cs index f6277b4ee4..9077e172b1 100644 --- a/Webapp/SDAF/Controllers/ArmclientController.cs +++ b/Webapp/SDAF/Controllers/ArmclientController.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Mvc.Rendering; using System.Collections.Generic; -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { public class ArmclientController : Controller { diff --git a/Webapp/SDAF/Controllers/EnvironmentController.cs b/Webapp/SDAF/Controllers/EnvironmentController.cs index efff82a169..e385088aba 100644 --- a/Webapp/SDAF/Controllers/EnvironmentController.cs +++ b/Webapp/SDAF/Controllers/EnvironmentController.cs @@ -1,10 +1,10 @@ -using AutomationForm.Models; +using SDAFWebApp.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using System; using System.Threading.Tasks; -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { public class EnvironmentController : Controller { diff --git a/Webapp/SDAF/Controllers/FileController.cs b/Webapp/SDAF/Controllers/FileController.cs index 1617fd1798..f7f7e02b2c 100644 --- a/Webapp/SDAF/Controllers/FileController.cs +++ b/Webapp/SDAF/Controllers/FileController.cs @@ -1,6 +1,6 @@ -using AutomationForm.Models; -using AutomationForm.Services; -using AutomationForm.Controllers; +using SDAFWebApp.Models; +using SDAFWebApp.Services; +using SDAFWebApp.Controllers; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; @@ -18,7 +18,7 @@ using System.Drawing.Drawing2D; using System.Collections.Concurrent; -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { public class FileController : Controller { diff --git a/Webapp/SDAF/Controllers/Helper.cs b/Webapp/SDAF/Controllers/Helper.cs index 26129a7bf9..c4b68bb0a0 100644 --- a/Webapp/SDAF/Controllers/Helper.cs +++ b/Webapp/SDAF/Controllers/Helper.cs @@ -1,5 +1,5 @@ -using AutomationForm.Models; -using AutomationForm.Services; +using SDAFWebApp.Models; +using SDAFWebApp.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; @@ -16,7 +16,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { public class Helper : Controller { diff --git a/Webapp/SDAF/Controllers/HomeController.cs b/Webapp/SDAF/Controllers/HomeController.cs index acf6af8444..78f90a8311 100644 --- a/Webapp/SDAF/Controllers/HomeController.cs +++ b/Webapp/SDAF/Controllers/HomeController.cs @@ -1,9 +1,9 @@ -using AutomationForm.Models; +using SDAFWebApp.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System.Diagnostics; -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { public class HomeController : Controller { diff --git a/Webapp/SDAF/Controllers/LandscapeController.cs b/Webapp/SDAF/Controllers/LandscapeController.cs index eabf1fadd3..12041fa2d2 100644 --- a/Webapp/SDAF/Controllers/LandscapeController.cs +++ b/Webapp/SDAF/Controllers/LandscapeController.cs @@ -1,10 +1,10 @@ -using AutomationForm.Models; -using AutomationForm.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Configuration; using Microsoft.Net.Http.Headers; using Newtonsoft.Json; +using SDAFWebApp.Models; +using SDAFWebApp.Services; using System; using System.Collections.Generic; using System.IO; @@ -12,9 +12,9 @@ using System.Text; using System.Threading.Tasks; -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { - public class LandscapeController : Controller + public class LandscapeController : Controller { private readonly ITableStorageService _landscapeService; diff --git a/Webapp/SDAF/Controllers/RestHelper.cs b/Webapp/SDAF/Controllers/RestHelper.cs index ba17f265b2..9649735b11 100644 --- a/Webapp/SDAF/Controllers/RestHelper.cs +++ b/Webapp/SDAF/Controllers/RestHelper.cs @@ -1,16 +1,11 @@ -using AutomationForm.Models; using Azure.Core; using Azure.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Configuration; -using Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos; -using Microsoft.VisualStudio.Services.Client; -using Microsoft.VisualStudio.Services.Common; -using Microsoft.VisualStudio.Services.TenantPolicy; -using Microsoft.VisualStudio.Services.WebApi; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using SDAFWebApp.Models; using System; using System.Collections.Generic; using System.Net.Http; @@ -19,352 +14,363 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Microsoft.VisualStudio.Services.Client; +using Microsoft.VisualStudio.Services.Common; +using Microsoft.VisualStudio.Services.TenantPolicy; +using Microsoft.VisualStudio.Services.WebApi; + using JsonSerializer = System.Text.Json.JsonSerializer; #pragma warning disable SYSLIB0020 -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { - public class RestHelper : Controller - { - private readonly string collectionUri; - private readonly string project; - private readonly string repositoryId; - private readonly string PAT; - private readonly string branch; - private readonly string sdafGeneralId; - private readonly string sdafControlPlaneEnvironment; - private readonly string sdafControlPlaneLocation; - private readonly string tenantId; - private readonly string managedIdentityClientId; - - private readonly TokenCredential credential; - - private readonly string sampleUrl = "https://api.github.com/repos/Azure/SAP-automation-samples"; - - private HttpClient client; - - public RestHelper(IConfiguration configuration, string type = "ADO") + public class RestHelper : Controller { - collectionUri = configuration["CollectionUri"]; - project = configuration["ProjectName"]; - repositoryId = configuration["RepositoryId"]; - PAT = configuration["PAT"]; - string devops_authentication = configuration["AUTHENTICATION_TYPE"]; - branch = configuration["SourceBranch"]; - sdafGeneralId = configuration["SDAF_GENERAL_GROUP_ID"]; - sdafControlPlaneEnvironment = configuration["CONTROLPLANE_ENV"]; - sdafControlPlaneLocation = configuration["CONTROLPLANE_LOC"]; - tenantId = configuration["AZURE_TENANT_ID"]; - managedIdentityClientId = configuration["OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID"]; - - if (type == "ADO") - { - if (devops_authentication == "PAT") - { - client = new HttpClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", - Convert.ToBase64String( - System.Text.ASCIIEncoding.ASCII.GetBytes( - string.Format("{0}:{1}", "", PAT)))); - } - else - { - credential = new DefaultAzureCredential( - new DefaultAzureCredentialOptions - { - TenantId = tenantId, - ManagedIdentityClientId = managedIdentityClientId - }); ; + private readonly string collectionUri; + private readonly string project; + private readonly string repositoryId; + private readonly string PAT; + private readonly string branch; + private readonly string sdafGeneralId; + private readonly string sdafControlPlaneEnvironment; + private readonly string sdafControlPlaneLocation; + private readonly string tenantId; + private readonly string managedIdentityClientId; + private readonly Azure.Identity.DefaultAzureCredential credential; - var tokenRequestContext = new TokenRequestContext(VssAadSettings.DefaultScopes); - var token = credential.GetToken(tokenRequestContext, CancellationToken.None); + private readonly string sampleUrl = "https://api.github.com/repos/Azure/SAP-automation-samples"; - var accessToken = token.Token; - var vssToken = new VssAadToken("Bearer", accessToken); + private HttpClient client; - client = new HttpClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", - accessToken); + private JsonSerializerOptions jsonSerializerOptions; - } + public RestHelper(IConfiguration configuration, string type = "ADO") + { + collectionUri = configuration["CollectionUri"]; + project = configuration["ProjectName"]; + repositoryId = configuration["RepositoryId"]; + PAT = configuration["PAT"]; + string devops_authentication = configuration["AUTHENTICATION_TYPE"]; + branch = configuration["SourceBranch"]; + sdafGeneralId = configuration["SDAF_GENERAL_GROUP_ID"]; + sdafControlPlaneEnvironment = configuration["CONTROLPLANE_ENV"]; + sdafControlPlaneLocation = configuration["CONTROLPLANE_LOC"]; + tenantId = configuration["AZURE_TENANT_ID"]; + managedIdentityClientId = configuration["OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID"]; + + jsonSerializerOptions = new JsonSerializerOptions() { IgnoreNullValues = true }; + + if (type == "ADO") + { + if (devops_authentication == "PAT") + { + client = new HttpClient(); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", + Convert.ToBase64String( + System.Text.ASCIIEncoding.ASCII.GetBytes( + string.Format("{0}:{1}", "", PAT)))); + } + else + { + if (string.IsNullOrEmpty(tenantId) || string.IsNullOrEmpty(managedIdentityClientId)) + { + throw new ArgumentNullException("TenantId and ManagedIdentityClientId must be provided for Managed Identity authentication."); + } - client.DefaultRequestHeaders.Accept.Add( - new MediaTypeWithQualityHeaderValue("application/json")); - client.DefaultRequestHeaders.Add("User-Agent", "sap-automation"); - } - else - { - client = new HttpClient(); + credential = new DefaultAzureCredential( + new DefaultAzureCredentialOptions + { + TenantId = tenantId, + ManagedIdentityClientId = managedIdentityClientId + }); - client.DefaultRequestHeaders.Accept.Add( - new MediaTypeWithQualityHeaderValue("application/json")); + //var tokenRequestContext = new TokenRequestContext(new[] { "https://management.azure.com/.default", "499b84ac-1321-427f-aa17-267ca6975798/.default" }); - client.DefaultRequestHeaders.Add("User-Agent", "sap-automation"); - } + var tokenRequestContext = new TokenRequestContext(VssAadSettings.DefaultScopes); + var token = credential.GetToken(tokenRequestContext, CancellationToken.None); + var accessToken = token.Token; - } + client = new HttpClient(); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", + accessToken); + } - // Get ADO project id - public async Task GetProjectId() - { - string getUri = $"{collectionUri}_apis/projects/{project}?api-version=7.1-preview.4"; - using HttpResponseMessage response = client.GetAsync(getUri).Result; - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); + client.DefaultRequestHeaders.Add("User-Agent", "sap-automation"); + } + else + { + client = new HttpClient(); - return JsonDocument.Parse(responseBody).RootElement.GetProperty("id").GetString(); - } + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); - // Add or edit a file in ADO - public async Task UpdateRepo(string path, string content) - { - string getUri = $"{collectionUri}{project}/_apis/git/repositories/{repositoryId}/refs/?filter=heads/{branch}"; - string postUri = $"{collectionUri}{project}/_apis/git/repositories/{repositoryId}/pushes?api-version=5.1"; - string ooId; + client.DefaultRequestHeaders.Add("User-Agent", "sap-automation"); + } + } - using HttpResponseMessage response = client.GetAsync(getUri).Result; - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); + // Get ADO project id + public async Task GetProjectId() + { + string getUri = $"{collectionUri}_apis/projects/{project}?api-version=7.1"; + using HttpResponseMessage response = client.GetAsync(getUri).Result; + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); - ooId = JsonDocument.Parse(responseBody).RootElement.GetProperty("value")[0].GetProperty("objectId").GetString(); + return JsonDocument.Parse(responseBody).RootElement.GetProperty("id").GetString(); + } - // Dynamically retrieve path - string pathBase = await GetVariableFromVariableGroup(sdafGeneralId, "SDAF-General", "Deployment_Configuration_Path"); - path = pathBase + path; + // Add or edit a file in ADO + public async Task UpdateRepo(string path, string content) + { + string getUri = $"{collectionUri}{project}/_apis/git/repositories/{repositoryId}/refs/?filter=heads/{branch}"; + string postUri = $"{collectionUri}{project}/_apis/git/repositories/{repositoryId}/pushes?api-version=5.1"; + string ooId; - // Create request body - Refupdate refUpdate = new() - { - name = $"refs/heads/{branch}", - oldObjectId = ooId - }; - GitRequestBody requestBody = new() - { - refUpdates = new Refupdate[] { refUpdate }, - }; - StringContent editContent = Helper.CreateHttpContent("edit", path, content, requestBody); + using HttpResponseMessage response = client.GetAsync(getUri).Result; + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); - // try to edit file (if it exists) - HttpResponseMessage editResponse = await client.PostAsync(postUri, editContent); + ooId = JsonDocument.Parse(responseBody).RootElement.GetProperty("value")[0].GetProperty("objectId").GetString(); - // add file on unsuccessful edit (because it does not exist) - if (!editResponse.IsSuccessStatusCode) - { - StringContent addContent = Helper.CreateHttpContent("add", path, content, requestBody); - HttpResponseMessage addResponse = await client.PostAsync(postUri, addContent); - string addResponseBody = await addResponse.Content.ReadAsStringAsync(); - HandleResponse(addResponse, addResponseBody); - } - } + // Dynamically retrieve path + string pathBase = await GetVariableFromVariableGroup(sdafGeneralId, "SDAF-General", "Deployment_Configuration_Path"); + path = pathBase + path; - // Trigger a pipeline in azure devops - public async Task TriggerPipeline(string pipelineId, PipelineRequestBody requestBody) - { - string getUri = $"{collectionUri}{project}/_apis/pipelines/{pipelineId}"; - using HttpResponseMessage getResponse = client.GetAsync(getUri).Result; - string getResponseBody = await getResponse.Content.ReadAsStringAsync(); - HandleResponse(getResponse, getResponseBody); + // Create request body + Refupdate refUpdate = new() + { + name = $"refs/heads/{branch}", + oldObjectId = ooId + }; + GitRequestBody requestBody = new() + { + refUpdates = new Refupdate[] { refUpdate }, + }; + StringContent editContent = Helper.CreateHttpContent("edit", path, content, requestBody); - string postUri = $"{collectionUri}{project}/_apis/pipelines/{pipelineId}/runs?api-version=6.0-preview.1"; + // try to edit file (if it exists) + HttpResponseMessage editResponse = await client.PostAsync(postUri, editContent); - string requestJson = JsonSerializer.Serialize(requestBody, typeof(PipelineRequestBody), new JsonSerializerOptions() { IgnoreNullValues = true }); - StringContent content = new(requestJson, Encoding.ASCII, "application/json"); + // add file on unsuccessful edit (because it does not exist) + if (!editResponse.IsSuccessStatusCode) + { + StringContent addContent = Helper.CreateHttpContent("add", path, content, requestBody); + HttpResponseMessage addResponse = await client.PostAsync(postUri, addContent); + string addResponseBody = await addResponse.Content.ReadAsStringAsync(); + HandleResponse(addResponse, addResponseBody); + } + } - HttpResponseMessage response = await client.PostAsync(postUri, content); - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); - } + // Trigger a pipeline in azure devops + public async Task TriggerPipeline(string pipelineId, PipelineRequestBody requestBody) + { + string getUri = $"{collectionUri}{project}/_apis/pipelines/{pipelineId}"; + using HttpResponseMessage getResponse = client.GetAsync(getUri).Result; + string getResponseBody = await getResponse.Content.ReadAsStringAsync(); + HandleResponse(getResponse, getResponseBody); - // Get an array of file names from azure sap-automation region given a directory - public async Task GetTemplateFileNames(string scopePath) - { - string getUri = $"{sampleUrl}/contents/{scopePath}?ref=main"; - using HttpResponseMessage response = client.GetAsync(getUri).Result; - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); + string postUri = $"{collectionUri}{project}/_apis/pipelines/{pipelineId}/runs?api-version=7.1"; - List fileNames = new(); + string requestJson = JsonSerializer.Serialize(requestBody, typeof(PipelineRequestBody), jsonSerializerOptions); + StringContent content = new(requestJson, Encoding.UTF8, "application/json"); - JsonElement values = JsonDocument.Parse(responseBody).RootElement; - foreach (var value in values.EnumerateArray()) - { - string type = value.GetProperty("type").GetString(); - string path = value.GetProperty("path").GetString(); - if (type == "dir") - { - string[] subFiles = await GetTemplateFileNames(path); - foreach (string subFile in subFiles) - { - fileNames.Add(subFile); - } - } - else if (type == "file") - { - if (path.EndsWith(".tfvars")) - { - fileNames.Add(path); - } + HttpResponseMessage response = await client.PostAsync(postUri, content); + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); } - } - return fileNames.ToArray(); - } - - // Get a file from azure sap-automation repository - public async Task GetTemplateFile(string path) - { - string getUri = $"{sampleUrl}/contents/{path}?ref=main"; + // Get an array of file names from azure sap-automation region given a directory + public async Task GetTemplateFileNames(string scopePath) + { + string getUri = $"{sampleUrl}/contents/{scopePath}?ref=main"; + using HttpResponseMessage response = client.GetAsync(getUri).Result; + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); - using HttpResponseMessage response = client.GetAsync(getUri).Result; - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); + List fileNames = new(); - string bitstring = JsonDocument.Parse(responseBody).RootElement.GetProperty("content").GetString(); - return Encoding.UTF8.GetString(Convert.FromBase64String(bitstring)); - } + JsonElement values = JsonDocument.Parse(responseBody).RootElement; + foreach (var value in values.EnumerateArray()) + { + string type = value.GetProperty("type").GetString(); + string path = value.GetProperty("path").GetString(); + if (type == "dir") + { + string[] subFiles = await GetTemplateFileNames(path); + foreach (string subFile in subFiles) + { + fileNames.Add(subFile); + } + } + else if (type == "file") + { + if (path.EndsWith(".tfvars")) + { + fileNames.Add(path); + } + } + } - // Get the json response for all variable groups in an ado project - public async Task GetVariableGroupsJson() - { - string getUri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups?api-version=6.0-preview.2"; + return fileNames.ToArray(); + } - using HttpResponseMessage response = client.GetAsync(getUri).Result; - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); + // Get a file from azure sap-automation repository + public async Task GetTemplateFile(string path) + { + string getUri = $"{sampleUrl}/contents/{path}?ref=main"; - JsonElement values = JsonDocument.Parse(responseBody).RootElement.GetProperty("value"); - return values; - } + using HttpResponseMessage response = client.GetAsync(getUri).Result; + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); - // List all variable groups from azure devops - public async Task GetVariableGroups() - { - JsonElement values = await GetVariableGroupsJson(); + string bitstring = JsonDocument.Parse(responseBody).RootElement.GetProperty("content").GetString(); + return Encoding.UTF8.GetString(Convert.FromBase64String(bitstring)); + } - List variableGroups = new(); + // Get the json response for all variable groups in an ado project + public async Task GetVariableGroupsJson() + { + string getUri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups?api-version=7.1"; - foreach (var value in values.EnumerateArray()) - { - EnvironmentModel environment = JsonSerializer.Deserialize(value.ToString()); + using HttpResponseMessage response = client.GetAsync(getUri).Result; + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); - environment.sdafControlPlaneEnvironment = sdafControlPlaneEnvironment; - if (!environment.name.EndsWith("-" + sdafControlPlaneEnvironment)) - { - if (environment.name.StartsWith("SDAF-")) - { - environment.name = environment.name.Replace("SDAF-", ""); - variableGroups.Add(environment); - } + JsonElement values = JsonDocument.Parse(responseBody).RootElement.GetProperty("value"); + return values; } - } + // List all variable groups from azure devops + public async Task GetVariableGroups() + { + JsonElement values = await GetVariableGroupsJson(); - return variableGroups.ToArray(); - } + List variableGroups = new(); - // Get a list of all variable group names for use in a dropdown - public async Task> GetEnvironmentsList() - { - JsonElement values = await GetVariableGroupsJson(); + foreach (var value in values.EnumerateArray()) + { + EnvironmentModel environment = JsonSerializer.Deserialize(value.ToString()); - List variableGroups = new() - { - new SelectListItem { Text = "", Value = "" } - }; + environment.sdafControlPlaneEnvironment = sdafControlPlaneEnvironment; + if (!environment.name.EndsWith("-" + sdafControlPlaneEnvironment)) + { + if (environment.name.StartsWith("SDAF-")) + { + environment.name = environment.name.Replace("SDAF-", ""); + variableGroups.Add(environment); + } + } - foreach (var value in values.EnumerateArray()) - { - string groupName = value.GetProperty("name").ToString(); - if (groupName.StartsWith("SDAF-")) - { - string text = value.GetProperty("name").ToString().Replace("SDAF-", ""); - variableGroups.Add(new SelectListItem - { - Text = text, - Value = text - }); + } + return variableGroups.ToArray(); } - } - return variableGroups; - } + // Get a list of all variable group names for use in a dropdown + public async Task> GetEnvironmentsList() + { + JsonElement values = await GetVariableGroupsJson(); - // Get a specific variable group from azure devops - public async Task GetVariableGroup(int id) - { - string getUri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups/{id}?api-version=6.0-preview.2"; + List variableGroups = new() + { + new SelectListItem { Text = "", Value = "" } + }; - using HttpResponseMessage response = client.GetAsync(getUri).Result; - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); + foreach (var value in values.EnumerateArray()) + { + string groupName = value.GetProperty("name").ToString(); + if (groupName.StartsWith("SDAF-")) + { + string text = value.GetProperty("name").ToString().Replace("SDAF-", ""); + variableGroups.Add(new SelectListItem + { + Text = text, + Value = text + }); - EnvironmentModel environment = JsonSerializer.Deserialize(responseBody); - environment.name = environment.name.Replace("SDAF-", ""); - return environment; - } + } + } - // Get a variable group id by name in ado - public async Task GetVariableGroupIdFromName(string name) - { - JsonElement values = await GetVariableGroupsJson(); + return variableGroups; + } - foreach (var value in values.EnumerateArray()) - { - if (value.GetProperty("name").ToString() == name) + // Get a specific variable group from azure devops + public async Task GetVariableGroup(int id) { - return value.GetProperty("id").ToString(); + string getUri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups/{id}?api-version=7.1"; + + using HttpResponseMessage response = client.GetAsync(getUri).Result; + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); + + EnvironmentModel environment = JsonSerializer.Deserialize(responseBody); + environment.name = environment.name.Replace("SDAF-", ""); + return environment; } - } - return null; - } - // Get a specific variables value from a variable group in ado - public async Task GetVariableFromVariableGroup(string id, string variableGroupName, string variableName) - { - try - { - if (id == null || id == "") + // Get a variable group id by name in ado + public async Task GetVariableGroupIdFromName(string name) { - id = await GetVariableGroupIdFromName(variableGroupName); - if (id == null) - { - throw new Exception(); - } - } - string getUri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups/{id}?api-version=6.0-preview.2"; + JsonElement values = await GetVariableGroupsJson(); - using HttpResponseMessage response = client.GetAsync(getUri).Result; - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); + foreach (var value in values.EnumerateArray()) + { + if (value.GetProperty("name").ToString() == name) + { + return value.GetProperty("id").ToString(); + } + } + return null; + } - JsonElement variables = JsonDocument.Parse(responseBody).RootElement.GetProperty("variables"); - string value = variables.GetProperty(variableName).GetProperty("value").GetString(); - if (value.EndsWith("/")) + // Get a specific variables value from a variable group in ado + public async Task GetVariableFromVariableGroup(string id, string variableGroupName, string variableName) { - value = value.Remove(value.Length - 1); + try + { + if (id == null || id == "") + { + id = await GetVariableGroupIdFromName(variableGroupName); + if (id == null) + { + throw new Exception(); + } + } + string getUri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups/{id}?api-version=7.1"; + + using HttpResponseMessage response = client.GetAsync(getUri).Result; + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); + + JsonElement variables = JsonDocument.Parse(responseBody).RootElement.GetProperty("variables"); + string value = variables.GetProperty(variableName).GetProperty("value").GetString(); + if (value.EndsWith('/')) + { + value = value.Remove(value.Length - 1); + } + return value; + } + catch + { + return "WORKSPACES"; + } } - return value; - } - catch - { - return "WORKSPACES"; - } - } - // Create a variable group in azure devops - public async Task CreateVariableGroup(EnvironmentModel environment, string newName, string description) - { - string postUri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups?api-version=6.0-preview.2"; + // Create a variable group in azure devops + public async Task CreateVariableGroup(EnvironmentModel environment, string newName, string description) + { + string postUri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups?api-version=7.1"; - string projectId = GetProjectId().Result; + string projectId = GetProjectId().Result; - newName = "SDAF-" + newName.Replace("SDAF-", ""); - environment.name = newName; - environment.variableGroupProjectReferences = new VariableGroupProjectReference[] - { + newName = "SDAF-" + newName.Replace("SDAF-", ""); + environment.name = newName; + environment.variableGroupProjectReferences = new VariableGroupProjectReference[] + { new VariableGroupProjectReference { name = newName, @@ -375,95 +381,93 @@ public async Task CreateVariableGroup(EnvironmentModel environment, string newNa name = project } } - }; + }; - string requestJson = JsonSerializer.Serialize(environment, typeof(EnvironmentModel), new JsonSerializerOptions() { IgnoreNullValues = true }); - StringContent content = new(requestJson, Encoding.ASCII, "application/json"); + string requestJson = JsonSerializer.Serialize(environment, typeof(EnvironmentModel), jsonSerializerOptions); + StringContent content = new(requestJson, Encoding.ASCII, "application/json"); - HttpResponseMessage response = await client.PostAsync(postUri, content); - string responseBody = await response.Content.ReadAsStringAsync(); - HandleResponse(response, responseBody); + HttpResponseMessage response = await client.PostAsync(postUri, content); + string responseBody = await response.Content.ReadAsStringAsync(); + HandleResponse(response, responseBody); - } + } - // Update a variable group in azure devops - public async Task UpdateVariableGroup(EnvironmentModel environment, string newName, string description) - { - string uri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups/{environment.id}?api-version=6.0-preview.2"; + // Update a variable group in azure devops + public async Task UpdateVariableGroup(EnvironmentModel environment, string newName, string description) + { + string uri = $"{collectionUri}{project}/_apis/distributedtask/variablegroups/{environment.id}?api-version=7.1"; - // Get the existing environment - using HttpResponseMessage getResponse = client.GetAsync(uri).Result; - string getResponseBody = await getResponse.Content.ReadAsStringAsync(); - HandleResponse(getResponse, getResponseBody); + // Get the existing environment + using HttpResponseMessage getResponse = client.GetAsync(uri).Result; + string getResponseBody = await getResponse.Content.ReadAsStringAsync(); + HandleResponse(getResponse, getResponseBody); - EnvironmentModel existingEnvironment = JsonSerializer.Deserialize(getResponseBody); + EnvironmentModel existingEnvironment = JsonSerializer.Deserialize(getResponseBody); - // Persist and update the project reference - environment.variableGroupProjectReferences = existingEnvironment.variableGroupProjectReferences; - if (environment.variableGroupProjectReferences != null && environment.variableGroupProjectReferences.Length > 0) - { - newName = "SDAF-" + newName.Replace("SDAF-", ""); - environment.variableGroupProjectReferences[0].name = newName; - environment.variableGroupProjectReferences[0].description = description; - } - else - { - throw new Exception("Existing environment project reference was empty"); - } - - // Persist any existing variables - string environmentJsonString = JsonConvert.SerializeObject(environment); - string variablesJsonString = JsonDocument.Parse(getResponseBody).RootElement.GetProperty("variables").ToString(); - dynamic dynamicEnvironment = JsonConvert.DeserializeObject(environmentJsonString); - dynamic dynamicVariables = JsonConvert.DeserializeObject(variablesJsonString); - - dynamicVariables.Agent = JToken.FromObject(environment.variables.Agent); - dynamicVariables.ARM_CLIENT_ID = JToken.FromObject(environment.variables.ARM_CLIENT_ID); - dynamicVariables.ARM_CLIENT_SECRET = JToken.FromObject(environment.variables.ARM_CLIENT_SECRET); - dynamicVariables.ARM_TENANT_ID = JToken.FromObject(environment.variables.ARM_TENANT_ID); - dynamicVariables.ARM_SUBSCRIPTION_ID = JToken.FromObject(environment.variables.ARM_SUBSCRIPTION_ID); - dynamicVariables.sap_fqdn = JToken.FromObject(environment.variables.sap_fqdn); - dynamicVariables.POOL = JToken.FromObject(environment.variables.POOL); - - dynamicEnvironment.variables = dynamicVariables; - - // Make the put call - string requestJson = JsonConvert.SerializeObject(dynamicEnvironment, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - StringContent content = new(requestJson, Encoding.ASCII, "application/json"); - - HttpResponseMessage putResponse = await client.PutAsync(uri, content); - string putResponseBody = await putResponse.Content.ReadAsStringAsync(); - HandleResponse(putResponse, putResponseBody); - } + // Persist and update the project reference + environment.variableGroupProjectReferences = existingEnvironment.variableGroupProjectReferences; + if (environment.variableGroupProjectReferences != null && environment.variableGroupProjectReferences.Length > 0) + { + newName = "SDAF-" + newName.Replace("SDAF-", ""); + environment.variableGroupProjectReferences[0].name = newName; + environment.variableGroupProjectReferences[0].description = description; + } + else + { + throw new Exception("Existing environment project reference was empty"); + } + + // Persist any existing variables + string environmentJsonString = JsonConvert.SerializeObject(environment); + string variablesJsonString = JsonDocument.Parse(getResponseBody).RootElement.GetProperty("variables").ToString(); + dynamic dynamicEnvironment = JsonConvert.DeserializeObject(environmentJsonString); + dynamic dynamicVariables = JsonConvert.DeserializeObject(variablesJsonString); + + dynamicVariables.Agent = JToken.FromObject(environment.variables.Agent); + dynamicVariables.ARM_CLIENT_ID = JToken.FromObject(environment.variables.ARM_CLIENT_ID); + dynamicVariables.ARM_CLIENT_SECRET = JToken.FromObject(environment.variables.ARM_CLIENT_SECRET); + dynamicVariables.ARM_TENANT_ID = JToken.FromObject(environment.variables.ARM_TENANT_ID); + dynamicVariables.ARM_SUBSCRIPTION_ID = JToken.FromObject(environment.variables.ARM_SUBSCRIPTION_ID); + dynamicVariables.sap_fqdn = JToken.FromObject(environment.variables.sap_fqdn); + dynamicVariables.POOL = JToken.FromObject(environment.variables.POOL); + + dynamicEnvironment.variables = dynamicVariables; + + // Make the put call + string requestJson = JsonConvert.SerializeObject(dynamicEnvironment, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + StringContent content = new(requestJson, Encoding.ASCII, "application/json"); + + HttpResponseMessage putResponse = await client.PutAsync(uri, content); + string putResponseBody = await putResponse.Content.ReadAsStringAsync(); + HandleResponse(putResponse, putResponseBody); + } - private void HandleResponse(HttpResponseMessage response, string responseBody) - { - if (!response.IsSuccessStatusCode) - { - string errorMessage; - switch (response.StatusCode) + static private void HandleResponse(HttpResponseMessage response, string responseBody) { - case System.Net.HttpStatusCode.Unauthorized: - errorMessage = "Unauthorized, please ensure that the MSI/Personal Access Token has sufficient permissions and that it has not expired."; - break; - case System.Net.HttpStatusCode.NotFound: - errorMessage = "Could not find the template."; - break; - default: - errorMessage = JsonDocument.Parse(responseBody).RootElement.GetProperty("message").ToString(); - break; - + if (!response.IsSuccessStatusCode) + { + string errorMessage; + switch (response.StatusCode) + { + case System.Net.HttpStatusCode.Unauthorized: + errorMessage = "Unauthorized, please ensure that the MSI/Personal Access Token has sufficient permissions and that it has not expired."; + break; + case System.Net.HttpStatusCode.NotFound: + errorMessage = "Could not find the template."; + break; + default: + errorMessage = JsonDocument.Parse(responseBody).RootElement.GetProperty("message").ToString(); + break; + } + throw new HttpRequestException(errorMessage); + } } - throw new HttpRequestException(errorMessage); - } - } - - public static List AppUserAgent { get; } = new() + public static List AppUserAgent { get; } = new() { new ProductInfoHeaderValue("SDAF") }; - } + } } #pragma warning restore SYSLIB0020 diff --git a/Webapp/SDAF/Controllers/SystemController.cs b/Webapp/SDAF/Controllers/SystemController.cs index 62680d2eeb..743ea393f0 100644 --- a/Webapp/SDAF/Controllers/SystemController.cs +++ b/Webapp/SDAF/Controllers/SystemController.cs @@ -1,5 +1,5 @@ -using AutomationForm.Models; -using AutomationForm.Services; +using SDAFWebApp.Models; +using SDAFWebApp.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Configuration; @@ -13,7 +13,7 @@ using System.Text; using System.Threading.Tasks; -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { public class SystemController : Controller { diff --git a/Webapp/SDAF/Controllers/ViewBagActionFilter.cs b/Webapp/SDAF/Controllers/ViewBagActionFilter.cs index 3537fc3e5a..1c6494f16e 100644 --- a/Webapp/SDAF/Controllers/ViewBagActionFilter.cs +++ b/Webapp/SDAF/Controllers/ViewBagActionFilter.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Configuration; -namespace AutomationForm.Controllers +namespace SDAFWebApp.Controllers { public class ViewBagActionFilter : ActionFilterAttribute { diff --git a/Webapp/SDAF/Models/AppFile.cs b/Webapp/SDAF/Models/AppFile.cs index 34fad3f45f..db5eb06a40 100644 --- a/Webapp/SDAF/Models/AppFile.cs +++ b/Webapp/SDAF/Models/AppFile.cs @@ -2,7 +2,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class AppFile { diff --git a/Webapp/SDAF/Models/AppFileEntity.cs b/Webapp/SDAF/Models/AppFileEntity.cs index d155f01071..415aa48693 100644 --- a/Webapp/SDAF/Models/AppFileEntity.cs +++ b/Webapp/SDAF/Models/AppFileEntity.cs @@ -2,7 +2,7 @@ using Azure.Data.Tables; using System; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class AppFileEntity : ITableEntity { diff --git a/Webapp/SDAF/Models/CustomValidators.cs b/Webapp/SDAF/Models/CustomValidators.cs index 342d0bf4c3..4ee9fb0d14 100644 --- a/Webapp/SDAF/Models/CustomValidators.cs +++ b/Webapp/SDAF/Models/CustomValidators.cs @@ -1,4 +1,4 @@ -using AutomationForm.Controllers; +using SDAFWebApp.Controllers; using Azure.ResourceManager.Resources; using Microsoft.Extensions.FileSystemGlobbing.Internal; using System; @@ -6,7 +6,7 @@ using System.Linq; using System.Text.RegularExpressions; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class CustomValidators { diff --git a/Webapp/SDAF/Models/DatabaseSettings.cs b/Webapp/SDAF/Models/DatabaseSettings.cs index 5aac91d3a9..f53a52dd9e 100644 --- a/Webapp/SDAF/Models/DatabaseSettings.cs +++ b/Webapp/SDAF/Models/DatabaseSettings.cs @@ -1,4 +1,4 @@ -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class DatabaseSettings : IDatabaseSettings { diff --git a/Webapp/SDAF/Models/EnvironmentModel.cs b/Webapp/SDAF/Models/EnvironmentModel.cs index 2fd83a75ed..b02e1d3128 100644 --- a/Webapp/SDAF/Models/EnvironmentModel.cs +++ b/Webapp/SDAF/Models/EnvironmentModel.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class EnvironmentModel diff --git a/Webapp/SDAF/Models/ErrorViewModel.cs b/Webapp/SDAF/Models/ErrorViewModel.cs index ccaf30b522..5e50daf188 100644 --- a/Webapp/SDAF/Models/ErrorViewModel.cs +++ b/Webapp/SDAF/Models/ErrorViewModel.cs @@ -1,4 +1,4 @@ -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class ErrorViewModel { diff --git a/Webapp/SDAF/Models/FileUploadModel.cs b/Webapp/SDAF/Models/FileUploadModel.cs index f1ec9682f7..512bfc4a95 100644 --- a/Webapp/SDAF/Models/FileUploadModel.cs +++ b/Webapp/SDAF/Models/FileUploadModel.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class FileUploadModel { diff --git a/Webapp/SDAF/Models/FormViewModel.cs b/Webapp/SDAF/Models/FormViewModel.cs index f87787f36d..11e895d1dd 100644 --- a/Webapp/SDAF/Models/FormViewModel.cs +++ b/Webapp/SDAF/Models/FormViewModel.cs @@ -1,4 +1,4 @@ -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class FormViewModel { diff --git a/Webapp/SDAF/Models/GitRequestBody.cs b/Webapp/SDAF/Models/GitRequestBody.cs index 5ea397b2a9..a5bb6fcc46 100644 --- a/Webapp/SDAF/Models/GitRequestBody.cs +++ b/Webapp/SDAF/Models/GitRequestBody.cs @@ -1,4 +1,4 @@ -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class GitRequestBody diff --git a/Webapp/SDAF/Models/GroupingModel.cs b/Webapp/SDAF/Models/GroupingModel.cs index 0c02603186..31e705996b 100644 --- a/Webapp/SDAF/Models/GroupingModel.cs +++ b/Webapp/SDAF/Models/GroupingModel.cs @@ -1,4 +1,4 @@ -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class Grouping { diff --git a/Webapp/SDAF/Models/ImageDropdown.cs b/Webapp/SDAF/Models/ImageDropdown.cs index 92bd75726e..0e23feaa9e 100644 --- a/Webapp/SDAF/Models/ImageDropdown.cs +++ b/Webapp/SDAF/Models/ImageDropdown.cs @@ -1,4 +1,4 @@ -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class ImageDropdown { diff --git a/Webapp/SDAF/Models/LandscapeEntity.cs b/Webapp/SDAF/Models/LandscapeEntity.cs index 93451b1431..8301227384 100644 --- a/Webapp/SDAF/Models/LandscapeEntity.cs +++ b/Webapp/SDAF/Models/LandscapeEntity.cs @@ -3,29 +3,29 @@ using System; using System.Text.Json; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { - public class LandscapeEntity : ITableEntity - { - public LandscapeEntity() { } - public LandscapeEntity(LandscapeModel landscape) + public class LandscapeEntity : ITableEntity { - RowKey = landscape.Id; - PartitionKey = landscape.environment; - IsDefault = landscape.IsDefault; - Landscape = JsonSerializer.Serialize(landscape, new JsonSerializerOptions() { }); - } + public LandscapeEntity() { } + public LandscapeEntity(LandscapeModel landscape) + { + RowKey = landscape.Id; + PartitionKey = landscape.environment; + IsDefault = landscape.IsDefault; + Landscape = JsonSerializer.Serialize(landscape, new JsonSerializerOptions() { }); + } - public string RowKey { get; set; } = default!; + public string RowKey { get; set; } = default!; - public string PartitionKey { get; set; } = default!; + public string PartitionKey { get; set; } = default!; - public ETag ETag { get; set; } = default!; + public ETag ETag { get; set; } = default!; - public DateTimeOffset? Timestamp { get; set; } = default!; + public DateTimeOffset? Timestamp { get; set; } = default!; - public string Landscape { get; set; } + public string Landscape { get; set; } - public bool IsDefault { get; set; } = false; - } + public bool IsDefault { get; set; } = false; + } } diff --git a/Webapp/SDAF/Models/LandscapeModel.cs b/Webapp/SDAF/Models/LandscapeModel.cs index d87e335508..8b0f2bb05b 100644 --- a/Webapp/SDAF/Models/LandscapeModel.cs +++ b/Webapp/SDAF/Models/LandscapeModel.cs @@ -1,8 +1,8 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using static AutomationForm.Models.CustomValidators; +using static SDAFWebApp.Models.CustomValidators; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class LandscapeModel { @@ -76,6 +76,10 @@ public bool IsValid() [NetworkAddressValidator(ErrorMessage = "Invalid network address arm id")] public string network_arm_id { get; set; } + public int? network_flow_timeout_in_minutes { get; set; } + + public bool? network_enable_route_propagation { get; set; } + //[SubnetRequired(subnetType: "admin")] [AddressPrefixValidator(ErrorMessage = "Admin subnet address space must be a valid RFC 1918 address")] public string admin_subnet_address_prefix { get; set; } diff --git a/Webapp/SDAF/Models/ParameterModel.cs b/Webapp/SDAF/Models/ParameterModel.cs index 90786daedc..15f6ed07d1 100644 --- a/Webapp/SDAF/Models/ParameterModel.cs +++ b/Webapp/SDAF/Models/ParameterModel.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc.Rendering; using System.Collections.Generic; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class ParameterModel { diff --git a/Webapp/SDAF/Models/PipelineRequestBody.cs b/Webapp/SDAF/Models/PipelineRequestBody.cs index 895904e706..c87c25a52a 100644 --- a/Webapp/SDAF/Models/PipelineRequestBody.cs +++ b/Webapp/SDAF/Models/PipelineRequestBody.cs @@ -1,4 +1,4 @@ -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class PipelineRequestBody diff --git a/Webapp/SDAF/Models/SapObjectIndexModel.cs b/Webapp/SDAF/Models/SapObjectIndexModel.cs index b355a7f29a..cb06de2472 100644 --- a/Webapp/SDAF/Models/SapObjectIndexModel.cs +++ b/Webapp/SDAF/Models/SapObjectIndexModel.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class SapObjectIndexModel { diff --git a/Webapp/SDAF/Models/SystemEntity.cs b/Webapp/SDAF/Models/SystemEntity.cs index e671b491b7..913edb0bd1 100644 --- a/Webapp/SDAF/Models/SystemEntity.cs +++ b/Webapp/SDAF/Models/SystemEntity.cs @@ -3,7 +3,7 @@ using System; using System.Text.Json; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class SystemEntity : ITableEntity { diff --git a/Webapp/SDAF/Models/SystemModel.cs b/Webapp/SDAF/Models/SystemModel.cs index 37fd26c4de..bcf51928a6 100644 --- a/Webapp/SDAF/Models/SystemModel.cs +++ b/Webapp/SDAF/Models/SystemModel.cs @@ -1,8 +1,8 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using static AutomationForm.Models.CustomValidators; +using static SDAFWebApp.Models.CustomValidators; -namespace AutomationForm.Models +namespace SDAFWebApp.Models { public class SystemModel { @@ -328,12 +328,14 @@ public bool IsValid() [IpAddressValidator] public string[] database_vm_storage_nic_ips { get; set; } + public bool? database_active_active { get; set; } + /*---------------------------------------------------------------------------8 | | | App Tier information | | | +------------------------------------4--------------------------------------*/ - // Application Tier + // Application Tier public bool? enable_app_tier_deployment { get; set; } = true; diff --git a/Webapp/SDAF/ParameterDetails/LandscapeDetails.json b/Webapp/SDAF/ParameterDetails/LandscapeDetails.json index d88c961541..d00e582c0c 100644 --- a/Webapp/SDAF/ParameterDetails/LandscapeDetails.json +++ b/Webapp/SDAF/ParameterDetails/LandscapeDetails.json @@ -18,7 +18,7 @@ "Link": "https://learn.microsoft.com/en-us/azure/sap/automation/automation-configure-workload-zone", "Parameters": [ { - "Name": "subscription", + "Name": "subscription_id", "Required": false, "Description": "IMPORTANT: please provide a subscription id to enable dropdown functionality for various arm id parameters, such as resourcegroup_arm_id, network_arm_id, etc.", "Type": "lookup", @@ -145,15 +145,6 @@ "Overrules": "", "Display": 2 }, - { - "Name": "use_spn", - "Required": false, - "Description": "If set, the deployment is performed using the Service Principal defined for the workload zone, otherwise the managed identity of the deployer is used", - "Type": "checkbox", - "Options": [], - "Overrules": "", - "Display": 2 - }, { "Name": "shared_access_key_enabled", "Required": false, @@ -319,6 +310,25 @@ "Overrules": "network_address_space", "Display": 3 }, + { + "Name": "network_flow_timeout_in_minutes", + "Required": false, + "Description": "The flow timeout in minutes of the virtual network", + "Type": "field", + "Options": [], + "Overrules": "", + "Display": 3 + }, + { + "Name": "network_enable_route_propagation", + "Required": false, + "Description": "Enable network route table propagation.", + "Type": "checkbox", + "Options": [], + "Overrules": "", + "Display": 3 + }, + { "Name": "use_private_endpoint", "Required": false, diff --git a/Webapp/SDAF/ParameterDetails/LandscapeTemplate.txt b/Webapp/SDAF/ParameterDetails/LandscapeTemplate.txt index 172bd1b026..86a8116f23 100644 --- a/Webapp/SDAF/ParameterDetails/LandscapeTemplate.txt +++ b/Webapp/SDAF/ParameterDetails/LandscapeTemplate.txt @@ -33,9 +33,12 @@ $$location$$ # Description of the Workload zone. $$Description$$ -#If you want to provide a custom naming json use the following parameter. +# If you want to provide a custom naming json use the following parameter. $$name_override_file$$ +# The subscription ID is used to control where the resources are deployed +$$subscription_id$$ + ######################################################################################### # # # Networking # @@ -75,7 +78,7 @@ $$use_private_endpoint$$ # use_service_endpoint is a boolean flag controlling if the key vaults and storage accounts have service endpoints $$use_service_endpoint$$ -#Defines if the SAP VNet will be peered with the control plane VNet +# Defines if the SAP VNet will be peered with the control plane VNet $$peer_with_control_plane_vnet$$ # Defines if access to the key vaults and storage accounts is restricted to the SAP and deployer VNets @@ -87,6 +90,12 @@ $$public_network_access_enabled$$ # place_delete_lock_on_resources, If defined, a delete lock will be placed on the key resources $$place_delete_lock_on_resources$$ +# The flow timeout in minutes of the virtual network +$$network_flow_timeout_in_minutes$$ + +# Enable network route table propagation. +$$network_enable_route_propagation$$ + ######################################################################################### # # # Admin Subnet variables # @@ -204,7 +213,6 @@ $$anf_subnet_nsg_arm_id$$ # # ########################################################################### -/* iscsi subnet information */ # If defined these parameters control the subnet name and the subnet prefix # iscsi_subnet_name is an optional parameter and should only be used if the default naming is not acceptable $$iscsi_subnet_name$$ @@ -227,7 +235,6 @@ $$iscsi_subnet_nsg_name$$ # # ########################################################################### -/* ams subnet information */ # If defined these parameters control the subnet name and the subnet prefix # ams_subnet_name is an optional parameter and should only be used if the default naming is not acceptable $$ams_subnet_name$$ @@ -251,7 +258,6 @@ $$ams_subnet_nsg_name$$ # # ########################################################################### -/* storage subnet information */ # If defined these parameters control the subnet name and the subnet prefix # storage_subnet_name is an optional parameter and should only be used if the default naming is not acceptable $$storage_subnet_name$$ @@ -268,7 +274,6 @@ $$storage_subnet_nsg_arm_id$$ # storage_subnet_nsg_name is an optional parameter and should only be used if the default naming is not acceptable for the network security group name $$storage_subnet_nsg_name$$ - ######################################################################################### # # # Common Virtual Machine settings # @@ -451,7 +456,7 @@ $$install_create_smb_shares$$ # If defined provides the DNS label for the Virtual Network $$dns_label$$ -#If defined provides the lsit of DNS servers to attach to the Virtual NEtwork +# If defined provides the list of DNS servers to attach to the Virtual NEtwork $$dns_server_list$$ ######################################################################################### @@ -478,22 +483,22 @@ $$use_AFS_for_shared_storage$$ # ANF_account_name is the name for the Netapp Account $$ANF_account_name$$ -#ANF_service_level is the service level for the NetApp pool +# ANF_service_level is the service level for the NetApp pool $$ANF_service_level$$ -#ANF_pool_name is the ANF pool name +# ANF_pool_name is the ANF pool name $$ANF_pool_name$$ -#ANF_pool_size is the pool size in TB for the NetApp pool +# ANF_pool_size is the pool size in TB for the NetApp pool $$ANF_pool_size$$ -#ANF_qos_type defines the Quality of Service type of the pool (Auto or Manual) +# ANF_qos_type defines the Quality of Service type of the pool (Auto or Manual) $$ANF_qos_type$$ # ANF_account_arm_id is the Azure resource identifier for an existing Netapp Account $$ANF_account_arm_id$$ -#ANF_use_existing_pool defines if an existing pool is used +# ANF_use_existing_pool defines if an existing pool is used $$ANF_use_existing_pool$$ ######################################################################################### @@ -523,16 +528,16 @@ $$ANF_transport_volume_zone$$ # # ######################################################################################### -#ANF_install_volume_use_existing defines if an existing volume is used for install +# ANF_install_volume_use_existing defines if an existing volume is used for install $$ANF_install_volume_use_existing$$ -#ANF_install_volume_name is the name of the install volume +# ANF_install_volume_name is the name of the install volume $$ANF_install_volume_name$$ -#ANF_install_volume_throughput is the throughput for the install volume +# ANF_install_volume_throughput is the throughput for the install volume $$ANF_install_volume_throughput$$ -#ANF_install_volume_size is the size for the install volume +# ANF_install_volume_size is the size for the install volume $$ANF_install_volume_size$$ # ANF_install_volume_zone is the zone for the transport volume @@ -583,9 +588,6 @@ $$tfstate_resource_id$$ # deployer_tfstate_key is the state file name for the deployer $$deployer_tfstate_key$$ -# use_spn defines if the deployments are performed using Service Principals or the deployer's managed identiry, true=SPN, false=MSI -$$use_spn$$ - ######################################################################################### # # diff --git a/Webapp/SDAF/ParameterDetails/SystemDetails.json b/Webapp/SDAF/ParameterDetails/SystemDetails.json index 11867db5fd..181797cf42 100644 --- a/Webapp/SDAF/ParameterDetails/SystemDetails.json +++ b/Webapp/SDAF/ParameterDetails/SystemDetails.json @@ -18,7 +18,7 @@ "Link": "https://learn.microsoft.com/en-us/azure/virtual-machines/workloads/sap/automation-configure-system?branch=main", "Parameters": [ { - "Name": "subscription", + "Name": "subscription_id", "Required": false, "Description": "IMPORTANT: please provide a subscription id to enable dropdown functionality for various Azure resource ID parameters, such as resourcegroup_arm_id, network_arm_id, etc.", "Type": "lookup", @@ -195,15 +195,6 @@ "Overrules": "", "Display": 2 }, - { - "Name": "use_spn", - "Required": false, - "Description": " If set, the deployment is performed using the Service Principal defined for the workload zone, otherwise the managed identity of the deployer is used", - "Type": "checkbox", - "Options": [], - "Overrules": "", - "Display": 2 - }, { "Name": "prevent_deletion_if_contains_resources", "Required": false, @@ -735,6 +726,15 @@ "Options": [], "Overrules": "", "Display": 2 + }, + { + "Name": "database_active_active", + "Required": false, + "Description": "If true, database will deployed with Active/Active (read enabled) configuration, only supported for HANA.", + "Type": "checkbox", + "Options": [], + "Overrules": "", + "Display": 3 } ] }, diff --git a/Webapp/SDAF/ParameterDetails/SystemTemplate.txt b/Webapp/SDAF/ParameterDetails/SystemTemplate.txt index 9ff4392530..f4f6a56edb 100644 --- a/Webapp/SDAF/ParameterDetails/SystemTemplate.txt +++ b/Webapp/SDAF/ParameterDetails/SystemTemplate.txt @@ -36,6 +36,10 @@ $$environment$$ # The location value is a mandatory field, it is used to control where the resources are deployed $$location$$ + +# The subscription ID is used to control where the resources are deployed +$$subscription_id$$ + # The sid value is a mandatory field that defines the SAP Application SID $$sid$$ @@ -62,10 +66,10 @@ $$Description$$ ######################################################################################### -#If you want to provide a custom naming json use the following parameter. +# If you want to provide a custom naming json use the following parameter. $$name_override_file$$ -#If you want to customize the disk sizes for VMs use the following parameter to specify the custom sizing file. +# If you want to customize the disk sizes for VMs use the following parameter to specify the custom sizing file. $$custom_disk_sizes_filename$$ # use_secondary_ips controls if the virtual machines should be deployed with two IP addresses. Required for SAP Virtual Hostname support @@ -192,6 +196,9 @@ $$database_use_avset$$ # Optional, Defines if the tags for the database virtual machines $$database_tags$$ +# If true, database will deployed with Active/Active (read enabled) configuration, only supported for HANA +$$database_active_active$$ + ######################################################################################### # # # Application tier # # @@ -294,7 +301,7 @@ $$application_server_nic_secondary_ips$$ # for the network interface cards connected to the admin subnet $$application_server_admin_nic_ips$$ -#If you want to customize the disk sizes for application tier use the following parameter. +# If you want to customize the disk sizes for application tier use the following parameter. $$app_disk_sizes_filename$$ # Optional, Defines the default authentication model for the Applicatiuon tier VMs (key/password) @@ -354,7 +361,7 @@ $$webdispatcher_server_sku$$ # webdispatcher_server_use_ppg defines the that the Web dispatcher virtual machines will be placed in a proximity placement group $$webdispatcher_server_use_ppg$$ -#webdispatcher_server_use_avset defines the that the Web dispatcher virtual machines will be placed in an availability set +# webdispatcher_server_use_avset defines the that the Web dispatcher virtual machines will be placed in an availability set $$webdispatcher_server_use_avset$$ # webdispatcher_server_tags, if defined provides the tags to be associated to the web dispatchers @@ -404,25 +411,25 @@ $$patch_assessment_mode$$ # scs_cluster_type defines cluster quorum type; AFA (Azure Fencing Agent), ASD (Azure Shared Disk), ISCSI $$scs_cluster_type$$ -#scs_cluster_disk_lun defines the LUN number for the SAP Central Services cluster disk +# scs_cluster_disk_lun defines the LUN number for the SAP Central Services cluster disk $$scs_cluster_disk_lun$$ -#scs_cluster_disk_size defines the size for the SAP Central Services cluster disk +# scs_cluster_disk_size defines the size for the SAP Central Services cluster disk $$scs_cluster_disk_size$$ -#scs_cluster_disk_type defines the storage_account_type of the shared disk for the SAP Central Services cluster +# scs_cluster_disk_type defines the storage_account_type of the shared disk for the SAP Central Services cluster $$scs_cluster_disk_type$$ # database_cluster_type defines cluster quorum type; AFA (Azure Fencing Agent), ASD (Azure Shared Disk), ISCSI $$database_cluster_type$$ -#database_cluster_disk_lun defines the LUN number for the database cluster disk +# database_cluster_disk_lun defines the LUN number for the database cluster disk $$database_cluster_disk_lun$$ -#database_cluster_disk_size defines the size for the database cluster disk +# database_cluster_disk_size defines the size for the database cluster disk $$database_cluster_disk_size$$ -#database_cluster_disk_type defines the storage_account_type of the shared disk for the Database cluster +# database_cluster_disk_type defines the storage_account_type of the shared disk for the Database cluster $$database_cluster_disk_type$$ # use_msi_for_clusters if defined will use managed service identity for the Pacemaker cluster fencing @@ -864,7 +871,7 @@ $$deployer_tfstate_key$$ $$landscape_tfstate_key$$ # use_spn defines if the deployments are performed using Service Principals or the deployer's managed identiry, true=SPN, false=MSI -$$use_spn$$ +$$ use_spn$$ ######################################################################################### # # @@ -895,10 +902,10 @@ $$tags$$ # # ######################################################################################### -#If true, the database tier will be configured for scale out scenario +# If true, the database tier will be configured for scale out scenario $$database_HANA_use_scaleout_scenario$$ -#If true, the database scale out tier will not have a standby role +# If true, the database scale out tier will not have a standby role $$database_HANA_no_standby_role$$ # Defined the standby node count in a scale out scenario diff --git a/Webapp/SDAF/Program.cs b/Webapp/SDAF/Program.cs index d29bb9172a..aa218f7ca2 100644 --- a/Webapp/SDAF/Program.cs +++ b/Webapp/SDAF/Program.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; -namespace AutomationForm +namespace SDAFWebApp { public class Program { diff --git a/Webapp/SDAF/Properties/launchSettings.json b/Webapp/SDAF/Properties/launchSettings.json index 54b53366aa..40d12efaca 100644 --- a/Webapp/SDAF/Properties/launchSettings.json +++ b/Webapp/SDAF/Properties/launchSettings.json @@ -15,7 +15,7 @@ "ASPNETCORE_ENVIRONMENT": "Development" } }, - "AutomationForm": { + "SDAFWebApp": { "commandName": "Project", "launchBrowser": true, "applicationUrl": "https://localhost:5001;http://localhost:5000", diff --git a/Webapp/SDAF/SDAFWebApp.csproj b/Webapp/SDAF/SDAFWebApp.csproj index 331fcadd00..fb131303d5 100644 --- a/Webapp/SDAF/SDAFWebApp.csproj +++ b/Webapp/SDAF/SDAFWebApp.csproj @@ -18,21 +18,21 @@ - + - - - - - - - + + + + + + + - - + + diff --git a/Webapp/SDAF/SDAFWebApp.csproj.user b/Webapp/SDAF/SDAFWebApp.csproj.user index 07ef4d7307..f0714b0db4 100644 --- a/Webapp/SDAF/SDAFWebApp.csproj.user +++ b/Webapp/SDAF/SDAFWebApp.csproj.user @@ -11,6 +11,6 @@ True False True - cpln-noeu-sapdeployment597 - Web Deploy1 + C:\Work\Repos\kimforss-sap-automation\Webapp\SDAF\Properties\PublishProfiles\cpln-noeu-sapdeployment748 - Web Deploy.pubxml \ No newline at end of file diff --git a/Webapp/SDAF/Services/AppFileService.cs b/Webapp/SDAF/Services/AppFileService.cs index f2535dbe86..44890782b2 100644 --- a/Webapp/SDAF/Services/AppFileService.cs +++ b/Webapp/SDAF/Services/AppFileService.cs @@ -1,4 +1,4 @@ -using AutomationForm.Models; +using SDAFWebApp.Models; using Azure.Data.Tables; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; @@ -7,7 +7,7 @@ using System.IO; using System.Threading.Tasks; -namespace AutomationForm.Services +namespace SDAFWebApp.Services { public class AppFileService : ITableStorageService { diff --git a/Webapp/SDAF/Services/ITableStorageService.cs b/Webapp/SDAF/Services/ITableStorageService.cs index ad2cead8e9..416ecc68ad 100644 --- a/Webapp/SDAF/Services/ITableStorageService.cs +++ b/Webapp/SDAF/Services/ITableStorageService.cs @@ -1,8 +1,8 @@ -using AutomationForm.Models; +using SDAFWebApp.Models; using System.Collections.Generic; using System.Threading.Tasks; -namespace AutomationForm.Services +namespace SDAFWebApp.Services { public interface ITableStorageService { diff --git a/Webapp/SDAF/Services/LandscapeService.cs b/Webapp/SDAF/Services/LandscapeService.cs index 0298358381..e0c0d4dcd6 100644 --- a/Webapp/SDAF/Services/LandscapeService.cs +++ b/Webapp/SDAF/Services/LandscapeService.cs @@ -1,4 +1,4 @@ -using AutomationForm.Models; +using SDAFWebApp.Models; using Azure; using Azure.Data.Tables; using Azure.Storage.Blobs; @@ -7,9 +7,9 @@ using System.Linq; using System.Threading.Tasks; -namespace AutomationForm.Services +namespace SDAFWebApp.Services { - public class LandscapeService : ITableStorageService + public class LandscapeService : ITableStorageService { private readonly TableClient client; private readonly BlobContainerClient tfvarsBlobContainerClient; diff --git a/Webapp/SDAF/Services/SystemService.cs b/Webapp/SDAF/Services/SystemService.cs index 24fbc1df76..0469e17f2b 100644 --- a/Webapp/SDAF/Services/SystemService.cs +++ b/Webapp/SDAF/Services/SystemService.cs @@ -1,4 +1,4 @@ -using AutomationForm.Models; +using SDAFWebApp.Models; using Azure; using Azure.Data.Tables; using Azure.Storage.Blobs; @@ -7,7 +7,7 @@ using System.Linq; using System.Threading.Tasks; -namespace AutomationForm.Services +namespace SDAFWebApp.Services { public class SystemService : ITableStorageService { diff --git a/Webapp/SDAF/Services/TableStorageService.cs b/Webapp/SDAF/Services/TableStorageService.cs index 869c655fad..7da7d182fe 100644 --- a/Webapp/SDAF/Services/TableStorageService.cs +++ b/Webapp/SDAF/Services/TableStorageService.cs @@ -1,4 +1,4 @@ -using AutomationForm.Models; +using SDAFWebApp.Models; using Azure.Data.Tables; using Azure.Identity; using Azure.Storage.Blobs; @@ -7,7 +7,7 @@ using System; using System.Threading.Tasks; -namespace AutomationForm.Services +namespace SDAFWebApp.Services { public class TableStorageService { diff --git a/Webapp/SDAF/Startup.cs b/Webapp/SDAF/Startup.cs index 9f5c75c709..e19051f59a 100644 --- a/Webapp/SDAF/Startup.cs +++ b/Webapp/SDAF/Startup.cs @@ -1,5 +1,3 @@ -using AutomationForm.Models; -using AutomationForm.Services; using Azure.Identity; using Azure.ResourceManager; using Microsoft.AspNetCore.Builder; @@ -9,11 +7,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; +using SDAFWebApp.Models; +using SDAFWebApp.Services; using System; -namespace AutomationForm +namespace SDAFWebApp { - public class Startup + public class Startup { public IConfiguration Configuration { get; } diff --git a/Webapp/SDAF/Views/File/Create.cshtml b/Webapp/SDAF/Views/File/Create.cshtml index 4df99193f3..a62e3d70fc 100644 --- a/Webapp/SDAF/Views/File/Create.cshtml +++ b/Webapp/SDAF/Views/File/Create.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.AppFile +@model SDAFWebApp.Models.AppFile @{ ViewBag.Title = "Create file"; diff --git a/Webapp/SDAF/Views/File/Delete.cshtml b/Webapp/SDAF/Views/File/Delete.cshtml index ac24eac17a..0b2dd32168 100644 --- a/Webapp/SDAF/Views/File/Delete.cshtml +++ b/Webapp/SDAF/Views/File/Delete.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.AppFile +@model SDAFWebApp.Models.AppFile @{ ViewBag.Title = "Delete file"; diff --git a/Webapp/SDAF/Views/File/Details.cshtml b/Webapp/SDAF/Views/File/Details.cshtml index bb6f358a00..6b0e07c164 100644 --- a/Webapp/SDAF/Views/File/Details.cshtml +++ b/Webapp/SDAF/Views/File/Details.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.AppFile +@model SDAFWebApp.Models.AppFile @{ ViewBag.Title = "File details"; diff --git a/Webapp/SDAF/Views/File/Edit.cshtml b/Webapp/SDAF/Views/File/Edit.cshtml index ebf395fed8..630fdaf14f 100644 --- a/Webapp/SDAF/Views/File/Edit.cshtml +++ b/Webapp/SDAF/Views/File/Edit.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.AppFile +@model SDAFWebApp.Models.AppFile @{ ViewBag.Title = "Edit file"; diff --git a/Webapp/SDAF/Views/File/Index.cshtml b/Webapp/SDAF/Views/File/Index.cshtml index 4b6cac68b8..b2d430645f 100644 --- a/Webapp/SDAF/Views/File/Index.cshtml +++ b/Webapp/SDAF/Views/File/Index.cshtml @@ -1,4 +1,4 @@ -@model IEnumerable +@model IEnumerable @{ ViewBag.Title = "Files"; diff --git a/Webapp/SDAF/Views/File/Upload.cshtml b/Webapp/SDAF/Views/File/Upload.cshtml index d843ee7678..447334393c 100644 --- a/Webapp/SDAF/Views/File/Upload.cshtml +++ b/Webapp/SDAF/Views/File/Upload.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FileUploadModel +@model SDAFWebApp.Models.FileUploadModel @{ ViewBag.Title = "Upload files"; diff --git a/Webapp/SDAF/Views/Landscape/Create.cshtml b/Webapp/SDAF/Views/Landscape/Create.cshtml index e5001ae67c..2f39997dc6 100644 --- a/Webapp/SDAF/Views/Landscape/Create.cshtml +++ b/Webapp/SDAF/Views/Landscape/Create.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel; +@model SDAFWebApp.Models.FormViewModel; @using System.Text.Json @{ diff --git a/Webapp/SDAF/Views/Landscape/Delete.cshtml b/Webapp/SDAF/Views/Landscape/Delete.cshtml index dfbe81981a..756742cc4b 100644 --- a/Webapp/SDAF/Views/Landscape/Delete.cshtml +++ b/Webapp/SDAF/Views/Landscape/Delete.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel +@model SDAFWebApp.Models.FormViewModel @{ ViewBag.Title = "Delete workload zone"; diff --git a/Webapp/SDAF/Views/Landscape/Deploy.cshtml b/Webapp/SDAF/Views/Landscape/Deploy.cshtml index 7f59e2988b..ce45041320 100644 --- a/Webapp/SDAF/Views/Landscape/Deploy.cshtml +++ b/Webapp/SDAF/Views/Landscape/Deploy.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel +@model SDAFWebApp.Models.FormViewModel @{ ViewBag.Title = "Deploy workload zone"; diff --git a/Webapp/SDAF/Views/Landscape/Details.cshtml b/Webapp/SDAF/Views/Landscape/Details.cshtml index e55be96bc8..aec3d4605b 100644 --- a/Webapp/SDAF/Views/Landscape/Details.cshtml +++ b/Webapp/SDAF/Views/Landscape/Details.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel +@model SDAFWebApp.Models.FormViewModel @{ ViewBag.Title = "Workload zone details"; diff --git a/Webapp/SDAF/Views/Landscape/Edit.cshtml b/Webapp/SDAF/Views/Landscape/Edit.cshtml index c87ccaf96c..8efd62c878 100644 --- a/Webapp/SDAF/Views/Landscape/Edit.cshtml +++ b/Webapp/SDAF/Views/Landscape/Edit.cshtml @@ -1,5 +1,5 @@ -@model AutomationForm.Models.FormViewModel; -@using AutomationForm.Models +@model SDAFWebApp.Models.FormViewModel; +@using SDAFWebApp.Models @using System.Text.Json @{ diff --git a/Webapp/SDAF/Views/Landscape/Index.cshtml b/Webapp/SDAF/Views/Landscape/Index.cshtml index 4d3877d847..1e28ac8f0b 100644 --- a/Webapp/SDAF/Views/Landscape/Index.cshtml +++ b/Webapp/SDAF/Views/Landscape/Index.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.SapObjectIndexModel +@model SDAFWebApp.Models.SapObjectIndexModel @{ ViewBag.Title = "Workload zones"; diff --git a/Webapp/SDAF/Views/System/Create.cshtml b/Webapp/SDAF/Views/System/Create.cshtml index 21622ece63..504cc5003f 100644 --- a/Webapp/SDAF/Views/System/Create.cshtml +++ b/Webapp/SDAF/Views/System/Create.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel; +@model SDAFWebApp.Models.FormViewModel; @using System.Text.Json @{ diff --git a/Webapp/SDAF/Views/System/Delete.cshtml b/Webapp/SDAF/Views/System/Delete.cshtml index 290491a3f1..2f7ba0a479 100644 --- a/Webapp/SDAF/Views/System/Delete.cshtml +++ b/Webapp/SDAF/Views/System/Delete.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel +@model SDAFWebApp.Models.FormViewModel @{ ViewBag.Title = "Delete system"; diff --git a/Webapp/SDAF/Views/System/Deploy.cshtml b/Webapp/SDAF/Views/System/Deploy.cshtml index a5c2fb1cd2..ac18ed2c49 100644 --- a/Webapp/SDAF/Views/System/Deploy.cshtml +++ b/Webapp/SDAF/Views/System/Deploy.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel +@model SDAFWebApp.Models.FormViewModel @{ ViewBag.Title = "Deploy system"; diff --git a/Webapp/SDAF/Views/System/Details.cshtml b/Webapp/SDAF/Views/System/Details.cshtml index 897b8bb905..66c089c23f 100644 --- a/Webapp/SDAF/Views/System/Details.cshtml +++ b/Webapp/SDAF/Views/System/Details.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel +@model SDAFWebApp.Models.FormViewModel @{ ViewBag.Title = "System details"; diff --git a/Webapp/SDAF/Views/System/Edit.cshtml b/Webapp/SDAF/Views/System/Edit.cshtml index ead787440c..5ba55f9229 100644 --- a/Webapp/SDAF/Views/System/Edit.cshtml +++ b/Webapp/SDAF/Views/System/Edit.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel; +@model SDAFWebApp.Models.FormViewModel; @using System.Text.Json @{ diff --git a/Webapp/SDAF/Views/System/Index.cshtml b/Webapp/SDAF/Views/System/Index.cshtml index 8465aacf78..e130b2ae06 100644 --- a/Webapp/SDAF/Views/System/Index.cshtml +++ b/Webapp/SDAF/Views/System/Index.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.SapObjectIndexModel +@model SDAFWebApp.Models.SapObjectIndexModel @{ ViewBag.Title = "Systems"; diff --git a/Webapp/SDAF/Views/System/Install.cshtml b/Webapp/SDAF/Views/System/Install.cshtml index 57720a6260..ba54c562d6 100644 --- a/Webapp/SDAF/Views/System/Install.cshtml +++ b/Webapp/SDAF/Views/System/Install.cshtml @@ -1,4 +1,4 @@ -@model AutomationForm.Models.FormViewModel +@model SDAFWebApp.Models.FormViewModel @{ ViewBag.Title = "Install SAP"; diff --git a/Webapp/SDAF/Views/_ViewImports.cshtml b/Webapp/SDAF/Views/_ViewImports.cshtml index 68ed587322..f72bd7b557 100644 --- a/Webapp/SDAF/Views/_ViewImports.cshtml +++ b/Webapp/SDAF/Views/_ViewImports.cshtml @@ -1,3 +1,3 @@ -@using AutomationForm -@using AutomationForm.Models +@using SDAFWebApp +@using SDAFWebApp.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/Webapp/package-lock.json b/Webapp/package-lock.json index 21ff7429d0..c865ec6f2a 100644 --- a/Webapp/package-lock.json +++ b/Webapp/package-lock.json @@ -5,156 +5,67 @@ "requires": true, "dependencies": { "@fluentui/web-components": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@fluentui/web-components/-/web-components-2.0.1.tgz", - "integrity": "sha512-T9nbzxeVIuwhSeM4d8UyS9zVz2sys454jDOE15csqTYRFvzWYO3Ere855YZq3nqGH2T16OR5imgPEhyhri8W3A==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@fluentui/web-components/-/web-components-2.6.1.tgz", + "integrity": "sha512-coyV+QZBVqcrJbncR2iyL0ZMXGFRJmP+JYUlewkYBt8bgmTMIwKBdUX0cN9S6KUp8JHoC2OSRqL8MYgT3T+YLQ==", "requires": { - "@microsoft/fast-colors": "^5.1.0", - "@microsoft/fast-element": "^1.6.0", - "@microsoft/fast-foundation": "^2.24.0", - "@microsoft/fast-web-utilities": "^5.0.0", - "tslib": "^1.13.0" + "@microsoft/fast-colors": "^5.3.0", + "@microsoft/fast-element": "^1.13.0", + "@microsoft/fast-foundation": "^2.49.6", + "@microsoft/fast-web-utilities": "^5.4.0", + "tslib": "^2.1.0" } }, "@microsoft/fast-colors": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@microsoft/fast-colors/-/fast-colors-5.1.4.tgz", - "integrity": "sha512-+0ZVfZ04627buD8ZK8k84FpZom85vU0qUoRtcnFQm6AG5MIWcRE8m5ybJlMIjv2LIJcI/q7tjl+ruKBpWaqwJQ==" + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@microsoft/fast-colors/-/fast-colors-5.3.1.tgz", + "integrity": "sha512-72RZXVfCbwQzvo5sXXkuLXLT7rMeYaSf5r/6ewQiv/trBtqpWRm4DEH2EilHw/iWTBKOXs1qZNQndgUMa5n4LA==" }, "@microsoft/fast-element": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.6.2.tgz", - "integrity": "sha512-TrFOpe9k9xIK2iLfIG5T2+bavUAWBvAC/KQ/3ecFsK65l9PAZ/j3zlkyLxNrpIksFtUBkfVdV03kwFurZjqzKQ==" + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.14.0.tgz", + "integrity": "sha512-zXvuSOzvsu8zDTy9eby8ix8VqLop2rwKRgp++ZN2kTCsoB3+QJVoaGD2T/Cyso2ViZQFXNpiNCVKfnmxBvmWkQ==" }, "@microsoft/fast-foundation": { - "version": "2.25.1", - "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.25.1.tgz", - "integrity": "sha512-7RuHTsgXFu7irhGicb4MUcgFOqrmW3dLynZTBO5FJPOVXZhWqnsAL4Vp8ZtPXb5mXfbN9co9xmnI2og3SrLQ+Q==", + "version": "2.50.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.50.0.tgz", + "integrity": "sha512-8mFYG88Xea1jZf2TI9Lm/jzZ6RWR8x29r24mGuLojNYqIR2Bl8+hnswoV6laApKdCbGMPKnsAL/O68Q0sRxeVg==", "requires": { - "@microsoft/fast-element": "^1.6.2", - "@microsoft/fast-web-utilities": "^5.0.2", - "@microsoft/tsdoc-config": "^0.13.4", + "@microsoft/fast-element": "^1.14.0", + "@microsoft/fast-web-utilities": "^5.4.1", "tabbable": "^5.2.0", "tslib": "^1.13.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "@microsoft/fast-web-utilities": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.0.2.tgz", - "integrity": "sha512-J8Wy64V1NWF/UjFJ1mvmJNNPChbWobsNkJ8xNaV5/M+VKOQEOheojrOS+RmOUG7DKTBlCLIbUvyXsj1YiCfwkA==", - "requires": { - "exenv-es6": "^1.0.0" - } - }, - "@microsoft/tsdoc": { - "version": "0.12.24", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.12.24.tgz", - "integrity": "sha512-Mfmij13RUTmHEMi9vRUhMXD7rnGR2VvxeNYtaGtaJ4redwwjT4UXYJ+nzmVJF7hhd4pn/Fx5sncDKxMVFJSWPg==" - }, - "@microsoft/tsdoc-config": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.13.9.tgz", - "integrity": "sha512-VqqZn+rT9f6XujFPFR2aN9XKF/fuir/IzKVzoxI0vXIzxysp4ee6S2jCakmlGFHEasibifFTsJr7IYmRPxfzYw==", - "requires": { - "@microsoft/tsdoc": "0.12.24", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz", + "integrity": "sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "exenv-es6": "^1.1.1" } }, "exenv-es6": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.0.0.tgz", - "integrity": "sha512-fcG/TX8Ruv9Ma6PBaiNsUrHRJzVzuFMP6LtPn/9iqR+nr9mcLeEOGzXQGLC5CVQSXGE98HtzW2mTZkrCA3XrDg==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "function-bind": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "requires": { - "has": "^1.0.3" - } - }, - "jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "requires": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - } + "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==" }, "tabbable": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.2.1.tgz", - "integrity": "sha512-40pEZ2mhjaZzK0BnI+QGNjJO8UYx9pP5v7BGe17SORTO0OEuuaAwQTkAp8whcZvqon44wKFOikD+Al11K3JICQ==" + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" } } } diff --git a/Webapp/package.json b/Webapp/package.json index 2df006f4e9..2019c0e104 100644 --- a/Webapp/package.json +++ b/Webapp/package.json @@ -1,19 +1,19 @@ { - "name": "automationform", - "version": "1.0.0", - "description": "UI for sap automation", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "https://azurecat-sapdeploy@dev.azure.com/azurecat-sapdeploy/sap_deployment_automation/_git/persius" - }, - "author": "Will Sheehan", - "license": "ISC", - "devDependencies": {}, - "dependencies": { - "@fluentui/web-components": "^2.0.1" + "name": "automationform", + "version": "1.0.0", + "description": "UI for sap automation", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://azurecat-sapdeploy@dev.azure.com/azurecat-sapdeploy/sap_deployment_automation/_git/persius" + }, + "author": "Will Sheehan", + "license": "ISC", + "devDependencies": {}, + "dependencies": { + "@fluentui/web-components": "^2.6.1" + } } -} diff --git a/deploy/ansible/roles-misc/0.3.sap-installation-media-storage-details/tasks/main.yaml b/deploy/ansible/roles-misc/0.3.sap-installation-media-storage-details/tasks/main.yaml index d313d03f0d..861f1b5fde 100644 --- a/deploy/ansible/roles-misc/0.3.sap-installation-media-storage-details/tasks/main.yaml +++ b/deploy/ansible/roles-misc/0.3.sap-installation-media-storage-details/tasks/main.yaml @@ -56,7 +56,7 @@ - name: "0.4 Installation Media: - Extract SAP Binaries Storage Account SAS (temp)" ansible.builtin.set_fact: - subscription_parameter: "{%if control_plane_subscription_id | length > 0 %}--subscription {{ control_plane_subscription_id }}{% else %}{% endif %}" + subscription_parameter: "{% if control_plane_subscription_id | length > 0 %}--subscription {{ control_plane_subscription_id }}{% else %}{% endif %}" - name: "0.4 Installation Media: - Extract SAP Binaries Storage Account secrets" block: @@ -85,7 +85,7 @@ - name: "0.4 Installation Media: - Extract Shared Key Access token flag" ansible.builtin.set_fact: - allowSharedKeyAccess: true + allowSharedKeyAccess: false - name: "0.4 Installation Media: - Check Binaries Storage Account for Shared Key Access with Control Plane Subscription" when: @@ -107,14 +107,13 @@ - name: "Parameter review..." ansible.builtin.debug: msg: # Best method for formatting output with Azure Devops Logs - - "account_name: {{ account_name }}" - - "allowSharedKeyAccess: {{ allowSharedKeyAccess | default(true) }}" - verbosity: 2 + - "Storage account_name: {{ account_name }}" + - "allowSharedKeyAccess: {{ allowSharedKeyAccess }}" - name: "0.4 Installation Media: - Retrieve Access Key secret" when: + - allowSharedKeyAccess - sapbits_access_key is not defined - - allowSharedKeyAccess | default(true) block: - name: "0.4 Installation Media: - Check if Access Key secret exists" ansible.builtin.command: >- @@ -216,7 +215,7 @@ ansible.builtin.set_fact: sapbits_sas_token: "{{ az_sapbits_sas_token.stdout }}" -- name: "0.4 Installation Media: - Create SAP Binaries Storage Account SAS token" +- name: "0.4 Installation Media: - Create User delegation SAP Binaries Storage Account SAS token" when: - sapbits_sas_token is not defined or (sapbits_sas_token | string | length == 0) block: @@ -229,7 +228,7 @@ ansible.builtin.command: "date +'%Y-%m-%d' -d '+3 days'" register: expiry - - name: "0.4 Installation Media: - Create USer delegation SAP Binaries Storage Account SAS in Control Plane subscription" + - name: "0.4 Installation Media: - Create User delegation SAP Binaries Storage Account SAS in Control Plane subscription" ansible.builtin.command: >- az storage container generate-sas \ --account-name {{ account_name }} \ diff --git a/deploy/ansible/roles-sap/0.1-bom-validator/tasks/bom_download.yaml b/deploy/ansible/roles-sap/0.1-bom-validator/tasks/bom_download.yaml index 0376468f93..e620d52aba 100644 --- a/deploy/ansible/roles-sap/0.1-bom-validator/tasks/bom_download.yaml +++ b/deploy/ansible/roles-sap/0.1-bom-validator/tasks/bom_download.yaml @@ -397,7 +397,9 @@ # Description: # - name: "BOM: {{ bom_name }} Upload File {{ bom_media_entry.archive }} using SAS keys" - + when: + - allowSharedKeyAccess + - sapbits_sas_token is defined ansible.builtin.command: >- az storage blob upload --account-name {{ account }} @@ -414,11 +416,10 @@ - azresult.rc != 0 - azresult.stderr is defined - azresult.stderr.find("BlobAlreadyExists") == -1 - when: - - sapbits_sas_token is defined - name: "BOM: {{ bom_name }} Upload File {{ bom_media_entry.archive }}" - + when: + - not allowSharedKeyAccess ansible.builtin.command: >- az storage blob upload --account-name {{ account }} @@ -435,8 +436,6 @@ - azresult.rc != 0 - azresult.stderr is defined - azresult.stderr.find("BlobAlreadyExists") == -1 - when: - - sapbits_sas_token is undefined # Step: 05-04-01 - END # -------------------------------+---------------------------------------------8 diff --git a/deploy/ansible/roles-sap/0.1-bom-validator/tasks/pre_checks.yaml b/deploy/ansible/roles-sap/0.1-bom-validator/tasks/pre_checks.yaml index 48cd5d8e5a..0b8dcf6af8 100644 --- a/deploy/ansible/roles-sap/0.1-bom-validator/tasks/pre_checks.yaml +++ b/deploy/ansible/roles-sap/0.1-bom-validator/tasks/pre_checks.yaml @@ -332,7 +332,7 @@ - name: "(pre_checks.yaml) - {{ task_prefix }} - Get account information" ansible.builtin.command: >- - az account show + az account show --query user --output yaml vars: task_prefix: Storage Account validation delegate_to: localhost @@ -457,6 +457,12 @@ sa_enabled: {{ sa_enabled }} failed_when: false +- name: "Storage account information" + ansible.builtin.debug: + msg: # Best method for formatting output with Azure Devops Logs + - "Storage account_name: {{ account_name }}" + - "allowSharedKeyAccess: {{ allowSharedKeyAccess }}" + - name: "(pre_checks.yaml) - Informational check of Storage Account parameters" when: allowSharedKeyAccess ansible.builtin.assert: diff --git a/deploy/pipelines/05-DB-and-SAP-installation.yaml b/deploy/pipelines/05-DB-and-SAP-installation.yaml index a96126b343..647c4fa64d 100644 --- a/deploy/pipelines/05-DB-and-SAP-installation.yaml +++ b/deploy/pipelines/05-DB-and-SAP-installation.yaml @@ -143,174 +143,12 @@ stages: parameters: getLatestFromBranch: true - task: PostBuildCleanup@4 - - bash: | - #!/bin/bash - # Exit immediately if a command exits with a non-zero status. - set -e - - green="\e[1;32m" - reset="\e[0m" - boldred="\e[1;31m" - if [[ ! -f /etc/profile.d/deploy_server.sh ]]; then - echo -e "$green --- Install dos2unix ---$reset" - sudo apt-get -qq install dos2unix - fi - - #External helper functions - source "sap-automation/deploy/pipelines/helper.sh" - - debug=False - - if [ "$SYSTEM_DEBUG" = True ]; then - set -x - set -o errexit - DEBUG=True - export DEBUG - fi - set -eu - - echo -e "$green--- Convert config file to UX format ---$reset" - echo -e "$green--- Update .sap_deployment_automation/config as DEPLOYMENT_REPO_PATH can change on devops agent ---$reset" - HOME=${CONFIG_REPO_PATH}/$(Deployment_Configuration_Path) - export HOME - cd "$HOME" - - # Check if running on deployer - if [[ ! -f /etc/profile.d/deploy_server.sh ]]; then - configureNonDeployer "$(tf_version)" || true - echo -e "$green--- az login ---$reset" - LogonToAzure false || true - else - LogonToAzure "$USE_MSI" || true - fi - return_code=$? - if [ 0 != $return_code ]; then - echo -e "$boldred--- Login failed ---$reset" - echo "##vso[task.logissue type=error]az login failed." - exit $return_code - fi - - echo -e "$green--- Configure devops CLI extension ---$reset" - az config set extension.use_dynamic_install=yes_without_prompt --output none --only-show-errors - - az extension add --name azure-devops --output none --only-show-errors - - az devops configure --defaults organization=$(System.CollectionUri) project='$(System.TeamProject)' --output none - - echo -e "$green--- Validations ---$reset" - # shellcheck disable=SC2086 - ENVIRONMENT=$(echo ${SAP_SYSTEM_CONFIGURATION_NAME} | awk -F'-' '{print $1}' | xargs) - - # shellcheck disable=SC2086 - LOCATION=$(echo ${SAP_SYSTEM_CONFIGURATION_NAME} | awk -F'-' '{print $2}' | xargs) - - # shellcheck disable=SC2086 - NETWORK=$(echo ${SAP_SYSTEM_CONFIGURATION_NAME} | awk -F'-' '{print $3}' | xargs) - - # shellcheck disable=SC2086 - SID=$(echo ${SAP_SYSTEM_CONFIGURATION_NAME} | awk -F'-' '{print $4}' | xargs) - - environment_file_name="$HOME/.sap_deployment_automation/$ENVIRONMENT$LOCATION$NETWORK" - parameters_filename="$HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml" - - if [ "azure pipelines" = "$(this_agent)" ]; then - echo "##vso[task.logissue type=error]Please use a self hosted agent for this playbook. Define it in the SDAF-${ENVIRONMENT} variable group using the 'POOL' variable." - exit 2 - fi - - if [ ! -f "$environment_file_name" ]; then - echo -e "$boldred--- $environment_file_name was not found ---$reset" - echo "##vso[task.logissue type=error]Workload zone configuration file $environment_file_name was not found." - exit 2 - fi - - if [ ! -f "$parameters_filename" ]; then - echo -e "$boldred--- $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml was not found ---$reset" - echo "##vso[task.logissue type=error]File $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml was not found." - exit 2 - else - dos2unix -q "$HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml" - fi - - if [ ! -n "${SID}" ]; then - echo "##vso[task.logissue type=error]SID was not found in ${SAP_SYSTEM_CONFIGURATION_NAME}." - exit 2 - fi - - if [ ! -f "$HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/${SID}_hosts.yaml" ]; then - echo -e "$boldred--- $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/${SID}_hosts.yaml was not found ---$reset" - echo "##vso[task.logissue type=error]File $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/${SID}_hosts.yaml was not found." - exit 2 - fi - dos2unix -q "$HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/${SID}_hosts.yaml" - - VARIABLE_GROUP_ID=$(az pipelines variable-group list --query "[?name=='$(variable_group)'].id | [0]") - if [ -z "${VARIABLE_GROUP_ID}" ]; then - echo "##vso[task.logissue type=error]Variable group $(variable_group) could not be found." - exit 2 - fi - - echo "##vso[build.updatebuildnumber]Deploying ${SAP_SYSTEM_CONFIGURATION_NAME} using BoM ${BOM_BASE_NAME}" - - echo "##vso[task.setvariable variable=SID;isOutput=true]${SID}" - echo "##vso[task.setvariable variable=SAP_PARAMETERS;isOutput=true]sap-parameters.yaml" - echo "##vso[task.setvariable variable=FOLDER;isOutput=true]$HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}" - echo "##vso[task.setvariable variable=HOSTS;isOutput=true]${SID}_hosts.yaml" - - echo "Environment: $ENVIRONMENT" - echo "Location: $LOCATION" - echo "Virtual network logical name: $NETWORK" - echo "SAP Application BoM: $BOM_BASE_NAME" - printf -v val '%-15s' "$(variable_group) id:" - echo "$val $VARIABLE_GROUP_ID" - - echo "SID: ${SID}" - echo "Folder: $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}" - echo "Hosts file: ${SID}_hosts.yaml" - echo "sap_parameters_file: $parameters_filename" - echo "Configuration file: $environment_file_name" - - echo -e "$green--- Get Files from the DevOps Repository ---$reset" - cd "${CONFIG_REPO_PATH}/$(Deployment_Configuration_Path)/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}" - - echo -e "$green--- Add BOM Base Name and SAP FQDN to sap-parameters.yaml ---$reset" - sed -i 's|bom_base_name:.*|bom_base_name: '"$BOM_BASE_NAME"'|' sap-parameters.yaml - - echo -e "$green--- Get connection details ---$reset" - mkdir -p artifacts - - prefix="${ENVIRONMENT}${LOCATION}${NETWORK}" - - workload_key_vault=$(getVariableFromVariableGroup "${VARIABLE_GROUP_ID}" "${prefix}Workload_Key_Vault" "${environment_file_name}" "workloadkeyvault" || true) - workload_prefix=$(getVariableFromVariableGroup "${VARIABLE_GROUP_ID}" "${prefix}Workload_Secret_Prefix" "${environment_file_name}" "workload_zone_prefix" || true) - control_plane_subscription=$(getVariableFromVariableGroup "${VARIABLE_GROUP_ID}" "Terraform_Remote_Storage_Subscription" "${environment_file_name}" "STATE_SUBSCRIPTION" || true) - - echo "SID: ${SID}" - echo "Folder: $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}" - echo "Workload Key Vault: ${workload_key_vault}" - - echo "Control Plane Subscription: ${control_plane_subscription}" - echo "Workload Prefix: ${workload_prefix}" - - if [[ $EXTRA_PARAMETERS = "'$(EXTRA_PARAMETERS)'" ]]; then - new_parameters=$PIPELINE_EXTRA_PARAMETERS - else - echo "##vso[task.logissue type=warning]Extra parameters were provided - '$EXTRA_PARAMETERS'" - new_parameters="$EXTRA_PARAMETERS $PIPELINE_EXTRA_PARAMETERS" - fi - - echo "##vso[task.setvariable variable=SSH_KEY_NAME;isOutput=true]${workload_prefix}-sid-sshkey" - echo "##vso[task.setvariable variable=VAULT_NAME;isOutput=true]$workload_key_vault" - echo "##vso[task.setvariable variable=PASSWORD_KEY_NAME;isOutput=true]${workload_prefix}-sid-password" - echo "##vso[task.setvariable variable=USERNAME_KEY_NAME;isOutput=true]${workload_prefix}-sid-username" - echo "##vso[task.setvariable variable=NEW_PARAMETERS;isOutput=true]${new_parameters}" - echo "##vso[task.setvariable variable=CP_SUBSCRIPTION;isOutput=true]${control_plane_subscription}" - - az keyvault secret show --name "${workload_prefix}-sid-sshkey" --vault-name "$workload_key_vault" --subscription "$control_plane_subscription" --query value -o tsv >"artifacts/${SAP_SYSTEM_CONFIGURATION_NAME}_sshkey" - cp sap-parameters.yaml artifacts/. - cp "${SID}_hosts.yaml" artifacts/. - - 2> >(while read line; do (echo >&2 "STDERROR: $line"); done) + - task: Bash@3 + inputs: + targetType: 'filePath' + filePath: "$(System.DefaultWorkingDirectory)/sap-automation/deploy/scripts/pipeline_scripts/05-DB-and-SAP-installation-prepare" + failOnStderr: false + workingDirectory: "$(System.DefaultWorkingDirectory)" name: Preparation displayName: Preparation for Ansible env: @@ -323,7 +161,7 @@ stages: AZURE_TENANT_ID: $(WL_ARM_TENANT_ID) AZURE_SUBSCRIPTION_ID: $(Terraform_Remote_Storage_Subscription) ANSIBLE_COLLECTIONS_PATHS: /opt/ansible/collections - CONFIG_REPO_PATH: ${{ parameters.config_repo_path }} + CONFIG_REPO_PATH: ${{ parameters.config_repo_path }}/$(Deployment_Configuration_Path) BOM_BASE_NAME: ${{ parameters.bom_base_name }} SAP_SYSTEM_CONFIGURATION_NAME: ${{ parameters.sap_system_configuration_name }} EXTRA_PARAMETERS: $(EXTRA_PARAMETERS) diff --git a/deploy/scripts/New-SDAFDevopsProject.ps1 b/deploy/scripts/New-SDAFDevopsProject.ps1 index bb5181f51c..6ca1a6c547 100644 --- a/deploy/scripts/New-SDAFDevopsProject.ps1 +++ b/deploy/scripts/New-SDAFDevopsProject.ps1 @@ -466,7 +466,7 @@ Write-Host "Creating the variable group SDAF-General" -ForegroundColor Green $general_group_id = (az pipelines variable-group list --query "[?name=='SDAF-General'].id | [0]" --only-show-errors) if ($general_group_id.Length -eq 0) { - az pipelines variable-group create --name SDAF-General --variables ANSIBLE_HOST_KEY_CHECKING=false Deployment_Configuration_Path=WORKSPACES Branch=main tf_version="1.9.8" ansible_core_version="2.15" S-Username=$SUserName S-Password=$SPassword --output yaml --authorize true --output none + az pipelines variable-group create --name SDAF-General --variables ANSIBLE_HOST_KEY_CHECKING=false Deployment_Configuration_Path=WORKSPACES Branch=main tf_version="1.10.1" ansible_core_version="2.16" S-Username=$SUserName S-Password=$SPassword --output yaml --authorize true --output none $general_group_id = (az pipelines variable-group list --query "[?name=='SDAF-General'].id | [0]" --only-show-errors) az pipelines variable-group variable update --group-id $general_group_id --name "S-Password" --value $SPassword --secret true --output none --only-show-errors } diff --git a/deploy/scripts/advanced_state_management.sh b/deploy/scripts/advanced_state_management.sh index ac595df6ac..0d082d88d6 100755 --- a/deploy/scripts/advanced_state_management.sh +++ b/deploy/scripts/advanced_state_management.sh @@ -203,7 +203,7 @@ if checkIfCloudShell; then export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" else if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then - mkdir -p /opt/terraform/.terraform.d/plugin-cache + sudo mkdir -p /opt/terraform/.terraform.d/plugin-cache sudo chown -R $USER /opt/terraform fi export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache diff --git a/deploy/scripts/configure_deployer.sh b/deploy/scripts/configure_deployer.sh index b2ecc1fc6c..5aec6b6964 100755 --- a/deploy/scripts/configure_deployer.sh +++ b/deploy/scripts/configure_deployer.sh @@ -38,8 +38,8 @@ # Check if the script is running as root if [[ $EUID -eq 0 ]]; then - echo "This script should not be run as root or with sudo. Please run as a regular user." - exit 1 + echo "This script should not be run as root or with sudo. Please run as a regular user." + exit 1 fi # Print expanded commands as they are about to be executed @@ -62,7 +62,7 @@ export local_user=$USER # if [ -z "${TF_VERSION}" ]; then - TF_VERSION="1.8.0" + TF_VERSION="1.10.1" fi # Fail if attempting to access and unset variable or parameter @@ -73,7 +73,7 @@ tfversion=$TF_VERSION # # Ansible Version settings # -ansible_version="${ansible_version:-2.13}" +ansible_version="${ansible_version:-2.16}" ansible_major="${ansible_version%%.*}" ansible_minor=$(echo "${ansible_version}." | cut -d . -f 2) @@ -84,147 +84,147 @@ distro_name="" distro_version="" distro_name_version="" error() { - echo 1>&2 "ERROR: ${@}" + echo 1>&2 "ERROR: ${@}" } get_distro_name() { - typeset -g distro_name + typeset -g distro_name - if [[ -z "${distro_name:-}" ]]; then - distro_name="$( - . /etc/os-release - echo "${ID,,}" - )" - fi + if [[ -z "${distro_name:-}" ]]; then + distro_name="$( + . /etc/os-release + echo "${ID,,}" + )" + fi - echo "${distro_name}" + echo "${distro_name}" } get_distro_version() { - typeset -g distro_version + typeset -g distro_version - if [[ -z "${distro_version:-}" ]]; then - distro_version="$( - . /etc/os-release - echo "${VERSION_ID,,}" - )" - fi + if [[ -z "${distro_version:-}" ]]; then + distro_version="$( + . /etc/os-release + echo "${VERSION_ID,,}" + )" + fi - echo "${distro_version}" + echo "${distro_version}" } get_distro_name_version() { - typeset -g distro_name_version + typeset -g distro_name_version - if [[ -z "${distro_name_version:-}" ]]; then - distro_name_version="$(get_distro_name)_$(get_distro_version)" - fi + if [[ -z "${distro_name_version:-}" ]]; then + distro_name_version="$(get_distro_name)_$(get_distro_version)" + fi - echo "${distro_name_version}" + echo "${distro_name_version}" } # # Package Management Functions # pkg_mgr_init() { - typeset -g pkg_mgr - - case "$(get_distro_name)" in - ubuntu | debian) - pkg_mgr="apt-get" - pkg_type="deb" - ;; - sles | opensuse*) - pkg_mgr="zypper" - pkg_type="rpm" - ;; - rhel | centos | fedora) - pkg_mgr="yum" - pkg_type="rpm" - ;; - *) - error "Unsupported distibution: '${distro_name}'" - exit 1 - ;; - esac + typeset -g pkg_mgr + + case "$(get_distro_name)" in + ubuntu | debian) + pkg_mgr="apt-get" + pkg_type="deb" + ;; + sles | opensuse*) + pkg_mgr="zypper" + pkg_type="rpm" + ;; + rhel | centos | fedora) + pkg_mgr="yum" + pkg_type="rpm" + ;; + *) + error "Unsupported distibution: '${distro_name}'" + exit 1 + ;; + esac } pkg_mgr_refresh() { - typeset -g pkg_mgr pkg_mgr_refreshed - - if [[ -z ${pkg_mgr:-} ]]; then - pkg_mgr_init - fi - - if [[ -n ${pkg_mgr_refreshed:-} ]]; then - return - fi - - case ${pkg_mgr} in - apt-get) - sudo "${pkg_mgr}" update --quiet - ;; - zypper) - set +o errexit - sudo "${pkg_mgr}" --gpg-auto-import-keys --quiet refresh - set -o errexit - ;; - yum) - sudo "${pkg_mgr}" update --quiet - ;; - esac - - pkg_mgr_refreshed=true + typeset -g pkg_mgr pkg_mgr_refreshed + + if [[ -z ${pkg_mgr:-} ]]; then + pkg_mgr_init + fi + + if [[ -n ${pkg_mgr_refreshed:-} ]]; then + return + fi + + case ${pkg_mgr} in + apt-get) + sudo "${pkg_mgr}" update --quiet + ;; + zypper) + set +o errexit + sudo "${pkg_mgr}" --gpg-auto-import-keys --quiet refresh + set -o errexit + ;; + yum) + sudo "${pkg_mgr}" update --quiet + ;; + esac + + pkg_mgr_refreshed=true } pkg_mgr_upgrade() { - typeset -g pkg_mgr pkg_mgr_upgraded - - if [[ -z ${pkg_mgr:-} ]]; then - pkg_mgr_init - fi - - if [[ -n ${pkg_mgr_upgraded:-} ]]; then - return - fi - - case ${pkg_mgr} in - apt-get) - sudo "${pkg_mgr}" upgrade --quiet -y - ;; - zypper) - set +o errexit - sudo "${pkg_mgr}" --gpg-auto-import-keys --non-interactive patch - set -o errexit - ;; - yum) - sudo "${pkg_mgr}" upgrade --quiet -y - ;; - esac - - pkg_mgr_upgraded=true + typeset -g pkg_mgr pkg_mgr_upgraded + + if [[ -z ${pkg_mgr:-} ]]; then + pkg_mgr_init + fi + + if [[ -n ${pkg_mgr_upgraded:-} ]]; then + return + fi + + case ${pkg_mgr} in + apt-get) + sudo "${pkg_mgr}" upgrade --quiet -y + ;; + zypper) + set +o errexit + sudo "${pkg_mgr}" --gpg-auto-import-keys --non-interactive patch + set -o errexit + ;; + yum) + sudo "${pkg_mgr}" upgrade --quiet -y + ;; + esac + + pkg_mgr_upgraded=true } pkg_mgr_install() { - typeset -g pkg_mgr - - pkg_mgr_refresh - - case ${pkg_mgr} in - apt-get) - sudo env DEBIAN_FRONTEND=noninteractive ${pkg_mgr} --quiet --yes install "${@}" - ;; - zypper) - set +o errexit - sudo "${pkg_mgr}" patch --auto-agree-with-licenses --with-interactive --no-confirm - sleep 60 - sudo "${pkg_mgr}" --gpg-auto-import-keys --quiet --non-interactive install --no-confirm "${@}" - set -o errexit - ;; - yum) - sudo "${pkg_mgr}" --nogpgcheck --quiet install --assumeyes "${@}" - ;; - esac + typeset -g pkg_mgr + + pkg_mgr_refresh + + case ${pkg_mgr} in + apt-get) + sudo env DEBIAN_FRONTEND=noninteractive ${pkg_mgr} --quiet --yes install "${@}" + ;; + zypper) + set +o errexit + sudo "${pkg_mgr}" patch --auto-agree-with-licenses --with-interactive --no-confirm + sleep 60 + sudo "${pkg_mgr}" --gpg-auto-import-keys --quiet --non-interactive install --no-confirm "${@}" + set -o errexit + ;; + yum) + sudo "${pkg_mgr}" --nogpgcheck --quiet install --assumeyes "${@}" + ;; + esac } # @@ -264,93 +264,93 @@ tf_zip="terraform_${tfversion}_linux_amd64.zip" # Check for supported distro case "$(get_distro_name_version)" in sles_12*) - error "Unsupported distro: ${distro_name_version} doesn't provide virtualenv in standard repos." - exit 1 - ;; + error "Unsupported distro: ${distro_name_version} doesn't provide virtualenv in standard repos." + exit 1 + ;; ubuntu* | sles*) - echo "${distro_name_version} is supported." - ;; + echo "${distro_name_version} is supported." + ;; rhel*) - echo "${distro_name_version} is supported." - ;; + echo "${distro_name_version} is supported." + ;; *) - error "Unsupported distro: ${distro_name_version} not currently supported." - exit 1 - ;; + error "Unsupported distro: ${distro_name_version} not currently supported." + exit 1 + ;; esac if [ "$(get_distro_version)" == "15.4" ]; then - error "Unsupported distro: ${distro_name_version} at this time." - exit 1 + error "Unsupported distro: ${distro_name_version} at this time." + exit 1 fi if [ "$(get_distro_version)" == "15.5" ]; then - error "Unsupported distro: ${distro_name_version} at this time." - exit 1 + error "Unsupported distro: ${distro_name_version} at this time." + exit 1 fi case "$(get_distro_name_version)" in sles*) - set +o errexit - zypper addrepo https://download.opensuse.org/repositories/network/SLE_15/network.repo - set -o errexit - ;; + set +o errexit + zypper addrepo https://download.opensuse.org/repositories/network/SLE_15/network.repo + set -o errexit + ;; esac echo "Set ansible version for specific distros" echo "" case "$(get_distro_name)" in ubuntu) - echo "we are inside ubuntu" - rel=$(lsb_release -a | grep Release | cut -d':' -f2 | xargs) - if [ "$rel" == "22.04" ]; then - ansible_version="2.15" - ansible_major="${ansible_version%%.*}" - ansible_minor=$(echo "${ansible_version}." | cut -d . -f 2) - fi - ;; + echo "we are inside ubuntu" + rel=$(lsb_release -a | grep Release | cut -d':' -f2 | xargs) + if [ "$rel" == "22.04" ]; then + ansible_version="2.16" + ansible_major="${ansible_version%%.*}" + ansible_minor=$(echo "${ansible_version}." | cut -d . -f 2) + fi + ;; sles) - echo "we are inside sles" - ansible_version="2.11" - ansible_major="${ansible_version%%.*}" - ansible_minor=$(echo "${ansible_version}." | cut -d . -f 2) - # Ansible installation directories - ansible_base="/opt/ansible" - ansible_bin="${ansible_base}/bin" - ansible_venv="${ansible_base}/venv/${ansible_version}" - ansible_venv_bin="${ansible_venv}/bin" - ansible_collections="${ansible_base}/collections" - ansible_pip3="${ansible_venv_bin}/pip3" - sudo python3 -m pip install virtualenv - ;; + echo "we are inside sles" + ansible_version="2.11" + ansible_major="${ansible_version%%.*}" + ansible_minor=$(echo "${ansible_version}." | cut -d . -f 2) + # Ansible installation directories + ansible_base="/opt/ansible" + ansible_bin="${ansible_base}/bin" + ansible_venv="${ansible_base}/venv/${ansible_version}" + ansible_venv_bin="${ansible_venv}/bin" + ansible_collections="${ansible_base}/collections" + ansible_pip3="${ansible_venv_bin}/pip3" + sudo python3 -m pip install virtualenv + ;; rhel) - echo "we are inside RHEL" - ansible_version="2.11" - ansible_major="${ansible_version%%.*}" - ansible_minor=$(echo "${ansible_version}." | cut -d . -f 2) - # Ansible installation directories - ansible_base="/opt/ansible" - ansible_bin="${ansible_base}/bin" - ansible_venv="${ansible_base}/venv/${ansible_version}" - ansible_venv_bin="${ansible_venv}/bin" - ansible_collections="${ansible_base}/collections" - ansible_pip3="${ansible_venv_bin}/pip3" - sudo python3 -m pip install virtualenv - ;; + echo "we are inside RHEL" + ansible_version="2.11" + ansible_major="${ansible_version%%.*}" + ansible_minor=$(echo "${ansible_version}." | cut -d . -f 2) + # Ansible installation directories + ansible_base="/opt/ansible" + ansible_bin="${ansible_base}/bin" + ansible_venv="${ansible_base}/venv/${ansible_version}" + ansible_venv_bin="${ansible_venv}/bin" + ansible_collections="${ansible_base}/collections" + ansible_pip3="${ansible_venv_bin}/pip3" + sudo python3 -m pip install virtualenv + ;; *) - echo "we are in the default case statement" - ;; + echo "we are in the default case statement" + ;; esac echo "Ansible version: ${ansible_version}" # List of required packages whose names are common to all supported distros required_pkgs=( - git - jq - unzip - ca-certificates - curl - gnupg - dos2unix + git + jq + unzip + ca-certificates + curl + gnupg + dos2unix ) cli_pkgs=( @@ -359,44 +359,44 @@ cli_pkgs=( # Include distro version agnostic packages into required packages list case "$(get_distro_name)" in ubuntu) - cli_pkgs+=( - azure-cli - ) - required_pkgs+=( - sshpass - python3-pip - python3-virtualenv - apt-transport-https - lsb-release - software-properties-common - ) - ;; + cli_pkgs+=( + azure-cli + ) + required_pkgs+=( + sshpass + python3-pip + python3-virtualenv + apt-transport-https + lsb-release + software-properties-common + ) + ;; sles) - required_pkgs+=( - curl - python3-pip - lsb-release - ) - ;; + required_pkgs+=( + curl + python3-pip + lsb-release + ) + ;; rhel) - cli_pkgs+=( - azure-cli - ) - required_pkgs+=( - sshpass - python36 - python3-pip - python3-virtualenv - ) - ;; + cli_pkgs+=( + azure-cli + ) + required_pkgs+=( + sshpass + python36 + python3-pip + python3-virtualenv + ) + ;; esac # Include distro version specific packages into required packages list case "$(get_distro_name_version)" in ubuntu_18.04) - required_pkgs+=( - virtualenv - ) - ;; + required_pkgs+=( + virtualenv + ) + ;; esac echo "$(get_distro_name_version)" @@ -419,32 +419,32 @@ subscription_id=$(curl -H Metadata:true --noproxy "*" "http://169.254.169.254/me # Prepare Azure SAP Automated Deployment folder structure mkdir -p \ - "${asad_ws}"/LOCAL/"${rg_name}" \ - "${asad_ws}"/LIBRARY \ - "${asad_ws}"/SYSTEM \ - "${asad_ws}"/LANDSCAPE \ - "${asad_ws}"/DEPLOYER + "${asad_ws}"/LOCAL/"${rg_name}" \ + "${asad_ws}"/LIBRARY \ + "${asad_ws}"/SYSTEM \ + "${asad_ws}"/LANDSCAPE \ + "${asad_ws}"/DEPLOYER # # Clone Azure SAP Automated Deployment code repository # if [[ ! -d "${asad_dir}" ]]; then - git clone "${asad_repo}" "${asad_dir}" + git clone "${asad_repo}" "${asad_dir}" fi # # Clone Azure SAP Automated Deployment sample repository # if [[ ! -d "${asad_sample_dir}" ]]; then - git clone "${asad_sample_repo}" "${asad_sample_dir}" + git clone "${asad_sample_repo}" "${asad_sample_dir}" fi # # Install terraform for all users # sudo mkdir -p \ - "${tf_dir}" \ - "${tf_bin}" + "${tf_dir}" \ + "${tf_bin}" wget -nv -O /tmp/"${tf_zip}" "https://releases.hashicorp.com/terraform/${tfversion}/${tf_zip}" sudo unzip -o /tmp/"${tf_zip}" -d "${tf_dir}" sudo ln -vfs "../$(basename "${tf_dir}")/terraform" "${tf_bin}/terraform" @@ -454,68 +454,68 @@ sudo rm /tmp/"${tf_zip}" # Uninstall Azure CLI - For some platforms case "$(get_distro_name)" in ubuntu | sles) - rel=$(lsb_release -a | grep Release | cut -d':' -f2 | xargs) - # Ubuntu 20.04 (Focal Fossa) and 20.10 (Groovy Gorilla) include an azure-cli package with version 2.0.81 provided by the universe repository. - # This package is outdated and not recommended. If this package is installed, remove the package - if [ "$rel" == "20.04" ]; then - echo "Removing Azure CLI" - sudo apt remove azure-cli -y - sudo apt autoremove -y - sudo apt update -y - fi - if [ "$(get_distro_version)" == "15.3" ]; then - set +o errexit - sudo zypper rm -y --clean-deps azure-cli - set -o errexit - fi - if [ "$(get_distro_version)" == "15.4" ]; then - set +o errexit - sudo zypper rm -y --clean-deps azure-cli - set -o errexit - fi - if [ "$(get_distro_version)" == "15.5" ]; then - set +o errexit - sudo zypper rm -y --clean-deps azure-cli - set -o errexit - fi - ;; + rel=$(lsb_release -a | grep Release | cut -d':' -f2 | xargs) + # Ubuntu 20.04 (Focal Fossa) and 20.10 (Groovy Gorilla) include an azure-cli package with version 2.0.81 provided by the universe repository. + # This package is outdated and not recommended. If this package is installed, remove the package + if [ "$rel" == "20.04" ]; then + echo "Removing Azure CLI" + sudo apt remove azure-cli -y + sudo apt autoremove -y + sudo apt update -y + fi + if [ "$(get_distro_version)" == "15.3" ]; then + set +o errexit + sudo zypper rm -y --clean-deps azure-cli + set -o errexit + fi + if [ "$(get_distro_version)" == "15.4" ]; then + set +o errexit + sudo zypper rm -y --clean-deps azure-cli + set -o errexit + fi + if [ "$(get_distro_version)" == "15.5" ]; then + set +o errexit + sudo zypper rm -y --clean-deps azure-cli + set -o errexit + fi + ;; esac # Install Azure CLI case "$(get_distro_name)" in ubuntu) - echo "Getting the Microsoft Key" - sudo mkdir -p /etc/apt/keyrings - curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/keyrings/microsoft.gpg >/dev/null - sudo chmod go+r /etc/apt/keyrings/microsoft.gpg - - AZ_REPO=$(lsb_release -cs) - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" | - sudo tee /etc/apt/sources.list.d/azure-cli.list - - sudo apt-get update - sudo apt-get install azure-cli - ;; + echo "Getting the Microsoft Key" + sudo mkdir -p /etc/apt/keyrings + curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/keyrings/microsoft.gpg >/dev/null + sudo chmod go+r /etc/apt/keyrings/microsoft.gpg + + AZ_REPO=$(lsb_release -cs) + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" | + sudo tee /etc/apt/sources.list.d/azure-cli.list + + sudo apt-get update + sudo apt-get install azure-cli + ;; sles) - set +o errexit - if [ -f /home/"${local_user}"/repos_configured ]; then - sudo zypper install -y --from azure-cli azure-cli - else - sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc - repo_found=$(zypper repos | grep "Azure CLI") - if [ -z "$repo_found" ]; then - sudo zypper addrepo --name 'Azure CLI' --check https://packages.microsoft.com/yumrepos/azure-cli azure-cli - fi - sudo touch /home/${local_user}/repos_configured - sudo zypper install -y --from azure-cli azure-cli - fi - set -o errexit - ;; + set +o errexit + if [ -f /home/"${local_user}"/repos_configured ]; then + sudo zypper install -y --from azure-cli azure-cli + else + sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc + repo_found=$(zypper repos | grep "Azure CLI") + if [ -z "$repo_found" ]; then + sudo zypper addrepo --name 'Azure CLI' --check https://packages.microsoft.com/yumrepos/azure-cli azure-cli + fi + sudo touch /home/${local_user}/repos_configured + sudo zypper install -y --from azure-cli azure-cli + fi + set -o errexit + ;; rhel*) - sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc - sudo dnf install -y https://packages.microsoft.com/config/rhel/8/packages-microsoft-prod.rpm - sudo dnf install -y azure-cli - ;; + sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc + sudo dnf install -y https://packages.microsoft.com/config/rhel/8/packages-microsoft-prod.rpm + sudo dnf install -y azure-cli + ;; esac # sudo az upgrade --all --yes --only-show-errors --output none @@ -528,19 +528,19 @@ export DOTNET_ROOT=${DOTNET_INSTALL_DIR} # Install dotNet case "$(get_distro_name)" in ubuntu) - sudo snap install dotnet-sdk --classic --channel=8.0 - sudo snap alias dotnet-sdk.dotnet dotnet - ;; + sudo snap install dotnet-sdk --classic --channel=8.0 + sudo snap alias dotnet-sdk.dotnet dotnet + ;; sles) - sudo wget https://dot.net/v1/dotnet-install.sh -O "/home/${local_user}/dotnet-install.sh" - sudo chmod +x "/home/${local_user}/dotnet-install.sh" - sudo /home/"${local_user}"/dotnet-install.sh --install-dir "${DOTNET_ROOT}" --channel 8.0 - ;; + sudo wget https://dot.net/v1/dotnet-install.sh -O "/home/${local_user}/dotnet-install.sh" + sudo chmod +x "/home/${local_user}/dotnet-install.sh" + sudo /home/"${local_user}"/dotnet-install.sh --install-dir "${DOTNET_ROOT}" --channel 8.0 + ;; rhel*) - sudo wget https://dot.net/v1/dotnet-install.sh -O "/home/${local_user}/dotnet-install.sh" - sudo chmod +x "/home/${local_user}/dotnet-install.sh" - sudo /home/"${local_user}"/dotnet-install.sh --install-dir "${DOTNET_ROOT}" --channel 8.0 - ;; + sudo wget https://dot.net/v1/dotnet-install.sh -O "/home/${local_user}/dotnet-install.sh" + sudo chmod +x "/home/${local_user}/dotnet-install.sh" + sudo /home/"${local_user}"/dotnet-install.sh --install-dir "${DOTNET_ROOT}" --channel 8.0 + ;; esac az config set extension.use_dynamic_install=yes_without_prompt @@ -556,37 +556,37 @@ set -o errexit # sudo mkdir -p \ - "${ansible_bin}" \ - "${ansible_collections}" + "${ansible_bin}" \ + "${ansible_collections}" # Create a Python3 based venv into which we will install Ansible. case "$(get_distro_name)" in ubuntu | sles) - if [[ ! -e "${ansible_venv_bin}/activate" ]]; then - sudo rm -rf "${ansible_venv}" - sudo virtualenv --python python3 "${ansible_venv}" - fi - ;; + if [[ ! -e "${ansible_venv_bin}/activate" ]]; then + sudo rm -rf "${ansible_venv}" + sudo virtualenv --python python3 "${ansible_venv}" + fi + ;; rhel*) - if [[ ! -e "${ansible_venv_bin}/activate" ]]; then - sudo rm -rf "${ansible_venv}" - sudo python3 -m venv "${ansible_venv}" - source "${ansible_venv_bin}/activate" - fi - ;; + if [[ ! -e "${ansible_venv_bin}/activate" ]]; then + sudo rm -rf "${ansible_venv}" + sudo python3 -m venv "${ansible_venv}" + source "${ansible_venv_bin}/activate" + fi + ;; esac # Fail if pip3 doesn't exist in the venv if [[ ! -x "${ansible_venv_bin}/pip3" ]]; then - echo "Using the wrong pip3: '${found_pip3}' != '${ansible_venv_bin}/pip3'" - exit 1 + echo "Using the wrong pip3: != '${ansible_venv_bin}/pip3'" + exit 1 fi # Ensure that standard tools are up to date sudo "${ansible_venv_bin}"/pip3 install --upgrade \ - pip \ - wheel \ - setuptools + pip \ + wheel \ + setuptools # Install latest MicroSoft Authentication Library # TODO(rtamalin): Do we need this? In particular do we expect to integrated @@ -601,11 +601,11 @@ sudo "${ansible_venv_bin}"/pip3 install --upgrade \ # yamllint \ sudo "${ansible_venv_bin}"/pip3 install \ - "ansible-core>=${ansible_major}.${ansible_minor},<${ansible_major}.$((ansible_minor + 1))" \ - argcomplete \ - 'pywinrm>=0.3.0' \ - netaddr \ - jmespath + "ansible-core>=${ansible_major}.${ansible_minor},<${ansible_major}.$((ansible_minor + 1))" \ + argcomplete \ + 'pywinrm>=0.3.0' \ + netaddr \ + jmespath # Create symlinks for all relevant commands that were installed in the Ansible # venv's bin so that they are available in the /opt/ansible/bin directory, which @@ -613,32 +613,32 @@ sudo "${ansible_venv_bin}"/pip3 install \ # that we need from the Ansible venv bin directory without superceding standard # system versions of the commands that are also found there, e.g. python3. ansible_venv_commands=( - # Ansible 2.9 command set - ansible - ansible-config - ansible-connection - ansible-console - ansible-doc - ansible-galaxy - ansible-inventory - ansible-playbook - ansible-pull - ansible-test - ansible-vault - - # ansible-lint - # ansible-lint - - # argcomplete - activate-global-python-argcomplete - - # yamllint - # yamllint + # Ansible 2.9 command set + ansible + ansible-config + ansible-connection + ansible-console + ansible-doc + ansible-galaxy + ansible-inventory + ansible-playbook + ansible-pull + ansible-test + ansible-vault + + # ansible-lint + # ansible-lint + + # argcomplete + activate-global-python-argcomplete + + # yamllint + # yamllint ) relative_path="$(realpath --relative-to ${ansible_bin} "${ansible_venv_bin}")" for vcmd in "${ansible_venv_commands[@]}"; do - sudo ln -vfs "${relative_path}/${vcmd}" "${ansible_bin}/${vcmd}" + sudo ln -vfs "${relative_path}/${vcmd}" "${ansible_bin}/${vcmd}" done # Ensure that Python argcomplete is enabled for all users interactive shell sessions @@ -655,17 +655,17 @@ sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install community.window sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install microsoft.ad --force --collections-path "${ansible_collections}" if [[ "${ansible_version}" == "2.11" ]]; then - # ansible galaxy upstream has changed. Some collections are only available for install via old-galaxy.ansible.com - # https://github.com/ansible/ansible/issues/81830 - # https://stackoverflow.com/questions/77225047/gitlab-pipeline-to-install-ansible-galaxy-role-fails/77238083#77238083 - echo "Installing some ansible collections from old-galaxy.ansible.com" - sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install community.general --force --collections-path "${ansible_collections}" --server="https://old-galaxy.ansible.com" --ignore-certs - sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install ansible.netcommon --force --collections-path "${ansible_collections}" --server="https://old-galaxy.ansible.com" --ignore-certs + # ansible galaxy upstream has changed. Some collections are only available for install via old-galaxy.ansible.com + # https://github.com/ansible/ansible/issues/81830 + # https://stackoverflow.com/questions/77225047/gitlab-pipeline-to-install-ansible-galaxy-role-fails/77238083#77238083 + echo "Installing some ansible collections from old-galaxy.ansible.com" + sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install community.general --force --collections-path "${ansible_collections}" --server="https://old-galaxy.ansible.com" --ignore-certs + sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install ansible.netcommon --force --collections-path "${ansible_collections}" --server="https://old-galaxy.ansible.com" --ignore-certs else - echo "Installing community.general" - sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install community.general --force --collections-path "${ansible_collections}" - echo "Installing ansible.netcommon:5.1.2" - sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install ansible.netcommon:5.1.2 --force --collections-path "${ansible_collections}" + echo "Installing community.general" + sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install community.general --force --collections-path "${ansible_collections}" + echo "Installing ansible.netcommon:5.1.2" + sudo -H "${ansible_venv_bin}/ansible-galaxy" collection install ansible.netcommon:5.1.2 --force --collections-path "${ansible_collections}" fi set -o xtrace # @@ -677,11 +677,11 @@ export PATH="${PATH}":"${ansible_bin}":"${tf_bin}":"${DOTNET_ROOT}" # Prepare Azure SAP Automated Deployment folder structure mkdir -p \ - "${asad_ws}"/LOCAL/"${rg_name}" \ - "${asad_ws}"/LIBRARY \ - "${asad_ws}"/SYSTEM \ - "${asad_ws}"/LANDSCAPE \ - "${asad_ws}"/DEPLOYER/"${rg_name}" + "${asad_ws}"/LOCAL/"${rg_name}" \ + "${asad_ws}"/LIBRARY \ + "${asad_ws}"/SYSTEM \ + "${asad_ws}"/LANDSCAPE \ + "${asad_ws}"/DEPLOYER/"${rg_name}" chown -R "${USER}" "${asad_ws}" @@ -721,53 +721,53 @@ AGENT_DIR="/home/${USER}/agent" # Check if the .agent file exists if [ -f "$AGENT_DIR/.agent" ]; then - devops_extension_installed=$(az extension list --query "[?name=='azure-devops'].name | [0]") - if [ -z "$devops_extension_installed" ]; then - az extension add --name azure-devops --output none - fi + devops_extension_installed=$(az extension list --query "[?name=='azure-devops'].name | [0]") + if [ -z "$devops_extension_installed" ]; then + az extension add --name azure-devops --output none + fi - echo "Azure DevOps Agent is configured." - echo export "PATH=${ansible_bin}:${tf_bin}:${PATH}" | tee -a /tmp/deploy_server.sh + echo "Azure DevOps Agent is configured." + echo export "PATH=${ansible_bin}:${tf_bin}:${PATH}" | tee -a /tmp/deploy_server.sh - devops_extension_installed=$(az extension list --query "[?name=='azure-devops'].name | [0]") - if [ -z "$devops_extension_installed" ]; then - az extension add --name azure-devops --output none - fi + devops_extension_installed=$(az extension list --query "[?name=='azure-devops'].name | [0]") + if [ -z "$devops_extension_installed" ]; then + az extension add --name azure-devops --output none + fi else - echo "Azure DevOps Agent is not configured." - - echo "export SAP_AUTOMATION_REPO_PATH=$HOME/Azure_SAP_Automated_Deployment/sap-automation" | tee -a /tmp/deploy_server.sh - echo "export DEPLOYMENT_REPO_PATH=$HOME/Azure_SAP_Automated_Deployment/sap-automation" | tee -a /tmp/deploy_server.sh - echo "export CONFIG_REPO_PATH=$HOME/Azure_SAP_Automated_Deployment/WORKSPACES" | tee -a /tmp/deploy_server.sh - - echo export "PATH=${ansible_bin}:${tf_bin}:${PATH}:${HOME}/Azure_SAP_Automated_Deployment/sap-automation/deploy/scripts:${HOME}/Azure_SAP_Automated_Deployment/sap-automation/deploy/ansible" | tee -a /tmp/deploy_server.sh - - # Set env for MSI - echo "export ARM_USE_MSI=true" | tee -a /tmp/deploy_server.sh - - /usr/bin/az login --identity 2>error.log || : - # Ensure that the user's account is logged in to Azure with specified creds - - if [ ! -f error.log ]; then - /usr/bin/az account show >az.json - client_id=$(jq --raw-output .id az.json) - tenant_id=$(jq --raw-output .tenantId az.json) - rm az.json - else - client_id='' - tenant_id='' - fi - - if [ -n "${client_id}" ]; then - export ARM_CLIENT_ID=${client_id} - echo "export ARM_CLIENT_ID=${client_id}" | tee -a /tmp/deploy_server.sh - fi - - # if [ -n "${tenant_id}" ]; then - # export ARM_TENANT_ID=${tenant_id} - # echo "export ARM_TENANT_ID=${tenant_id}" | tee -a /tmp/deploy_server.sh - # fi + echo "Azure DevOps Agent is not configured." + + echo "export SAP_AUTOMATION_REPO_PATH=$HOME/Azure_SAP_Automated_Deployment/sap-automation" | tee -a /tmp/deploy_server.sh + echo "export DEPLOYMENT_REPO_PATH=$HOME/Azure_SAP_Automated_Deployment/sap-automation" | tee -a /tmp/deploy_server.sh + echo "export CONFIG_REPO_PATH=$HOME/Azure_SAP_Automated_Deployment/WORKSPACES" | tee -a /tmp/deploy_server.sh + + echo export "PATH=${ansible_bin}:${tf_bin}:${PATH}:${HOME}/Azure_SAP_Automated_Deployment/sap-automation/deploy/scripts:${HOME}/Azure_SAP_Automated_Deployment/sap-automation/deploy/ansible" | tee -a /tmp/deploy_server.sh + + # Set env for MSI + echo "export ARM_USE_MSI=true" | tee -a /tmp/deploy_server.sh + + /usr/bin/az login --identity 2>error.log || : + # Ensure that the user's account is logged in to Azure with specified creds + + if [ ! -f error.log ]; then + /usr/bin/az account show >az.json + client_id=$(jq --raw-output .id az.json) + tenant_id=$(jq --raw-output .tenantId az.json) + rm az.json + else + client_id='' + tenant_id='' + fi + + if [ -n "${client_id}" ]; then + export ARM_CLIENT_ID=${client_id} + echo "export ARM_CLIENT_ID=${client_id}" | tee -a /tmp/deploy_server.sh + fi + + # if [ -n "${tenant_id}" ]; then + # export ARM_TENANT_ID=${tenant_id} + # echo "export ARM_TENANT_ID=${tenant_id}" | tee -a /tmp/deploy_server.sh + # fi fi # Set env for ansible @@ -778,11 +778,11 @@ echo "export BOM_CATALOG=${asad_sample_dir}/SAP" | tee -a /tmp/deploy_server.sh # export DOTNET_ROOT case "$(get_distro_name)" in ubuntu) - echo "export DOTNET_ROOT=/snap/dotnet-sdk/current" | tee -a /tmp/deploy_server.sh - ;; + echo "export DOTNET_ROOT=/snap/dotnet-sdk/current" | tee -a /tmp/deploy_server.sh + ;; sles) - echo "export DOTNET_ROOT=${DOTNET_ROOT}" | tee -a /tmp/deploy_server.sh - ;; + echo "export DOTNET_ROOT=${DOTNET_ROOT}" | tee -a /tmp/deploy_server.sh + ;; rhel*) ;; esac diff --git a/deploy/scripts/deploy_controlplane.sh b/deploy/scripts/deploy_controlplane.sh index 6b5ea5f61e..c6d762e5fa 100755 --- a/deploy/scripts/deploy_controlplane.sh +++ b/deploy/scripts/deploy_controlplane.sh @@ -31,8 +31,8 @@ full_script_path="$(realpath "${BASH_SOURCE[0]}")" script_directory="$(dirname "${full_script_path}")" if [[ -f /etc/profile.d/deploy_server.sh ]]; then - path=$(grep -m 1 "export PATH=" /etc/profile.d/deploy_server.sh | awk -F'=' '{print $2}' | xargs) - export PATH=$path + path=$(grep -m 1 "export PATH=" /etc/profile.d/deploy_server.sh | awk -F'=' '{print $2}' | xargs) + export PATH=$path fi #call stack has full scriptname when using source @@ -43,97 +43,99 @@ source "${script_directory}/helpers/script_helpers.sh" force=0 recover=0 -ado_flag="" +ado_flag="none" deploy_using_msi_only=0 INPUT_ARGUMENTS=$(getopt -n deploy_controlplane -o d:l:s:c:p:t:a:k:ifohrvm --longoptions deployer_parameter_file:,library_parameter_file:,subscription:,spn_id:,spn_secret:,tenant_id:,storageaccountname:,vault:,auto-approve,force,only_deployer,help,recover,ado,msi -- "$@") VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - control_plane_showhelp + control_plane_showhelp fi eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -a | --storageaccountname) - REMOTE_STATE_SA="$2" - shift 2 - ;; - -c | --spn_id) - client_id="$2" - shift 2 - ;; - -d | --deployer_parameter_file) - deployer_parameter_file="$2" - shift 2 - ;; - -k | --vault) - keyvault="$2" - shift 2 - ;; - -l | --library_parameter_file) - library_parameter_file="$2" - shift 2 - ;; - -p | --spn_secret) - spn_secret="$2" - shift 2 - ;; - -s | --subscription) - subscription="$2" - shift 2 - ;; - -t | --tenant_id) - tenant_id="$2" - shift 2 - ;; - -f | --force) - force=1 - shift - ;; - -i | --auto-approve) - approve="--auto-approve" - shift - ;; - -m | --msi) - deploy_using_msi_only=1 - shift - ;; - -o | --only_deployer) - only_deployer=1 - shift - ;; - -r | --recover) - recover=1 - shift - ;; - -v | --ado) - ado_flag="--ado" - shift - ;; - -h | --help) - control_plane_showhelp - exit 3 - ;; - --) - shift - break - ;; - esac + case "$1" in + -a | --storageaccountname) + REMOTE_STATE_SA="$2" + shift 2 + ;; + -c | --spn_id) + client_id="$2" + TF_VAR_spn_id="$client_id" + export TF_VAR_spn_id + shift 2 + ;; + -d | --deployer_parameter_file) + deployer_parameter_file="$2" + shift 2 + ;; + -k | --vault) + keyvault="$2" + shift 2 + ;; + -l | --library_parameter_file) + library_parameter_file="$2" + shift 2 + ;; + -p | --spn_secret) + client_secret="$2" + shift 2 + ;; + -s | --subscription) + subscription="$2" + shift 2 + ;; + -t | --tenant_id) + tenant_id="$2" + shift 2 + ;; + -f | --force) + force=1 + shift + ;; + -i | --auto-approve) + approve="--auto-approve" + shift + ;; + -m | --msi) + deploy_using_msi_only=1 + shift + ;; + -o | --only_deployer) + only_deployer=1 + shift + ;; + -r | --recover) + recover=1 + shift + ;; + -v | --ado) + ado_flag="--ado" + shift + ;; + -h | --help) + control_plane_showhelp + exit 3 + ;; + --) + shift + break + ;; + esac done if [ "$DEBUG" = True ]; then - # Enable debugging - set -x - # Exit on error - set -o errexit + # Enable debugging + set -x + # Exit on error + set -o errexit fi echo "ADO flag: ${ado_flag}" if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then - echo "Approve: Automatically" + echo "Approve: Automatically" fi key=$(basename "${deployer_parameter_file}" | cut -d. -f1) @@ -152,32 +154,32 @@ this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 root_dirname=$(pwd) if [ ! -f /etc/profile.d/deploy_server.sh ]; then - export TF_VAR_Agent_IP=$this_ip + export TF_VAR_Agent_IP=$this_ip fi if [ ! -f "$deployer_parameter_file" ]; then - control_plane_missing 'deployer parameter file' - exit 2 #No such file or directory + control_plane_missing 'deployer parameter file' + exit 2 #No such file or directory fi if [ ! -f "$library_parameter_file" ]; then - control_plane_missing 'library parameter file' - exit 2 #No such file or directory + control_plane_missing 'library parameter file' + exit 2 #No such file or directory fi # Check that Terraform and Azure CLI is installed validate_dependencies return_code=$? if [ 0 != $return_code ]; then - echo "validate_dependencies returned $return_code" - exit $return_code + echo "validate_dependencies returned $return_code" + exit $return_code fi # Check that parameter files have environment and location defined validate_key_parameters "$deployer_parameter_file" if [ 0 != $return_code ]; then - echo "Errors in parameter file" >"${deployer_config_information}".err - exit $return_code + echo "Errors in parameter file" >"${deployer_config_information}".err + exit $return_code fi # Convert the region to the correct code @@ -190,31 +192,36 @@ generic_config_information="${automation_config_directory}"/config deployer_config_information="${automation_config_directory}"/"${environment}""${region_code}" if [ $force == 1 ]; then - if [ -f "${deployer_config_information}" ]; then - rm "${deployer_config_information}" - fi + if [ -f "${deployer_config_information}" ]; then + rm "${deployer_config_information}" + fi fi init "${automation_config_directory}" "${generic_config_information}" "${deployer_config_information}" save_config_var "deployer_tfstate_key" "${deployer_config_information}" +if [ -z "${keyvault}" ]; then + load_config_vars "${deployer_config_information}" "keyvault" +fi + + # Check that the exports ARM_SUBSCRIPTION_ID and SAP_AUTOMATION_REPO_PATH are defined validate_exports return_code=$? if [ 0 != $return_code ]; then - echo "Missing exports" >"${deployer_config_information}".err - exit $return_code + echo "Missing exports" >"${deployer_config_information}".err + exit $return_code fi # Check that webapp exports are defined, if deploying webapp if [ -n "${TF_VAR_use_webapp}" ]; then - if [ "${TF_VAR_use_webapp}" == "true" ]; then - validate_webapp_exports - return_code=$? - if [ 0 != $return_code ]; then - exit $return_code - fi - fi + if [ "${TF_VAR_use_webapp}" == "true" ]; then + validate_webapp_exports + return_code=$? + if [ 0 != $return_code ]; then + exit $return_code + fi + fi fi deployer_dirname=$(dirname "${deployer_parameter_file}") @@ -224,9 +231,15 @@ library_dirname=$(dirname "${library_parameter_file}") library_file_parametername=$(basename "${library_parameter_file}") relative_path="${deployer_dirname}" -export TF_DATA_DIR="${relative_path}"/.terraform +TF_DATA_DIR="${relative_path}"/.terraform +export TF_DATA_DIR + +load_config_vars "${deployer_config_information}" "step" +if [ -z "${step}" ]; then + step=0 +fi +echo "Step: $step" -step=0 echo "" echo "#########################################################################################" echo "# #" @@ -237,212 +250,186 @@ echo "" noAccess=$(az account show --query name | grep "N/A(tenant level account)" || true) if [ -n "$noAccess" ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red The provided credentials do not have access to the subscription!!! $reset_formatting #" - echo "# #" - echo "#########################################################################################" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red The provided credentials do not have access to the subscription!!! $reset_formatting #" + echo "# #" + echo "#########################################################################################" - az account show --output table + az account show --output table - exit 65 + exit 65 fi az account list --query "[].{Name:name,Id:id}" --output table #setting the user environment variables if [ -n "${subscription}" ]; then - if is_valid_guid "$subscription"; then - echo "" - else - printf -v val %-40.40s "$subscription" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided subscription is not valid:$bold_red ${val} $reset_formatting# " - echo "# #" - echo "#########################################################################################" - - echo "The provided subscription is not valid: ${subscription}" >"${deployer_config_information}".err - - exit 65 - fi - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Changing the subscription to: $subscription $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - if [ -z "$keyvault" ]; then - load_config_vars "${deployer_config_information}" "keyvault" - fi - - if [ -n "${keyvault}" ]; then - - kv_found=$(az keyvault list --query "[?name=='$keyvault'].name | [0]" --subscription "${subscription}") - if [ -z "${kv_found}" ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Detected a failed deployment $reset_formatting #" - echo "# #" - echo -e "# $cyan Trying to recover $reset_formatting #" - echo "# #" - echo "#########################################################################################" - step=0 - save_config_var "step" "${deployer_config_information}" - fi - else - step=0 - save_config_var "step" "${deployer_config_information}" - fi -fi - -load_config_vars "${deployer_config_information}" "step" -echo "Step: $step" - -if [ 0 = "${deploy_using_msi_only:-}" ]; then - echo "Identity to use: Service Principal" - unset ARM_USE_MSI - set_executing_user_environment_variables "${spn_secret}" -else - echo "Identity to use: Managed Identity" - set_executing_user_environment_variables "none" -fi - -if [ $recover == 1 ]; then - if [ -n "$REMOTE_STATE_SA" ]; then - save_config_var "REMOTE_STATE_SA" "${deployer_config_information}" - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${deployer_config_information}" - #Support running deploy_controlplane on new host when the resources are already deployed - step=3 - save_config_var "step" "${deployer_config_information}" - fi -fi - -#Persist the parameters -if [ -n "$subscription" ]; then - save_config_var "subscription" "${deployer_config_information}" - export STATE_SUBSCRIPTION=$subscription - save_config_var "STATE_SUBSCRIPTION" "${deployer_config_information}" - export ARM_SUBSCRIPTION_ID=$subscription - save_config_var "ARM_SUBSCRIPTION_ID" "${deployer_config_information}" + if is_valid_guid "$subscription"; then + echo "" + else + printf -v val %-40.40s "$subscription" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided subscription is not valid:$bold_red ${val} $reset_formatting# " + echo "# #" + echo "#########################################################################################" + + echo "The provided subscription is not valid: ${subscription}" >"${deployer_config_information}".err + + exit 65 + fi + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Changing the subscription to: $subscription $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + if [ 0 = "${deploy_using_msi_only:-}" ]; then + echo "Identity to use: Service Principal" + unset ARM_USE_MSI + set_executing_user_environment_variables "${client_secret}" + else + echo "Identity to use: Managed Identity" + set_executing_user_environment_variables "none" + fi + + if [ $recover == 1 ]; then + if [ -n "$REMOTE_STATE_SA" ]; then + save_config_var "REMOTE_STATE_SA" "${deployer_config_information}" + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${deployer_config_information}" + #Support running deploy_controlplane on new host when the resources are already deployed + step=3 + save_config_var "step" "${deployer_config_information}" + fi + fi + + #Persist the parameters + if [ -n "$subscription" ]; then + save_config_var "subscription" "${deployer_config_information}" + export STATE_SUBSCRIPTION=$subscription + save_config_var "STATE_SUBSCRIPTION" "${deployer_config_information}" + export ARM_SUBSCRIPTION_ID=$subscription + save_config_var "ARM_SUBSCRIPTION_ID" "${deployer_config_information}" + fi + + if [ -n "$client_id" ]; then + save_config_var "client_id" "${deployer_config_information}" + fi + + if [ -n "$tenant_id" ]; then + save_config_var "tenant_id" "${deployer_config_information}" + fi + + current_directory=$(pwd) + + ########################################################################################## + # # + # STEP 0 # + # Bootstrapping the deployer # + # # + # # + ########################################################################################## + + if [ 0 == "$step" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Bootstrapping the deployer $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + allParameters=$(printf " --parameterfile %s %s" "${deployer_file_parametername}" "${autoApproveParameter}") + + cd "${deployer_dirname}" || exit + + if [ -n "${FORCE_RESET}" ]; then + step=0 + save_config_var "step" "${deployer_config_information}" + fi + + echo "Calling install_deployer.sh: $allParameters" + echo "Deployer State File: ${deployer_tfstate_key}" + + if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then + + if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/install_deployer.sh" \ + --parameterfile "${deployer_file_parametername}" --auto-approve; then + echo "Bootstrapping of the deployer failed" + step=0 + save_config_var "step" "${deployer_config_information}" + exit 10 + fi + else + if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/install_deployer.sh" \ + --parameterfile "${deployer_file_parametername}"; then + echo "Bootstrapping of the deployer failed" + step=0 + save_config_var "step" "${deployer_config_information}" + exit 10 + fi + fi + return_code=$? + + echo "Return code from install_Deployer: ${return_code}" + if [ 0 != $return_code ]; then + echo "Bootstrapping of the deployer failed" >"${deployer_config_information}".err + exit 10 + else + step=1 + save_config_var "step" "${deployer_config_information}" + + load_config_vars "${deployer_config_information}" "step" + echo "Step: $step" + + if [ 1 = "${only_deployer:-}" ]; then + exit 0 + fi + fi + + load_config_vars "${deployer_config_information}" "keyvault" + echo "Key vault: ${keyvault}" + + if [ -z "$keyvault" ]; then + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Bootstrapping of the deployer failed $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "Bootstrapping of the deployer failed" >"${deployer_config_information}".err + exit 10 + fi + if [ -n "${FORCE_RESET}" ]; then + step=0 + save_config_var "step" "${deployer_config_information}" + exit 0 + else + export step=1 + fi + save_config_var "step" "${deployer_config_information}" + + cd "$root_dirname" || exit + + load_config_vars "${deployer_config_information}" "sshsecret" + load_config_vars "${deployer_config_information}" "keyvault" + load_config_vars "${deployer_config_information}" "deployer_public_ip_address" + + echo "##vso[task.setprogress value=20;]Progress Indicator" + else + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Deployer is bootstrapped $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "##vso[task.setprogress value=20;]Progress Indicator" + fi + + cd "$root_dirname" || exit fi -if [ -n "$client_id" ]; then - save_config_var "client_id" "${deployer_config_information}" -fi - -if [ -n "$tenant_id" ]; then - save_config_var "tenant_id" "${deployer_config_information}" -fi - -curdir=$(pwd) - -########################################################################################## -# # -# STEP 0 # -# Bootstrapping the deployer # -# # -# # -########################################################################################## - -if [ 0 == $step ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Bootstrapping the deployer $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - allParameters=$(printf " --parameterfile %s %s" "${deployer_file_parametername}" "${autoApproveParameter}") - - cd "${deployer_dirname}" || exit - - if [ -n "${FORCE_RESET}" ]; then - step=0 - save_config_var "step" "${deployer_config_information}" - fi - - echo "Calling install_deployer.sh: $allParameters" - echo "Deployer State File: ${deployer_tfstate_key}" - - if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then - - if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/install_deployer.sh" \ - --parameterfile "${deployer_file_parametername}" --auto-approve; then - echo "Bootstrapping of the deployer failed" - step=0 - save_config_var "step" "${deployer_config_information}" - exit 10 - fi - else - if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/install_deployer.sh" \ - --parameterfile "${deployer_file_parametername}"; then - echo "Bootstrapping of the deployer failed" - step=0 - save_config_var "step" "${deployer_config_information}" - exit 10 - fi - fi - return_code=$? - - echo "Return code from install_Deployer: ${return_code}" - if [ 0 != $return_code ]; then - echo "Bootstrapping of the deployer failed" >"${deployer_config_information}".err - exit 10 - else - step=1 - save_config_var "step" "${deployer_config_information}" - - load_config_vars "${deployer_config_information}" "step" - echo "Step: $step" - - if [ 1 = "${only_deployer:-}" ]; then - exit 0 - fi - fi - - load_config_vars "${deployer_config_information}" "keyvault" - echo "Key vault: ${keyvault}" - - if [ -z "$keyvault" ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Bootstrapping of the deployer failed $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "Bootstrapping of the deployer failed" >"${deployer_config_information}".err - exit 10 - fi - if [ -n "${FORCE_RESET}" ]; then - step=0 - save_config_var "step" "${deployer_config_information}" - exit 0 - else - export step=1 - fi - save_config_var "step" "${deployer_config_information}" - - cd "$root_dirname" || exit - - load_config_vars "${deployer_config_information}" "sshsecret" - load_config_vars "${deployer_config_information}" "keyvault" - load_config_vars "${deployer_config_information}" "deployer_public_ip_address" - - echo "##vso[task.setprogress value=20;]Progress Indicator" -else - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Deployer is bootstrapped $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "##vso[task.setprogress value=20;]Progress Indicator" -fi - -cd "$root_dirname" || exit - ########################################################################################## # # # Step 1 # @@ -453,54 +440,114 @@ cd "$root_dirname" || exit echo "Step: $step" +TF_DATA_DIR="${deployer_dirname}"/.terraform +export TF_DATA_DIR + +cd "${deployer_dirname}" || exit + if [ 1 == $step ] || [ 3 == $step ]; then - # If the keyvault is not set, check the terraform state file - if [ -z "$keyvault" ]; then - key=$(echo "${deployer_file_parametername}" | cut -d. -f1) - if [ $recover == 1 ] && [ -n "$REMOTE_STATE_SA" ]; then - terraform_module_directory="$SAP_AUTOMATION_REPO_PATH"/deploy/terraform/run/sap_deployer/ - terraform -chdir="${terraform_module_directory}" init -upgrade=true \ - --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ - --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ - --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate" - - keyvault=$(terraform -chdir="${terraform_module_directory}" output deployer_kv_user_name | tr -d \") - fi - fi - - if [ -z "$keyvault" ]; then - if [ $ado_flag != "--ado" ]; then - read -r -p "Deployer keyvault name: " keyvault - else - exit 10 - fi - fi + # If the keyvault is not set, check the terraform state file + if [ -z "$keyvault" ]; then + key=$(echo "${deployer_file_parametername}" | cut -d. -f1) + cd "${deployer_dirname}" || exit + if [ -f ./.terraform/terraform.tfstate ]; then + azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) + if [ -n "$azure_backend" ]; then + + terraform_module_directory="$SAP_AUTOMATION_REPO_PATH"/deploy/terraform/run/sap_deployer/ + terraform -chdir="${terraform_module_directory}" init -upgrade=true + + keyvault=$(terraform -chdir="${terraform_module_directory}" output deployer_kv_user_name | tr -d \") + save_config_var "keyvault" "${deployer_config_information}" + fi + fi + fi + + if [ -z "$keyvault" ]; then + if [ $ado_flag != "--ado" ]; then + read -r -p "Deployer keyvault name: " keyvault + else + exit 10 + fi + fi + + if [ 1 == $step ] && [ -n "$client_secret" ]; then + + if "${SAP_AUTOMATION_REPO_PATH}"/deploy/scripts/set_secrets.sh \ + --environment "${environment}" \ + --region "${region_code}" \ + --vault "${keyvault}" \ + --spn_id "${client_id}" \ + --spn_secret "${client_secret}" \ + --tenant_id "${tenant_id}"; then + echo "" + echo -e "${cyan}Set secrets: succeeded$reset_formatting" + echo "" + else + echo -e "${bold_red}Set secrets: succeeded$failed" + exit 10 + fi + fi + +fi + +if [ -z "$keyvault" ]; then + load_config_vars "${deployer_config_information}" "keyvault" +fi + +if [ -n "${keyvault}" ] && [ 0 != "$step" ]; then + + echo "Checking for keyvault: ${keyvault}" + + kv_found=$(az keyvault show --name="$keyvault" --subscription "${subscription}" --query name) + if [ -z "${kv_found}" ]; then + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Detected a failed deployment $reset_formatting #" + echo "# #" + echo "# #" + echo "#########################################################################################" + exit 10 + else + TF_VAR_deployer_kv_user_arm_id=$(az keyvault show --name="$keyvault" --subscription "${subscription}" --query id) + export TF_VAR_deployer_kv_user_arm_id + fi +else + if [ $ado_flag != "--ado" ]; then + read -r -p "Deployer keyvault name: " keyvault + save_config_var "keyvault" "${deployer_config_information}" + else + step=0 + save_config_var "step" "${deployer_config_information}" + exit 10 + fi + fi unset TF_DATA_DIR cd "$root_dirname" || exit -if validate_key_vault "$keyvault"; then - echo "Key vault: ${keyvault}" - save_config_var "keyvault" "${deployer_config_information}" - if [ 1 == $step ]; then - export step=2 - save_config_var "step" "${deployer_config_information}" - fi +az account set --subscription "$ARM_SUBSCRIPTION_ID" + +if validate_key_vault "$keyvault" "$ARM_SUBSCRIPTION_ID"; then + echo "Key vault: ${keyvault}" + save_config_var "keyvault" "${deployer_config_information}" + if [ 1 == $step ]; then + export step=2 + save_config_var "step" "${deployer_config_information}" + fi else - return_code=$? - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Key vault not found $reset_formatting #" - echo "# #" - echo "#########################################################################################" - exit $return_code - step=1 - save_config_var "step" "${deployer_config_information}" + return_code=$? + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Key vault not found $reset_formatting #" + echo "# #" + echo "#########################################################################################" + exit $return_code + step=1 + save_config_var "step" "${deployer_config_information}" fi ########################################################################################## @@ -512,89 +559,96 @@ fi ########################################################################################## if [ 2 == $step ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Bootstrapping the library $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - relative_path="${library_dirname}" - export TF_DATA_DIR="${relative_path}/.terraform" - relative_path="${deployer_dirname}" - - cd "${library_dirname}" || exit - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_library/ - - if [ $force == 1 ]; then - rm -Rf .terraform terraform.tfstate* - fi - - echo "Calling install_library.sh with: --parameterfile ${library_file_parametername} --deployer_statefile_foldername ${relative_path} --keyvault ${keyvault} ${autoApproveParameter}" - - if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then - - if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/install_library.sh" \ - --parameterfile "${library_file_parametername}" \ - --deployer_statefile_foldername "${relative_path}" \ - --keyvault "${keyvault}" --auto-approve; then - echo "Bootstrapping of the SAP Library failed" - step=2 - save_config_var "step" "${deployer_config_information}" - exit 20 - fi - else - if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/install_library.sh" \ - --parameterfile "${library_file_parametername}" \ - --deployer_statefile_foldername "${relative_path}" \ - --keyvault "${keyvault}"; then - echo "Bootstrapping of the SAP Library failed" - step=2 - save_config_var "step" "${deployer_config_information}" - exit 20 - fi - fi - return_code=$? - if [ -z "$REMOTE_STATE_SA" ]; then - REMOTE_STATE_RG=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sapbits_sa_resource_group_name | tr -d \") - fi - if [ -z "$REMOTE_STATE_SA" ]; then - REMOTE_STATE_SA=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw remote_state_storage_account_name | tr -d \") - fi - if [ -z "$STATE_SUBSCRIPTION" ]; then - STATE_SUBSCRIPTION=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_subscription_id | tr -d \") - fi - - if [ "${ado_flag}" != "--ado" ]; then - az storage account network-rule add -g "${REMOTE_STATE_RG}" --account-name "${REMOTE_STATE_SA}" --ip-address "${this_ip}" --output none - fi - - TF_VAR_sa_connection_string=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sa_connection_string | tr -d \") - export TF_VAR_sa_connection_string - - if [ -n "${tfstate_resource_id}" ]; then - TF_VAR_tfstate_resource_id="${tfstate_resource_id}" - export TF_VAR_tfstate_resource_id - else - tfstate_resource_id=$(az resource list --name "$REMOTE_STATE_SA" --subscription "$STATE_SUBSCRIPTION" --resource-type Microsoft.Storage/storageAccounts --query "[].id | [0]" -o tsv) - TF_VAR_tfstate_resource_id=$tfstate_resource_id - fi - export TF_VAR_tfstate_resource_id - - cd "${curdir}" || exit - save_config_var "step" "${deployer_config_information}" - echo "##vso[task.setprogress value=60;]Progress Indicator" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Bootstrapping the library $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + relative_path="${library_dirname}" + export TF_DATA_DIR="${relative_path}/.terraform" + relative_path="${deployer_dirname}" + + cd "${library_dirname}" || exit + terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_library/ + + if [ $force == 1 ]; then + rm -Rf .terraform terraform.tfstate* + fi + + echo "Calling install_library.sh with: --parameterfile ${library_file_parametername} --deployer_statefile_foldername ${relative_path} --keyvault ${keyvault} ${autoApproveParameter}" + + if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then + + if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/install_library.sh" \ + --parameterfile "${library_file_parametername}" \ + --deployer_statefile_foldername "${relative_path}" \ + --keyvault "${keyvault}" --auto-approve; then + echo "Bootstrapping of the SAP Library failed" + step=2 + save_config_var "step" "${deployer_config_information}" + exit 20 + else + step=3 + save_config_var "step" "${deployer_config_information}" + + fi + else + if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/install_library.sh" \ + --parameterfile "${library_file_parametername}" \ + --deployer_statefile_foldername "${relative_path}" \ + --keyvault "${keyvault}"; then + echo "Bootstrapping of the SAP Library failed" + step=2 + save_config_var "step" "${deployer_config_information}" + exit 20 + else + step=3 + save_config_var "step" "${deployer_config_information}" + fi + fi + return_code=$? + if [ -z "$REMOTE_STATE_SA" ]; then + REMOTE_STATE_RG=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sapbits_sa_resource_group_name | tr -d \") + fi + if [ -z "$REMOTE_STATE_SA" ]; then + REMOTE_STATE_SA=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw remote_state_storage_account_name | tr -d \") + fi + if [ -z "$STATE_SUBSCRIPTION" ]; then + STATE_SUBSCRIPTION=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_subscription_id | tr -d \") + fi + + if [ "${ado_flag}" != "--ado" ]; then + az storage account network-rule add -g "${REMOTE_STATE_RG}" --account-name "${REMOTE_STATE_SA}" --ip-address "${this_ip}" --output none + fi + + TF_VAR_sa_connection_string=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sa_connection_string | tr -d \") + export TF_VAR_sa_connection_string + + if [ -n "${tfstate_resource_id}" ]; then + TF_VAR_tfstate_resource_id="${tfstate_resource_id}" + export TF_VAR_tfstate_resource_id + else + tfstate_resource_id=$(az resource list --name "$REMOTE_STATE_SA" --subscription "$STATE_SUBSCRIPTION" --resource-type Microsoft.Storage/storageAccounts --query "[].id | [0]" -o tsv) + TF_VAR_tfstate_resource_id=$tfstate_resource_id + fi + export TF_VAR_tfstate_resource_id + + cd "${current_directory}" || exit + save_config_var "step" "${deployer_config_information}" + echo "##vso[task.setprogress value=60;]Progress Indicator" else - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Library is bootstrapped $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "##vso[task.setprogress value=60;]Progress Indicator" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Library is bootstrapped $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "##vso[task.setprogress value=60;]Progress Indicator" fi @@ -610,97 +664,88 @@ echo "##vso[task.setprogress value=80;]Progress Indicator" # # ########################################################################################## -if [ 3 == $step ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Migrating the deployer state $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - cd "${deployer_dirname}" || exit - - # Remove the script file - if [ -f post_deployment.sh ]; then - rm post_deployment.sh - fi - - secretname=sa-connection-string - deleted=$(az keyvault secret list-deleted --vault-name "${keyvault}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" | tr -d \") - if [ "${deleted}" == "${secretname}" ]; then - echo -e "\t $cyan Recovering secret ${secretname} in keyvault ${keyvault} $reset_formatting \n" - az keyvault secret recover --name "${secretname}" --vault-name "${keyvault}" - sleep 10 - fi - - v="" - secret=$(az keyvault secret list --vault-name "${keyvault}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" | tr -d \") - if [ "${secret}" == "${secretname}" ]; then - TF_VAR_sa_connection_string=$(az keyvault secret show --name "${secretname}" --vault-name "${keyvault}" --query value | tr -d \") - export TF_VAR_sa_connection_string - - fi - - if [[ -z $REMOTE_STATE_SA ]]; then - load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" - fi - - if [[ -z $STATE_SUBSCRIPTION ]]; then - load_config_vars "${deployer_config_information}" "STATE_SUBSCRIPTION" - fi - - if [[ -z $ARM_SUBSCRIPTION_ID ]]; then - load_config_vars "${deployer_config_information}" "ARM_SUBSCRIPTION_ID" - fi - - if [ -z "${REMOTE_STATE_SA}" ]; then - export step=2 - save_config_var "step" "${deployer_config_information}" - echo "##vso[task.setprogress value=40;]Progress Indicator" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Could not find the SAP Library, please re-run! $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 11 - - fi - - echo "Calling installer.sh with: --parameterfile ${deployer_file_parametername} \ +if [ 3 == "$step" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Migrating the deployer state $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + cd "${deployer_dirname}" || exit + + # Remove the script file + if [ -f post_deployment.sh ]; then + rm post_deployment.sh + fi + + if [[ -z $REMOTE_STATE_SA ]]; then + load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" + fi + + if [[ -z $STATE_SUBSCRIPTION ]]; then + load_config_vars "${deployer_config_information}" "STATE_SUBSCRIPTION" + fi + + if [[ -z $ARM_SUBSCRIPTION_ID ]]; then + load_config_vars "${deployer_config_information}" "ARM_SUBSCRIPTION_ID" + fi + + if [ -z "${REMOTE_STATE_SA}" ]; then + export step=2 + save_config_var "step" "${deployer_config_information}" + echo "##vso[task.setprogress value=40;]Progress Indicator" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Could not find the SAP Library, please re-run! $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 11 + + fi + + echo "Calling installer.sh with: --parameterfile ${deployer_file_parametername} \ --storageaccountname ${REMOTE_STATE_SA} --state_subscription ${STATE_SUBSCRIPTION} --type sap_deployer ${autoApproveParameter} ${ado_flag}" - if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then - - if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/installer.sh" \ - --type sap_deployer \ - --parameterfile ${deployer_file_parametername} \ - --storageaccountname "${REMOTE_STATE_SA}" \ - $ado_flag \ - --auto-approve; then - echo "Migrating the Deployer state failed" - step=3 - save_config_var "step" "${deployer_config_information}" - exit 30 - fi - else - if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/installer.sh" \ - --type sap_deployer \ - --parameterfile ${deployer_file_parametername} \ - --storageaccountname "${REMOTE_STATE_SA}"; then - echo "Migrating the SAP Library state failed" - step=3 - save_config_var "step" "${deployer_config_information}" - exit 30 - fi - fi - return_code=$? - - cd "${curdir}" || exit - export step=4 - save_config_var "step" "${deployer_config_information}" + if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then + + if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/installer.sh" \ + --type sap_deployer \ + --parameterfile ${deployer_file_parametername} \ + --storageaccountname "${REMOTE_STATE_SA}" \ + $ado_flag \ + --auto-approve; then + echo "Migrating the Deployer state failed" + step=3 + save_config_var "step" "${deployer_config_information}" + exit 30 + else + step=4 + save_config_var "step" "${deployer_config_information}" + + fi + else + if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/installer.sh" \ + --type sap_deployer \ + --parameterfile ${deployer_file_parametername} \ + --storageaccountname "${REMOTE_STATE_SA}"; then + echo "Migrating the SAP Library state failed" + step=3 + save_config_var "step" "${deployer_config_information}" + exit 30 + else + step=4 + save_config_var "step" "${deployer_config_information}" + fi + fi + return_code=$? + + cd "${current_directory}" || exit + export step=4 + save_config_var "step" "${deployer_config_information}" fi @@ -720,55 +765,55 @@ load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" ########################################################################################## if [ 4 == $step ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Migrating the library state $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - terraform_module_directory="$SAP_AUTOMATION_REPO_PATH"/deploy/terraform/run/sap_library/ - cd "${library_dirname}" || exit - - echo "Calling installer.sh with: \ + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Migrating the library state $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + terraform_module_directory="$SAP_AUTOMATION_REPO_PATH"/deploy/terraform/run/sap_library/ + cd "${library_dirname}" || exit + + echo "Calling installer.sh with: \ --type sap_library \ --parameterfile ${library_file_parametername} \ --storageaccountname ${REMOTE_STATE_SA} \ --deployer_tfstate_key ${deployer_tfstate_key}" - if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then - - if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/installer.sh" \ - --type sap_library \ - --parameterfile "${library_file_parametername}" \ - --storageaccountname "${REMOTE_STATE_SA}" \ - --deployer_tfstate_key "${deployer_tfstate_key}" \ - $ado_flag \ - --auto-approve; then - echo "Migrating the SAP Library state failed" - step=4 - save_config_var "step" "${deployer_config_information}" - exit 40 - fi - else - if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/installer.sh" \ - --type sap_library \ - --parameterfile "${library_file_parametername}" \ - --storageaccountname "${REMOTE_STATE_SA}" \ - --deployer_tfstate_key "${deployer_tfstate_key}"; then - echo "Migrating the SAP Library state failed" - step=4 - save_config_var "step" "${deployer_config_information}" - exit 40 - fi - fi - return_code=$? - - cd "$root_dirname" || exit - - step=5 - save_config_var "step" "${deployer_config_information}" + if [ "$ado_flag" == "--ado" ] || [ "$approve" == "--auto-approve" ]; then + + if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/installer.sh" \ + --type sap_library \ + --parameterfile "${library_file_parametername}" \ + --storageaccountname "${REMOTE_STATE_SA}" \ + --deployer_tfstate_key "${deployer_tfstate_key}" \ + $ado_flag \ + --auto-approve; then + echo "Migrating the SAP Library state failed" + step=4 + save_config_var "step" "${deployer_config_information}" + exit 40 + fi + else + if ! "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/installer.sh" \ + --type sap_library \ + --parameterfile "${library_file_parametername}" \ + --storageaccountname "${REMOTE_STATE_SA}" \ + --deployer_tfstate_key "${deployer_tfstate_key}"; then + echo "Migrating the SAP Library state failed" + step=4 + save_config_var "step" "${deployer_config_information}" + exit 40 + fi + fi + return_code=$? + + cd "$root_dirname" || exit + + step=5 + save_config_var "step" "${deployer_config_information}" fi printf -v kvname '%-40s' "${keyvault}" @@ -808,58 +853,58 @@ deployer_keyvault="${keyvault}" export deployer_keyvault if [ -n "${deployer_public_ip_address}" ]; then - deployer_ip="${deployer_public_ip_address}" - export deployer_ip + deployer_ip="${deployer_public_ip_address}" + export deployer_ip fi terraform_state_storage_account="${REMOTE_STATE_SA}" export terraform_state_storage_account if [ 5 == $step ]; then - if [ "${ado_flag}" != "--ado" ]; then - cd "${curdir}" || exit - - load_config_vars "${deployer_config_information}" "sshsecret" - load_config_vars "${deployer_config_information}" "keyvault" - load_config_vars "${deployer_config_information}" "deployer_public_ip_address" - if [ ! -f /etc/profile.d/deploy_server.sh ]; then - # Only run this when not on deployer - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Copying the parameterfiles $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - if [ -n "${sshsecret}" ]; then - step=3 - save_config_var "step" "${deployer_config_information}" - printf "%s\n" "Collecting secrets from KV" - temp_file=$(mktemp) - ppk=$(az keyvault secret show --vault-name "${keyvault}" --name "${sshsecret}" | jq -r .value) - echo "${ppk}" >"${temp_file}" - chmod 600 "${temp_file}" - - remote_deployer_dir="/home/azureadm/Azure_SAP_Automated_Deployment/WORKSPACES/"$(dirname "$deployer_parameter_file") - remote_library_dir="/home/azureadm/Azure_SAP_Automated_Deployment/WORKSPACES/"$(dirname "$library_parameter_file") - remote_config_dir="$CONFIG_REPO_PATH/.sap_deployment_automation" - - ssh -i "${temp_file}" -o StrictHostKeyChecking=no -o ConnectTimeout=10 azureadm@"${deployer_public_ip_address}" "mkdir -p ${remote_deployer_dir}"/.terraform 2>/dev/null - scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$deployer_parameter_file" azureadm@"${deployer_public_ip_address}":"${remote_deployer_dir}"/. 2>/dev/null - scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$(dirname "$deployer_parameter_file")"/.terraform/terraform.tfstate azureadm@"${deployer_public_ip_address}":"${remote_deployer_dir}"/.terraform/terraform.tfstate 2>/dev/null - scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$(dirname "$deployer_parameter_file")"/terraform.tfstate azureadm@"${deployer_public_ip_address}":"${remote_deployer_dir}"/terraform.tfstate 2>/dev/null - - ssh -i "${temp_file}" -o StrictHostKeyChecking=no -o ConnectTimeout=10 azureadm@"${deployer_public_ip_address}" " mkdir -p ${remote_library_dir}"/.terraform 2>/dev/null - scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$(dirname "$deployer_parameter_file")"/.terraform/terraform.tfstate azureadm@"${deployer_public_ip_address}":"${remote_deployer_dir}"/. 2>/dev/null - scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$library_parameter_file" azureadm@"${deployer_public_ip_address}":"$remote_library_dir"/. 2>/dev/null - - ssh -i "${temp_file}" -o StrictHostKeyChecking=no -o ConnectTimeout=10 azureadm@"${deployer_public_ip_address}" "mkdir -p ${remote_config_dir}" 2>/dev/null - scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "${deployer_config_information}" azureadm@"${deployer_public_ip_address}":"${remote_config_dir}"/. 2>/dev/null - rm "${temp_file}" - fi - fi - - fi + if [ "${ado_flag}" != "--ado" ]; then + cd "${current_directory}" || exit + + load_config_vars "${deployer_config_information}" "sshsecret" + load_config_vars "${deployer_config_information}" "keyvault" + load_config_vars "${deployer_config_information}" "deployer_public_ip_address" + if [ ! -f /etc/profile.d/deploy_server.sh ]; then + # Only run this when not on deployer + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Copying the parameterfiles $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + if [ -n "${sshsecret}" ]; then + step=3 + save_config_var "step" "${deployer_config_information}" + printf "%s\n" "Collecting secrets from KV" + temp_file=$(mktemp) + ppk=$(az keyvault secret show --vault-name "${keyvault}" --name "${sshsecret}" | jq -r .value) + echo "${ppk}" >"${temp_file}" + chmod 600 "${temp_file}" + + remote_deployer_dir="/home/azureadm/Azure_SAP_Automated_Deployment/WORKSPACES/"$(dirname "$deployer_parameter_file") + remote_library_dir="/home/azureadm/Azure_SAP_Automated_Deployment/WORKSPACES/"$(dirname "$library_parameter_file") + remote_config_dir="$CONFIG_REPO_PATH/.sap_deployment_automation" + + ssh -i "${temp_file}" -o StrictHostKeyChecking=no -o ConnectTimeout=10 azureadm@"${deployer_public_ip_address}" "mkdir -p ${remote_deployer_dir}"/.terraform 2>/dev/null + scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$deployer_parameter_file" azureadm@"${deployer_public_ip_address}":"${remote_deployer_dir}"/. 2>/dev/null + scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$(dirname "$deployer_parameter_file")"/.terraform/terraform.tfstate azureadm@"${deployer_public_ip_address}":"${remote_deployer_dir}"/.terraform/terraform.tfstate 2>/dev/null + scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$(dirname "$deployer_parameter_file")"/terraform.tfstate azureadm@"${deployer_public_ip_address}":"${remote_deployer_dir}"/terraform.tfstate 2>/dev/null + + ssh -i "${temp_file}" -o StrictHostKeyChecking=no -o ConnectTimeout=10 azureadm@"${deployer_public_ip_address}" " mkdir -p ${remote_library_dir}"/.terraform 2>/dev/null + scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$(dirname "$deployer_parameter_file")"/.terraform/terraform.tfstate azureadm@"${deployer_public_ip_address}":"${remote_deployer_dir}"/. 2>/dev/null + scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "$library_parameter_file" azureadm@"${deployer_public_ip_address}":"$remote_library_dir"/. 2>/dev/null + + ssh -i "${temp_file}" -o StrictHostKeyChecking=no -o ConnectTimeout=10 azureadm@"${deployer_public_ip_address}" "mkdir -p ${remote_config_dir}" 2>/dev/null + scp -i "${temp_file}" -q -o StrictHostKeyChecking=no -o ConnectTimeout=120 -p "${deployer_config_information}" azureadm@"${deployer_public_ip_address}":"${remote_config_dir}"/. 2>/dev/null + rm "${temp_file}" + fi + fi + + fi fi step=3 diff --git a/deploy/scripts/helpers/script_helpers.sh b/deploy/scripts/helpers/script_helpers.sh index d0faf0b961..e9c15af158 100755 --- a/deploy/scripts/helpers/script_helpers.sh +++ b/deploy/scripts/helpers/script_helpers.sh @@ -13,620 +13,643 @@ script_directory_parent="$(dirname "${script_directory}")" source "${script_directory_parent}"/deploy_utils.sh if [[ -f /etc/profile.d/deploy_server.sh ]]; then - path=$(grep -m 1 "export PATH=" /etc/profile.d/deploy_server.sh | awk -F'=' '{print $2}' | xargs) - export PATH=$PATH:$path + path=$(grep -m 1 "export PATH=" /etc/profile.d/deploy_server.sh | awk -F'=' '{print $2}' | xargs) + export PATH=$PATH:$path fi function control_plane_showhelp { - echo "" - echo "#################################################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to prepare an Azure region to support the SAP Deployment Automation by #" - echo "# preparing the deployer and the library. #" - echo "# The script experts the following exports: #" - echo "# #" - echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" - echo "# #" - echo "# The script is to be run from a parent folder to the folders containing the json parameter files for #" - echo "# the deployer and the library and the environment. #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" - echo "# #" - echo "# #" - echo "# Usage: deploy_controlplane.sh #" - echo "# -d or --deployer_parameter_file deployer parameter file #" - echo "# -l or --library_parameter_file library parameter file #" - echo "# #" - echo "# Optional parameters #" - echo "# -s or --subscription subscription #" - echo "# -c or --spn_id SPN application id #" - echo "# -p or --spn_secret SPN password #" - echo "# -t or --tenant_id SPN Tenant id #" - echo "# -f or --force Clean up the local Terraform files. #" - echo "# -i or --auto-approve Silent install #" - echo "# -h or --help Help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# \$SAP_AUTOMATION_REPO_PATH/scripts/deploy_controlplane.sh \ #" - echo "# --deployer_parameter_file DEPLOYER/MGMT-WEEU-DEP00-INFRASTRUCTURE/MGMT-WEEU-DEP00-INFRASTRUCTURE.json \ #" - echo "# --library_parameter_file LIBRARY/MGMT-WEEU-SAP_LIBRARY/MGMT-WEEU-SAP_LIBRARY.json \ #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# \$SAP_AUTOMATION_REPO_PATH/scripts/deploy_controlplane.sh \ #" - echo "# --deployer_parameter_file DEPLOYER/PROD-WEEU-DEP00-INFRASTRUCTURE/PROD-WEEU-DEP00-INFRASTRUCTURE.json \ #" - echo "# --library_parameter_file LIBRARY/PROD-WEEU-SAP_LIBRARY/PROD-WEEU-SAP_LIBRARY.json \ #" - echo "# --subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ #" - echo "# --spn_id yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy \ #" - echo "# --spn_secret ************************ \ #" - echo "# --tenant_id zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz \ #" - echo "# --auto-approve #" - echo "# #" - echo "#################################################################################################################" + echo "" + echo "#################################################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to prepare an Azure region to support the SAP Deployment Automation by #" + echo "# preparing the deployer and the library. #" + echo "# The script experts the following exports: #" + echo "# #" + echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" + echo "# #" + echo "# The script is to be run from a parent folder to the folders containing the json parameter files for #" + echo "# the deployer and the library and the environment. #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" + echo "# #" + echo "# #" + echo "# Usage: deploy_controlplane.sh #" + echo "# -d or --deployer_parameter_file deployer parameter file #" + echo "# -l or --library_parameter_file library parameter file #" + echo "# #" + echo "# Optional parameters #" + echo "# -s or --subscription subscription #" + echo "# -c or --spn_id SPN application id #" + echo "# -p or --spn_secret SPN password #" + echo "# -t or --tenant_id SPN Tenant id #" + echo "# -f or --force Clean up the local Terraform files. #" + echo "# -i or --auto-approve Silent install #" + echo "# -h or --help Help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# \$SAP_AUTOMATION_REPO_PATH/scripts/deploy_controlplane.sh \ #" + echo "# --deployer_parameter_file DEPLOYER/MGMT-WEEU-DEP00-INFRASTRUCTURE/MGMT-WEEU-DEP00-INFRASTRUCTURE.json \ #" + echo "# --library_parameter_file LIBRARY/MGMT-WEEU-SAP_LIBRARY/MGMT-WEEU-SAP_LIBRARY.json \ #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# \$SAP_AUTOMATION_REPO_PATH/scripts/deploy_controlplane.sh \ #" + echo "# --deployer_parameter_file DEPLOYER/PROD-WEEU-DEP00-INFRASTRUCTURE/PROD-WEEU-DEP00-INFRASTRUCTURE.json \ #" + echo "# --library_parameter_file LIBRARY/PROD-WEEU-SAP_LIBRARY/PROD-WEEU-SAP_LIBRARY.json \ #" + echo "# --subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ #" + echo "# --spn_id yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy \ #" + echo "# --spn_secret ************************ \ #" + echo "# --tenant_id zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz \ #" + echo "# --auto-approve #" + echo "# #" + echo "#################################################################################################################" } function control_plane_missing { - printf -v val '%-40s' "$1" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Missing : ${val} #" - echo "# #" - echo "# Usage: deploy_controlplane.sh #" - echo "# -d or --deployer_parameter_file deployer parameter file #" - echo "# -l or --library_parameter_file library parameter file #" - echo "# #" - echo "# Optional parameters #" - echo "# -s or --subscription subscription #" - echo "# -c or --spn_id SPN application id #" - echo "# -p or --spn_secret SPN password #" - echo "# -t or --tenant_id SPN Tenant id #" - echo "# -f or --force Clean up the local Terraform files. #" - echo "# -i or --auto-approve Silent install #" - echo "# -h or --help Help #" - echo "# #" - echo "#########################################################################################" + printf -v val '%-40s' "$1" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Missing : ${val} #" + echo "# #" + echo "# Usage: deploy_controlplane.sh #" + echo "# -d or --deployer_parameter_file deployer parameter file #" + echo "# -l or --library_parameter_file library parameter file #" + echo "# #" + echo "# Optional parameters #" + echo "# -s or --subscription subscription #" + echo "# -c or --spn_id SPN application id #" + echo "# -p or --spn_secret SPN password #" + echo "# -t or --tenant_id SPN Tenant id #" + echo "# -f or --force Clean up the local Terraform files. #" + echo "# -i or --auto-approve Silent install #" + echo "# -h or --help Help #" + echo "# #" + echo "#########################################################################################" } function workload_zone_showhelp { - echo "" - echo "###############################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to deploy the workload infrastructure to Azure #" - echo "# #" - echo "# The script experts the following exports: #" - echo "# #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" - echo "# #" - echo "# The script is to be run from the folder containing the json parameter file #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" - echo "# #" - echo "# Usage: install_workloadzone.sh #" - echo "# -p or --parameterfile deployer parameter file #" - echo "# #" - echo "# Optional parameters #" - echo "# -d or --deployer_tfstate_key Deployer terraform state file name #" - echo "# -e or --deployer_environment Deployer environment, i.e. MGMT #" - echo "# -s or --subscription subscription #" - echo "# -k or --state_subscription subscription for statefile #" - echo "# -c or --spn_id SPN application id #" - echo "# -p or --spn_secret SPN password #" - echo "# -t or --tenant_id SPN Tenant id #" - echo "# -f or --force Clean up the local Terraform files. #" - echo "# -i or --auto-approve Silent install #" - echo "# -h or --help Help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/install_workloadzone.sh \ #" - echo "# --parameterfile PROD-WEEU-SAP01-INFRASTRUCTURE #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/install_workloadzone.sh \ #" - echo "# --parameterfile PROD-WEEU-SAP01-INFRASTRUCTURE \ #" - echo "# --deployer_environment MGMT \ #" - echo "# --subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ #" - echo "# --spn_id yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy \ #" - echo "# --spn_secret ************************ \ #" - echo "# --spn_secret yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy \ #" - echo "# --tenant_id zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz \ #" - echo "# --auto-approve #" - echo "##############################################################################################" + echo "" + echo "###############################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to deploy the workload infrastructure to Azure #" + echo "# #" + echo "# The script experts the following exports: #" + echo "# #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" + echo "# #" + echo "# The script is to be run from the folder containing the json parameter file #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" + echo "# #" + echo "# Usage: install_workloadzone.sh #" + echo "# -p or --parameterfile deployer parameter file #" + echo "# #" + echo "# Optional parameters #" + echo "# -d or --deployer_tfstate_key Deployer terraform state file name #" + echo "# -e or --deployer_environment Deployer environment, i.e. MGMT #" + echo "# -s or --subscription subscription #" + echo "# -k or --state_subscription subscription for statefile #" + echo "# -c or --spn_id SPN application id #" + echo "# -p or --spn_secret SPN password #" + echo "# -t or --tenant_id SPN Tenant id #" + echo "# -f or --force Clean up the local Terraform files. #" + echo "# -i or --auto-approve Silent install #" + echo "# -h or --help Help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/install_workloadzone.sh \ #" + echo "# --parameterfile PROD-WEEU-SAP01-INFRASTRUCTURE #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/install_workloadzone.sh \ #" + echo "# --parameterfile PROD-WEEU-SAP01-INFRASTRUCTURE \ #" + echo "# --deployer_environment MGMT \ #" + echo "# --subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ #" + echo "# --spn_id yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy \ #" + echo "# --spn_secret ************************ \ #" + echo "# --spn_secret yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy \ #" + echo "# --tenant_id zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz \ #" + echo "# --auto-approve #" + echo "##############################################################################################" } function workload_zone_missing { - printf -v val %-.40s "$1" - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Missing environment variables: ${val}!!! #" - echo "# #" - echo "# Please export the folloing variables: #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" - echo "# #" - echo "# Usage: install_workloadzone.sh #" - echo "# -p or --parameterfile deployer parameter file #" - echo "# #" - echo "# Optional parameters #" - echo "# -d or --deployer_tfstate_key Deployer terraform state file name #" - echo "# -e or --deployer_environment Deployer environment, i.e. MGMT #" - echo "# -k or --state_subscription subscription of keyvault with SPN details #" - echo "# -v or --keyvault Name of Azure keyvault with SPN details #" - echo "# -s or --subscription subscription #" - echo "# -c or --spn_id SPN application id #" - echo "# -o or --storageaccountname Storage account for terraform state files #" - echo "# -n or --spn_secret SPN password #" - echo "# -t or --tenant_id SPN Tenant id #" - echo "# -f or --force Clean up the local Terraform files. #" - echo "# -i or --auto-approve Silent install #" - echo "# -h or --help Help #" - echo "#########################################################################################" + printf -v val %-.40s "$1" + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Missing environment variables: ${val}!!! #" + echo "# #" + echo "# Please export the folloing variables: #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" + echo "# #" + echo "# Usage: install_workloadzone.sh #" + echo "# -p or --parameterfile deployer parameter file #" + echo "# #" + echo "# Optional parameters #" + echo "# -d or --deployer_tfstate_key Deployer terraform state file name #" + echo "# -e or --deployer_environment Deployer environment, i.e. MGMT #" + echo "# -k or --state_subscription subscription of keyvault with SPN details #" + echo "# -v or --keyvault Name of Azure keyvault with SPN details #" + echo "# -s or --subscription subscription #" + echo "# -c or --spn_id SPN application id #" + echo "# -o or --storageaccountname Storage account for terraform state files #" + echo "# -n or --spn_secret SPN password #" + echo "# -t or --tenant_id SPN Tenant id #" + echo "# -f or --force Clean up the local Terraform files. #" + echo "# -i or --auto-approve Silent install #" + echo "# -h or --help Help #" + echo "#########################################################################################" } function validate_exports { - if [ -z "$SAP_AUTOMATION_REPO_PATH" ]; then - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Missing environment variables (SAP_AUTOMATION_REPO_PATH)!!! $reset_formatting #" - echo "# #" - echo "# Please export the following variables: #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the automation repo folder (sap-automation)) #" - echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config)) #" - echo "# #" - echo "#########################################################################################" - return 65 #data format error - fi - - if [ -z "$CONFIG_REPO_PATH" ]; then - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Missing environment variables (CONFIG_REPO_PATH)!!! $reset_formatting #" - echo "# #" - echo "# Please export the following variables: #" - echo "# CONFIG_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config)) #" - echo "# #" - echo "#########################################################################################" - return 65 #data format error - fi - - if [ -z "$ARM_SUBSCRIPTION_ID" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Missing environment variables (ARM_SUBSCRIPTION_ID)!!! $reset_formatting #" - echo "# #" - echo "# Please export the following variables: #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config)) #" - echo "# #" - echo "#########################################################################################" - return 65 #data format error - fi - - return 0 + if [ -z "$SAP_AUTOMATION_REPO_PATH" ]; then + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Missing environment variables (SAP_AUTOMATION_REPO_PATH)!!! $reset_formatting #" + echo "# #" + echo "# Please export the following variables: #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the automation repo folder (sap-automation)) #" + echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config)) #" + echo "# #" + echo "#########################################################################################" + return 65 #data format error + fi + + if [ -z "$CONFIG_REPO_PATH" ]; then + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Missing environment variables (CONFIG_REPO_PATH)!!! $reset_formatting #" + echo "# #" + echo "# Please export the following variables: #" + echo "# CONFIG_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config)) #" + echo "# #" + echo "#########################################################################################" + return 65 #data format error + fi + + if [ -z "$ARM_SUBSCRIPTION_ID" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Missing environment variables (ARM_SUBSCRIPTION_ID)!!! $reset_formatting #" + echo "# #" + echo "# Please export the following variables: #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config)) #" + echo "# #" + echo "#########################################################################################" + return 65 #data format error + fi + + return 0 } function validate_webapp_exports { - if [ -z "$TF_VAR_app_registration_app_id" ]; then - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Missing environment variables (TF_VAR_app_registration_app_id)!!! $reset_formatting #" - echo "# #" - echo "# Please export the following variables to successfully deploy the Webapp: #" - echo "# TF_VAR_app_registration_app_id (webapp registration application id) #" - echo "# TF_VAR_webapp_client_secret (webapp registration password / secret) #" - echo "# #" - echo "# If you do not wish to deploy the Webapp, unset the TF_VAR_use_webapp variable #" - echo "# #" - echo "#########################################################################################" - return 65 #data format error - fi - - if [ "${ARM_USE_MSI}" == "false" ]; then - if [ -z "$TF_VAR_webapp_client_secret" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Missing environment variables (TF_VAR_webapp_client_secret)!!! $reset_formatting #" - echo "# #" - echo "# Please export the following variables to successfully deploy the Webapp: #" - echo "# TF_VAR_app_registration_app_id (webapp registration application id) #" - echo "# TF_VAR_webapp_client_secret (webapp registration password / secret) #" - echo "# #" - echo "# If you do not wish to deploy the Webapp, unset the TF_VAR_use_webapp variable #" - echo "# #" - echo "#########################################################################################" - return 65 #data format error - fi - fi - - return 0 + if [ -z "$TF_VAR_app_registration_app_id" ]; then + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Missing environment variables (TF_VAR_app_registration_app_id)!!! $reset_formatting #" + echo "# #" + echo "# Please export the following variables to successfully deploy the Webapp: #" + echo "# TF_VAR_app_registration_app_id (webapp registration application id) #" + echo "# TF_VAR_webapp_client_secret (webapp registration password / secret) #" + echo "# #" + echo "# If you do not wish to deploy the Webapp, unset the TF_VAR_use_webapp variable #" + echo "# #" + echo "#########################################################################################" + return 65 #data format error + fi + + if [ "${ARM_USE_MSI}" == "false" ]; then + if [ -z "$TF_VAR_webapp_client_secret" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Missing environment variables (TF_VAR_webapp_client_secret)!!! $reset_formatting #" + echo "# #" + echo "# Please export the following variables to successfully deploy the Webapp: #" + echo "# TF_VAR_app_registration_app_id (webapp registration application id) #" + echo "# TF_VAR_webapp_client_secret (webapp registration password / secret) #" + echo "# #" + echo "# If you do not wish to deploy the Webapp, unset the TF_VAR_use_webapp variable #" + echo "# #" + echo "#########################################################################################" + return 65 #data format error + fi + fi + + return 0 } function showhelp { - echo "" - echo "#########################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to deploy the different systems #" - echo "# The script experts the following exports: #" - echo "# #" - echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" - echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing the cloned sap-automation#" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" - echo "# #" - echo "# #" - echo "# Usage: installer.sh #" - echo "# -p or --parameterfile parameter file #" - echo "# -t or --type type of system to remove #" - echo "# valid options: #" - echo "# sap_deployer #" - echo "# sap_library #" - echo "# sap_landscape #" - echo "# sap_system #" - echo "# #" - echo "# Optional parameters #" - echo "# #" - echo "# -o or --storageaccountname Storage account name for state file #" - echo "# -s or --state_subscription Subscription for tfstate storage account #" - echo "# -i or --auto-approve Silent install #" - echo "# -h or --help Show help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/installer.sh \ #" - echo "# --parameterfile DEV-WEEU-SAP01-X00 \ #" - echo "# --type sap_system #" - echo "# --auto-approve #" - echo "# #" - echo "#########################################################################################" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to deploy the different systems #" + echo "# The script experts the following exports: #" + echo "# #" + echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" + echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing the cloned sap-automation#" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" + echo "# #" + echo "# #" + echo "# Usage: installer.sh #" + echo "# -p or --parameterfile parameter file #" + echo "# -t or --type type of system to remove #" + echo "# valid options: #" + echo "# sap_deployer #" + echo "# sap_library #" + echo "# sap_landscape #" + echo "# sap_system #" + echo "# #" + echo "# Optional parameters #" + echo "# #" + echo "# -o or --storageaccountname Storage account name for state file #" + echo "# -s or --state_subscription Subscription for tfstate storage account #" + echo "# -i or --auto-approve Silent install #" + echo "# -h or --help Show help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/installer.sh \ #" + echo "# --parameterfile DEV-WEEU-SAP01-X00 \ #" + echo "# --type sap_system #" + echo "# --auto-approve #" + echo "# #" + echo "#########################################################################################" } function missing { - printf -v val %-.40s "$option" - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Missing environment variables: ${option}!!! #" - echo "# #" - echo "# Please export the folloing variables: #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" - echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" - echo "# REMOTE_STATE_RG (resource group name for storage account containing state files) #" - echo "# REMOTE_STATE_SA (storage account for state file) #" - echo "# #" - echo "#########################################################################################" + printf -v val %-.40s "$option" + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Missing environment variables: ${option}!!! #" + echo "# #" + echo "# Please export the folloing variables: #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" + echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" + echo "# REMOTE_STATE_RG (resource group name for storage account containing state files) #" + echo "# REMOTE_STATE_SA (storage account for state file) #" + echo "# #" + echo "#########################################################################################" } function validate_dependencies { - tfPath="/opt/terraform/bin/terraform" - - if [ -f /opt/terraform/bin/terraform ]; then - tfPath="/opt/terraform/bin/terraform" - else - tfPath=$(which terraform) - fi - - echo "Checking Terraform: $tfPath" - - # if /opt/terraform exists, assign permissions to the user - if [ -d /opt/terraform ]; then - sudo chown -R "$USER" /opt/terraform - fi - - # Check terraform - if checkIfCloudShell; then - tf=$(terraform --version | grep Terraform) - else - tf=$($tfPath --version | grep Terraform) - fi - - if [ -z "$tf" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore Please install Terraform $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - return 2 #No such file or directory - fi - - if checkIfCloudShell; then - mkdir -p "${HOME}/.terraform.d/plugin-cache" - export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" - else - if [ ! -d "/opt/terraform/.terraform.d/plugin-cache" ]; then - mkdir -p "/opt/terraform/.terraform.d/plugin-cache" - fi - export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache - fi - # Set Terraform Plug in cache - - az_version=$(az --version | grep "azure-cli") - if [ -z "${az_version}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore Please install the Azure CLI $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - return 2 #No such file or directory - fi - cloudIDUsed=$(az account show | grep "cloudShellID" || true) - if [ -n "${cloudIDUsed}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Please login using your credentials or service principal credentials! $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 67 #addressee unknown - fi - - return 0 + tfPath="/opt/terraform/bin/terraform" + + if [ -f /opt/terraform/bin/terraform ]; then + tfPath="/opt/terraform/bin/terraform" + else + tfPath=$(which terraform) + fi + + echo "Checking Terraform: $tfPath" + + # if /opt/terraform exists, assign permissions to the user + if [ -d /opt/terraform ]; then + sudo chown -R "$USER" /opt/terraform + fi + + # Check terraform + if checkIfCloudShell; then + tf=$(terraform --version | grep Terraform) + else + tf=$($tfPath --version | grep Terraform) + fi + + if [ -z "$tf" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore Please install Terraform $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + return 2 #No such file or directory + fi + + if checkIfCloudShell; then + mkdir -p "${HOME}/.terraform.d/plugin-cache" + export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" + else + if [ ! -d "/opt/terraform/.terraform.d/plugin-cache" ]; then + mkdir -p "/opt/terraform/.terraform.d/plugin-cache" + fi + export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache + fi + # Set Terraform Plug in cache + + az_version=$(az --version | grep "azure-cli") + if [ -z "${az_version}" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore Please install the Azure CLI $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + return 2 #No such file or directory + fi + cloudIDUsed=$(az account show | grep "cloudShellID" || true) + if [ -n "${cloudIDUsed}" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Please login using your credentials or service principal credentials! $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 67 #addressee unknown + fi + + return 0 } function validate_key_parameters { - echo "Validating: $1" - - # Helper variables - load_config_vars "$1" "environment" - environment=$(echo "${environment}" | xargs | tr "[:lower:]" "[:upper:]" | tr -d '\r') - export environment - - load_config_vars "$1" "location" - region=$(echo "${location}" | xargs | tr -d '\r') - export region - - if [ -z "${environment}" ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Incorrect parameter file. $reset_formatting #" - echo "# #" - echo "# The file must contain the environment attribute!! #" - echo "# #" - echo "#########################################################################################" - echo "" - return 64 #script usage wrong - fi - - if [ -z "${region}" ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Incorrect parameter file. $reset_formatting #" - echo "# #" - echo "# The file must contain the region/location attribute!! #" - echo "# #" - echo "#########################################################################################" - echo "" - return 64 #script usage wrong - fi - - return 0 + echo "Validating: $1" + + # Helper variables + load_config_vars "$1" "environment" + environment=$(echo "${environment}" | xargs | tr "[:lower:]" "[:upper:]" | tr -d '\r') + export environment + + load_config_vars "$1" "location" + region=$(echo "${location}" | xargs | tr -d '\r') + export region + + if [ -z "${environment}" ]; then + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Incorrect parameter file. $reset_formatting #" + echo "# #" + echo "# The file must contain the environment attribute!! #" + echo "# #" + echo "#########################################################################################" + echo "" + return 64 #script usage wrong + fi + + if [ -z "${region}" ]; then + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Incorrect parameter file. $reset_formatting #" + echo "# #" + echo "# The file must contain the region/location attribute!! #" + echo "# #" + echo "#########################################################################################" + echo "" + return 64 #script usage wrong + fi + + return 0 } function version_compare { - echo "Comparison: $1 <= $2" - - if [ -z $1 ]; then - return 2 - fi - - if [[ "$1" == "$2" ]]; then - return 0 - fi - local IFS=. - local i ver1=($1) ver2=($2) - # fill empty fields in ver1 with zeros - for ((i = ${#ver1[@]}; i < ${#ver2[@]}; i++)); do - ver1[i]=0 - done - for ((i = 0; i < ${#ver1[@]}; i++)); do - if ((10#${ver1[i]:=0} > 10#${ver2[i]:=0})); then - return 1 - fi - if ((10#${ver1[i]} < 10#${ver2[i]})); then - return 2 - fi - done - return 0 + echo "Comparison: $1 <= $2" + + if [ -z $1 ]; then + return 2 + fi + + if [[ "$1" == "$2" ]]; then + return 0 + fi + local IFS=. + local i ver1=($1) ver2=($2) + # fill empty fields in ver1 with zeros + for ((i = ${#ver1[@]}; i < ${#ver2[@]}; i++)); do + ver1[i]=0 + done + for ((i = 0; i < ${#ver1[@]}; i++)); do + if ((10#${ver1[i]:=0} > 10#${ver2[i]:=0})); then + return 1 + fi + if ((10#${ver1[i]} < 10#${ver2[i]})); then + return 2 + fi + done + return 0 } function ReplaceResourceInStateFile { - local moduleID=$1 - local terraform_module_directory=$2 - azureResourceID=$(terraform -chdir="${terraform_module_directory}" state show "${moduleID}" | grep -m1 " $3 " | xargs | cut -d "=" -f2 | xargs) - tempString=$(echo "${azureResourceID}" | grep "/fileshares/") - if [ -n "${tempString}" ]; then - # Use sed to replace /fileshares/ with /shares/ - # shellcheck disable=SC2001 - azureResourceID=$(echo "$azureResourceID" | sed 's|/fileshares/|/shares/|g') - fi - - echo "Terraform resource ID: $moduleID" - echo "Azure resource ID: $azureResourceID" - if [ -n "${azureResourceID}" ]; then - echo "Removing storage account state object: ${moduleID} " - if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then - echo "Importing storage account state object: ${moduleID}" - echo "terraform -chdir=${terraform_module_directory} import -var-file=${var_file} -var deployer_tfstate_key=${deployer_tfstate_key} -var tfstate_resource_id=${tfstate_resource_id} $4 ${moduleID} ${azureResourceID}" - if ! terraform -chdir="${terraform_module_directory}" import -var-file="${var_file}" -var "deployer_tfstate_key=${deployer_tfstate_key}" -var "tfstate_resource_id=${tfstate_resource_id}" $4 "${moduleID}" "${azureResourceID}"; then - echo -e "$bold_red Importing storage account state object: ${moduleID} failed $reset_formatting" - exit 65 - fi - fi - fi - - return $? + local moduleID=$1 + local terraform_module_directory=$2 + + # shellcheck disable=SC2086 + if [ -z $STORAGE_ACCOUNT_ID ]; then + azureResourceID=$(terraform -chdir="${terraform_module_directory}" state show "${moduleID}" | grep -m1 $3 | xargs | cut -d "=" -f2 | xargs) + tempString=$(echo "${azureResourceID}" | grep "/fileshares/") + if [ -n "${tempString}" ]; then + # Use sed to replace /fileshares/ with /shares/ + # shellcheck disable=SC2001 + azureResourceID=$(echo "$azureResourceID" | sed 's|/fileshares/|/shares/|g') + fi + else + azureResourceID=$STORAGE_ACCOUNT_ID + fi + + echo "Terraform resource ID: $moduleID" + echo "Azure resource ID: $azureResourceID" + if [ -n "${azureResourceID}" ]; then + echo "Removing storage account state object: ${moduleID} " + if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then + echo "Importing storage account state object: ${moduleID}" + echo "terraform -chdir=${terraform_module_directory} import -var-file=${var_file} -var deployer_tfstate_key=${deployer_tfstate_key} -var tfstate_resource_id=${tfstate_resource_id} $4 ${moduleID} ${azureResourceID}" + if ! terraform -chdir="${terraform_module_directory}" import -var-file="${var_file}" -var "deployer_tfstate_key=${deployer_tfstate_key}" -var "tfstate_resource_id=${tfstate_resource_id}" $4 "${moduleID}" "${azureResourceID}"; then + echo -e "$bold_red Importing storage account state object: ${moduleID} failed $reset_formatting" + exit 65 + fi + fi + fi + + return $? } function ImportAndReRunApply { - local fileName=$1 - local terraform_module_directory=$2 - local importParameters=$3 - local applyParameters=$4 - - return_value=0 - - if [ -f "$fileName" ]; then - - errors_occurred=$(jq 'select(."@level" == "error") | length' "$fileName") - - if [[ -n $errors_occurred ]]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore!Errors during the apply phase!$reset_formatting #" - echo "# #" - echo "# #" - echo "#########################################################################################" - - # Check for resource that can be imported - existing=$(jq 'select(."@level" == "error") | {address: .diagnostic.address, summary: .diagnostic.summary} | select(.summary | startswith("A resource with the ID"))' "$fileName") - if [[ -n ${existing} ]]; then - - readarray -t existing_resources < <(echo ${existing} | jq -c '.') - for item in "${existing_resources[@]}"; do - moduleID=$(jq -c -r '.address ' <<<"$item") - azureResourceID=$(jq -c -r '.summary' <<<"$item" | awk -F'\"' '{print $2}') - echo "Trying to import $azureResourceID into $moduleID" - # shellcheck disable=SC2086 - echo terraform -chdir="${terraform_module_directory}" import $importParameters "${moduleID}" "${azureResourceID}" - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" import $importParameters "${moduleID}" "${azureResourceID}"; then - return_value=$? - echo "Error when importing resource" - return $return_value - fi - done - rm "$fileName" - - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Re-running Terraform apply$reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "" - - echo terraform -chdir="${terraform_module_directory}" apply -no-color -compact-warnings -json -input=false --auto-approve $applyParameters - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply -no-color -compact-warnings -json -input=false --auto-approve $applyParameters | tee -a "$fileName"; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - fi - fi - fi - fi - - return $return_value + local fileName=$1 + local terraform_module_directory=$2 + local importParameters=$3 + local applyParameters=$4 + + return_value=0 + + if [ -f "$fileName" ]; then + + errors_occurred=$(jq 'select(."@level" == "error") | length' "$fileName") + + if [[ -n $errors_occurred ]]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore!Errors during the apply phase!$reset_formatting #" + echo "# #" + echo "# #" + echo "#########################################################################################" + + # Check for resource that can be imported + existing=$(jq 'select(."@level" == "error") | {address: .diagnostic.address, summary: .diagnostic.summary} | select(.summary | startswith("A resource with the ID"))' "$fileName") + if [[ -n ${existing} ]]; then + + readarray -t existing_resources < <(echo ${existing} | jq -c '.') + for item in "${existing_resources[@]}"; do + moduleID=$(jq -c -r '.address ' <<<"$item") + azureResourceID=$(jq -c -r '.summary' <<<"$item" | awk -F'\"' '{print $2}') + echo "Trying to import $azureResourceID into $moduleID" + # shellcheck disable=SC2086 + echo terraform -chdir="${terraform_module_directory}" import $importParameters "${moduleID}" "${azureResourceID}" + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" import $importParameters "${moduleID}" "${azureResourceID}"; then + return_value=$? + echo "Error when importing resource" + echo "Terraform import: failed" + + return $return_value + else + echo "Terraform import: succeeded" + fi + done + rm "$fileName" + + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Re-running Terraform apply$reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "" + + echo terraform -chdir="${terraform_module_directory}" apply -no-color -compact-warnings -json -input=false --auto-approve $applyParameters + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply -no-color -compact-warnings -json -input=false --auto-approve $applyParameters | tee -a "$fileName"; then + return_value=$? + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform apply: failed$reset_formatting" + echo "" + else + # return code 2 is ok + echo "" + echo -e "${cyan}Terraform apply: succeeded$reset_formatting" + echo "" + return_value=0 + fi + else + echo "" + echo -e "${cyan}Terraform apply: succeeded$reset_formatting" + echo "" + + fi + fi + fi + fi + + return $return_value } function testIfResourceWouldBeRecreated { - local moduleId="$1" - local fileName="$2" - local shortName="$3" - printf -v val '%-40s' "$shortName" - return_value=0 - # || true suppresses the exitcode of grep. To not trigger the strict exit on error - willResourceWouldBeRecreated=$(grep "$moduleId" "$fileName" | grep -m1 "must be replaced" || true) - if [ -n "${willResourceWouldBeRecreated}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore!!! Risk for Data loss !!!$reset_formatting #" - echo "# #" - echo "# Resource will be removed: ${val} #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "" - echo "##vso[task.logissue type=error]Resource will be removed: $shortName" - return_value=1 - fi - return $return_value + local moduleId="$1" + local fileName="$2" + local shortName="$3" + printf -v val '%-40s' "$shortName" + return_value=0 + # || true suppresses the exitcode of grep. To not trigger the strict exit on error + willResourceWouldBeRecreated=$(grep "$moduleId" "$fileName" | grep -m1 "must be replaced" || true) + if [ -n "${willResourceWouldBeRecreated}" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore!!! Risk for Data loss !!!$reset_formatting #" + echo "# #" + echo "# Resource will be removed: ${val} #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "" + echo "##vso[task.logissue type=error]Resource will be removed: $shortName" + return_value=1 + fi + return $return_value } function validate_key_vault { - local keyvault_to_check=$1 - return_value=0 - - kv_name_check=$(az keyvault list --query "[?name=='$keyvault_to_check'].name | [0]") - if [ -z "$kv_name_check" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Retrying keyvault access $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - sleep 60 - kv_name_check=$(az keyvault list --query "[?name=='$keyvault_to_check'].name | [0]") - fi - - if [ -z "$kv_name_check" ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Unable to access keyvault: $keyvault_to_check $reset_formatting #" - echo "# Please ensure the key vault exists. #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 10 - fi - - access_error=$(az keyvault secret list --vault "$keyvault_to_check" --only-show-errors | grep "The user, group or application" || true) - if [ -n "${access_error}" ]; then - - az_subscription_id=$(az account show --query id -o tsv) - printf -v val %-40.40s "$az_subscription_id" - echo "#########################################################################################" - echo "# #" - echo -e "#$bold_red User account ${val} does not have access to: $keyvault $reset_formatting" - echo "# #" - echo "#########################################################################################" - - echo "##vso[task.setprogress value=40;]Progress Indicator" - return 65 - - fi - return $return_value + local keyvault_to_check=$1 + local subscription=$2 + return_value=0 + + kv_name_check=$(az keyvault show --name="$keyvault_to_check" --subscription "${subscription}" --query name) + return_value=$? + if [ -z "$kv_name_check" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Retrying keyvault access $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + sleep 60 + kv_name_check=$(az keyvault show --name="$keyvault_to_check" --subscription "${subscription}" --query name) + return_value=$? + fi + + if [ -z "$kv_name_check" ]; then + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Unable to access keyvault: $keyvault_to_check $reset_formatting #" + echo "# Please ensure the key vault exists. #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 10 + fi + + access_error=$(az keyvault secret list --vault "$keyvault_to_check" --subscription "${subscription}" --only-show-errors | grep "The user, group or application" || true) + if [ -n "${access_error}" ]; then + + az_subscription_id=$(az account show --query id -o tsv) + printf -v val %-40.40s "$az_subscription_id" + echo "#########################################################################################" + echo "# #" + echo -e "#$bold_red User account ${val} does not have access to: $keyvault $reset_formatting" + echo "# #" + echo "#########################################################################################" + + echo "##vso[task.setprogress value=40;]Progress Indicator" + return 65 + + fi + return $return_value } diff --git a/deploy/scripts/install_deployer.sh b/deploy/scripts/install_deployer.sh index 721ea494b3..e4526fcee4 100755 --- a/deploy/scripts/install_deployer.sh +++ b/deploy/scripts/install_deployer.sh @@ -20,33 +20,33 @@ source "${script_directory}/helpers/script_helpers.sh" #Internal helper functions function showhelp { - echo "" - echo "#########################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to deploy the deployer. #" - echo "# The script experts the following exports: #" - echo "# #" - echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" - echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing the cloned sap-automation #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" - echo "# #" - echo "# #" - echo "# Usage: install_deployer.sh #" - echo "# -p deployer parameter file #" - echo "# #" - echo "# -i interactive true/false setting the value to false will not prompt before apply #" - echo "# -h Show help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/install_deployer.sh \ #" - echo "# -p PROD-WEEU-DEP00-INFRASTRUCTURE.json \ #" - echo "# -i true #" - echo "# #" - echo "#########################################################################################" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to deploy the deployer. #" + echo "# The script experts the following exports: #" + echo "# #" + echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" + echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing the cloned sap-automation #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" + echo "# #" + echo "# #" + echo "# Usage: install_deployer.sh #" + echo "# -p deployer parameter file #" + echo "# #" + echo "# -i interactive true/false setting the value to false will not prompt before apply #" + echo "# -h Show help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/install_deployer.sh \ #" + echo "# -p PROD-WEEU-DEP00-INFRASTRUCTURE.json \ #" + echo "# -i true #" + echo "# #" + echo "#########################################################################################" } #process inputs - may need to check the option i for auto approve as it is not used @@ -54,30 +54,30 @@ INPUT_ARGUMENTS=$(getopt -n install_deployer -o p:ih --longoptions parameterfile VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp - exit 3 + showhelp + exit 3 fi eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -p | --parameterfile) - parameterfile="$2" - shift 2 - ;; - -i | --auto-approve) - approve="--auto-approve" - shift - ;; - -h | --help) - showhelp - exit 3 - ;; - --) - shift - break - ;; - esac + case "$1" in + -p | --parameterfile) + parameterfile="$2" + shift 2 + ;; + -i | --auto-approve) + approve="--auto-approve" + shift + ;; + -h | --help) + showhelp + exit 3 + ;; + --) + shift + break + ;; + esac done deployment_system=sap_deployer @@ -88,36 +88,36 @@ export TF_DATA_DIR="${param_dirname}/.terraform" echo "Parameter file: ${parameterfile}" if [ ! -f "${parameterfile}" ]; then - printf -v val %-40.40s "$parameterfile" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Parameter file does not exist: ${val} #" - echo "# #" - echo "#########################################################################################" - exit 2 #No such file or directory + printf -v val %-40.40s "$parameterfile" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Parameter file does not exist: ${val} #" + echo "# #" + echo "#########################################################################################" + exit 2 #No such file or directory fi if [ "$param_dirname" != '.' ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Please run this command from the folder containing the parameter file #" - echo "# #" - echo "#########################################################################################" - exit 3 + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Please run this command from the folder containing the parameter file #" + echo "# #" + echo "#########################################################################################" + exit 3 fi if [ "$DEBUG" = True ]; then - set -x - set -o errexit + set -x + set -o errexit fi # Check that parameter files have environment and location defined validate_key_parameters "$parameterfile" return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi region=$(echo "${region}" | tr "[:upper:]" "[:lower:]") @@ -140,7 +140,7 @@ var_file="${param_dirname}"/"${parameterfile}" validate_exports return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi echo "Configuration file: $parameterfile" @@ -158,85 +158,114 @@ echo "Agent IP: $this_ip" validate_dependencies return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi extra_vars="" reinstalled=0 if [ -f terraform.tfvars ]; then - extra_vars=" -var-file=${param_dirname}/terraform.tfvars " + extra_vars=" -var-file=${param_dirname}/terraform.tfvars " fi allParameters=$(printf " -var-file=%s %s" "${var_file}" "${extra_vars}") allImportParameters=$(printf " -var-file=%s %s " "${var_file}" "${extra_vars}") if [ ! -d ./.terraform/ ]; then - echo "#########################################################################################" - echo "# #" - echo "# New deployment #" - echo "# #" - echo "#########################################################################################" - terraform -chdir="${terraform_module_directory}" init -backend-config "path=${param_dirname}/terraform.tfstate" + echo "#########################################################################################" + echo "# #" + echo "# New deployment #" + echo "# #" + echo "#########################################################################################" + terraform -chdir="${terraform_module_directory}" init -upgrade=true -backend-config "path=${param_dirname}/terraform.tfstate" else - if [ -f ./.terraform/terraform.tfstate ]; then - azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) - if [ -n "$azure_backend" ]; then - - echo "#########################################################################################" - echo "# #" - echo "# The state is already migrated to Azure!!! #" - echo "# #" - echo "#########################################################################################" - - REINSTALL_SUBSCRIPTION=$(grep -m1 "subscription_id" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d '", \r' | xargs || true) - REINSTALL_ACCOUNTNAME=$(grep -m1 "storage_account_name" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) - REINSTALL_RESOURCE_GROUP=$(grep -m1 "resource_group_name" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) - - tfstate_resource_id=$(az resource list --name "$REINSTALL_ACCOUNTNAME" --subscription "$REINSTALL_SUBSCRIPTION" --resource-type Microsoft.Storage/storageAccounts --query "[].id | [0]" -o tsv) - if [ -n "${tfstate_resource_id}" ]; then - echo "Reinitializing against remote state" - this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 - az storage account network-rule add --account-name "$REINSTALL_ACCOUNTNAME" --resource-group "$REINSTALL_RESOURCE_GROUP" --ip-address "${this_ip}" --only-show-errors --output none - echo "Sleeping for 30 seconds to allow the network rule to take effect" - sleep 30 - export TF_VAR_tfstate_resource_id=$tfstate_resource_id - - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}/deploy/terraform/run/sap_deployer"/ - - if terraform -chdir="${terraform_module_directory}" init \ - --backend-config "subscription_id=$REINSTALL_SUBSCRIPTION" \ - --backend-config "resource_group_name=$REINSTALL_RESOURCE_GROUP" \ - --backend-config "storage_account_name=$REINSTALL_ACCOUNTNAME" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate"; then - terraform -chdir="${terraform_module_directory}" refresh -var-file="${var_file}" - else - return 10 - fi - else - terraform -chdir="${terraform_module_directory}" init -reconfigure --backend-config "path=${param_dirname}/terraform.tfstate" - terraform -chdir="${terraform_module_directory}" refresh -var-file="${var_file}" - fi - fi - else - terraform -chdir="${terraform_module_directory}" init -upgrade=true -backend-config "path=${param_dirname}/terraform.tfstate" - fi - terraform -chdir="${terraform_module_directory}" init -upgrade=true -backend-config "path=${param_dirname}/terraform.tfstate" - echo "Parameters: $allParameters" - terraform -chdir="${terraform_module_directory}" refresh $allParameters + if [ -f ./.terraform/terraform.tfstate ]; then + azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) + if [ -n "$azure_backend" ]; then + + echo "#########################################################################################" + echo "# #" + echo "# The state is already migrated to Azure!!! #" + echo "# #" + echo "#########################################################################################" + + REINSTALL_SUBSCRIPTION=$(grep -m1 "subscription_id" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d '", \r' | xargs || true) + REINSTALL_ACCOUNTNAME=$(grep -m1 "storage_account_name" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) + REINSTALL_RESOURCE_GROUP=$(grep -m1 "resource_group_name" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) + + tfstate_resource_id=$(az resource list --name "$REINSTALL_ACCOUNTNAME" --subscription "$REINSTALL_SUBSCRIPTION" --resource-type Microsoft.Storage/storageAccounts --query "[].id | [0]" -o tsv) + if [ -n "${tfstate_resource_id}" ]; then + echo "Reinitializing against remote state" + this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 + az storage account network-rule add --account-name "$REINSTALL_ACCOUNTNAME" --resource-group "$REINSTALL_RESOURCE_GROUP" --ip-address "${this_ip}" --only-show-errors --output none + echo "Sleeping for 30 seconds to allow the network rule to take effect" + sleep 30 + export TF_VAR_tfstate_resource_id=$tfstate_resource_id + + terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}/deploy/terraform/run/sap_deployer"/ + + if terraform -chdir="${terraform_module_directory}" init -upgrade=true \ + --backend-config "subscription_id=$REINSTALL_SUBSCRIPTION" \ + --backend-config "resource_group_name=$REINSTALL_RESOURCE_GROUP" \ + --backend-config "storage_account_name=$REINSTALL_ACCOUNTNAME" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + terraform -chdir="${terraform_module_directory}" refresh -var-file="${var_file}" + else + echo -e "${bold_red}Terraform init: succeeded$reset_formatting" + return 10 + fi + else + if terraform -chdir="${terraform_module_directory}" init -upgrade=true -reconfigure --backend-config "path=${param_dirname}/terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + terraform -chdir="${terraform_module_directory}" refresh -var-file="${var_file}" + else + echo -e "${bold_red}Terraform init: succeeded$reset_formatting" + return 10 + fi + fi + fi + else + if terraform -chdir="${terraform_module_directory}" init -upgrade=true -backend-config "path=${param_dirname}/terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + echo "" + echo -e "${bold_red}Terraform init: succeeded$reset_formatting" + echo "" + return 10 + fi + fi + if terraform -chdir="${terraform_module_directory}" init -upgrade=true -backend-config "path=${param_dirname}/terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + echo "" + echo -e "${bold_red}Terraform init: succeeded$reset_formatting" + echo "" + return 10 + fi + echo "Parameters: $allParameters" + terraform -chdir="${terraform_module_directory}" refresh $allParameters fi return_value=$? if [ 1 == $return_value ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore Errors during the init phase $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - unset TF_DATA_DIR - exit $return_value + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore Errors during the init phase $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + unset TF_DATA_DIR + exit $return_value fi echo "" @@ -250,31 +279,38 @@ echo "" # shellcheck disable=SC2086 if terraform -chdir="$terraform_module_directory" plan -detailed-exitcode $allParameters | tee -a plan_output.log; then - return_value=0 + echo "" + echo -e "${cyan}Terraform plan: succeeded$reset_formatting" + echo "" + return_value=0 else - return_value=$? + echo "" + echo -e "${bold_red}Terraform plan: failed$reset_formatting" + echo "" + return_value=$? + exit $return_value fi echo "Terraform Plan return code: $return_value" if [ 1 == $return_value ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore Errors during the plan phase $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - if [ -f plan_output.log ]; then - cat plan_output.log - rm plan_output.log - fi - unset TF_DATA_DIR - exit $return_value + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore Errors during the plan phase $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + if [ -f plan_output.log ]; then + cat plan_output.log + rm plan_output.log + fi + unset TF_DATA_DIR + exit $return_value fi if [ -f plan_output.log ]; then - rm plan_output.log + rm plan_output.log fi echo "" @@ -289,95 +325,109 @@ parallelism=10 #Provide a way to limit the number of parallell tasks for Terraform if [[ -n "${TF_PARALLELLISM}" ]]; then - parallelism=$TF_PARALLELLISM + parallelism=$TF_PARALLELLISM fi if [ -f apply_output.json ]; then - rm apply_output.json + rm apply_output.json fi if [ -n "${approve}" ]; then - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" \ - $allParameters -no-color -compact-warnings -json -input=false --auto-approve | tee -a apply_output.json; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - fi + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" \ + $allParameters -no-color -compact-warnings -json -input=false --auto-approve | tee -a apply_output.json; then + return_value=$? + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform apply: failed$reset_formatting" + echo "" + else + # return code 2 is ok + echo "" + echo -e "${cyan}Terraform apply: succeeded$reset_formatting" + echo "" + return_value=0 + fi + fi else - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" $allParameters; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - fi + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" $allParameters | tee -a apply_output.json; then + return_value=$? + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform apply: failed$reset_formatting" + echo "" + else + # return code 2 is ok + echo "" + echo -e "${cyan}Terraform apply: succeeded$reset_formatting" + echo "" + return_value=0 + fi + fi fi return_value=$? if [ -f apply_output.json ]; then - errors_occurred=$(jq 'select(."@level" == "error") | length' apply_output.json) - - if [[ -n $errors_occurred ]]; then - - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then - return_value=$? - else - return_value=0 - fi - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then - return_value=$? - else - return_value=0 - fi - fi - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then - return_value=$? - else - return_value=0 - fi - fi - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then - return_value=$? - else - return_value=0 - fi - fi - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then - return_value=$? - else - return_value=0 - fi - fi - fi + errors_occurred=$(jq 'select(."@level" == "error") | length' apply_output.json) + + if [[ -n $errors_occurred ]]; then + if [ -n "${approve}" ]; then + + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then + return_value=$? + else + return_value=0 + fi + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then + return_value=$? + else + return_value=0 + fi + fi + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then + return_value=$? + else + return_value=0 + fi + fi + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then + return_value=$? + else + return_value=0 + fi + fi + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" $allImportParameters $allParameters; then + return_value=$? + else + return_value=0 + fi + fi + else + return_value=10 + fi + fi fi echo "Terraform Apply return code: $return_value" if [ 0 != $return_value ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore !!! Error when Creating the deployer !!! $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - exit $return_value + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore !!! Error when Creating the deployer !!! $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + exit $return_value fi terraform -chdir="${terraform_module_directory}" output @@ -385,36 +435,36 @@ terraform -chdir="${terraform_module_directory}" output keyvault=$(terraform -chdir="${terraform_module_directory}" output deployer_kv_user_name | tr -d \") temp=$(echo "${keyvault}" | grep "Warning") if [ -z "${temp}" ]; then - temp=$(echo "${keyvault}" | grep "Backend reinitialization required") - if [ -z "${temp}" ]; then - touch "${deployer_config_information}" - printf -v val %-.20s "$keyvault" - - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# Keyvault to use for SPN details:$cyan $val $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - save_config_var "keyvault" "${deployer_config_information}" - return_value=0 - else - return_value=2 - fi + temp=$(echo "${keyvault}" | grep "Backend reinitialization required") + if [ -z "${temp}" ]; then + touch "${deployer_config_information}" + printf -v val %-.20s "$keyvault" + + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# Keyvault to use for SPN details:$cyan $val $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + save_config_var "keyvault" "${deployer_config_information}" + return_value=0 + else + return_value=2 + fi fi sshsecret=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_sshkey_secret_name | tr -d \") if [ -n "${sshsecret}" ]; then - save_config_var "sshsecret" "${deployer_config_information}" - return_value=0 + save_config_var "sshsecret" "${deployer_config_information}" + return_value=0 fi deployer_public_ip_address=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_public_ip_address | tr -d \") if [ -n "${deployer_public_ip_address}" ]; then - save_config_var "deployer_public_ip_address" "${deployer_config_information}" - return_value=0 + save_config_var "deployer_public_ip_address" "${deployer_config_information}" + return_value=0 fi unset TF_DATA_DIR diff --git a/deploy/scripts/install_library.sh b/deploy/scripts/install_library.sh index 3da3491d8b..7ade2acb5a 100755 --- a/deploy/scripts/install_library.sh +++ b/deploy/scripts/install_library.sh @@ -20,36 +20,36 @@ source "${script_directory}/helpers/script_helpers.sh" #Internal helper functions function showhelp { - echo "" - echo "#########################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to deploy the deployer. #" - echo "# The script experts the following exports: #" - echo "# #" - echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" - echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing #" - echo "# the cloned sap-automation #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" - echo "# #" - echo "# #" - echo "# Usage: install_library.sh #" - echo "# -p or --parameterfile library parameter file #" - echo "# -v or --keyvault Name of key vault containing credentiols #" - echo "# -s or --deployer_statefile_foldername relative path to deployer folder #" - echo "# -i or --auto-approve if set will not prompt before apply #" - echo "# -h Show help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/install_library.sh \ #" - echo "# -p PROD-WEEU-SAP_LIBRARY.json \ #" - echo "# -d ../../DEPLOYER/PROD-WEEU-DEP00-INFRASTRUCTURE/ \ #" - echo "# -i true #" - echo "# #" - echo "#########################################################################################" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to deploy the deployer. #" + echo "# The script experts the following exports: #" + echo "# #" + echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" + echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing #" + echo "# the cloned sap-automation #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" + echo "# #" + echo "# #" + echo "# Usage: install_library.sh #" + echo "# -p or --parameterfile library parameter file #" + echo "# -v or --keyvault Name of key vault containing credentiols #" + echo "# -s or --deployer_statefile_foldername relative path to deployer folder #" + echo "# -i or --auto-approve if set will not prompt before apply #" + echo "# -h Show help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/install_library.sh \ #" + echo "# -p PROD-WEEU-SAP_LIBRARY.json \ #" + echo "# -d ../../DEPLOYER/PROD-WEEU-DEP00-INFRASTRUCTURE/ \ #" + echo "# -i true #" + echo "# #" + echo "#########################################################################################" } #process inputs - may need to check the option i for auto approve as it is not used @@ -57,112 +57,112 @@ INPUT_ARGUMENTS=$(getopt -n install_library -o p:d:v:ih --longoptions parameterf VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp + showhelp fi eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -p | --parameterfile) - parameterfile_name="$2" - shift 2 - ;; - -d | --deployer_statefile_foldername) - deployer_statefile_foldername="$2" - shift 2 - ;; - -i | --auto-approve) - approve="--auto-approve" - shift - ;; - -h | --help) - showhelp - exit 3 - ;; - -v | --keyvault) - keyvault="$2" - shift 2 - ;; - --) - shift - break - ;; - esac + case "$1" in + -p | --parameterfile) + parameterfile_name="$2" + shift 2 + ;; + -d | --deployer_statefile_foldername) + deployer_statefile_foldername="$2" + shift 2 + ;; + -i | --auto-approve) + approve="--auto-approve" + shift + ;; + -h | --help) + showhelp + exit 3 + ;; + -v | --keyvault) + keyvault="$2" + shift 2 + ;; + --) + shift + break + ;; + esac done deployment_system=sap_library use_deployer=true if [ "$DEBUG" = True ]; then - set -x - set -o errexit + set -x + set -o errexit fi if [ ! -f "${parameterfile_name}" ]; then - printf -v val %-40.40s "$parameterfile_name" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Parameter file does not exist: ${val} #" - echo "# #" - echo "#########################################################################################" - exit 65 + printf -v val %-40.40s "$parameterfile_name" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Parameter file does not exist: ${val} #" + echo "# #" + echo "#########################################################################################" + exit 65 fi param_dirname=$(dirname "${parameterfile_name}") export TF_DATA_DIR="${param_dirname}"/.terraform if [ "$param_dirname" != '.' ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Please run this command from the folder containing the parameter file #" - echo "# #" - echo "#########################################################################################" - exit 3 + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Please run this command from the folder containing the parameter file #" + echo "# #" + echo "#########################################################################################" + exit 3 fi # Check that parameter files have environment and location defined validate_key_parameters "$parameterfile_name" return_code=$? if [ 0 != $return_code ]; then - echo "Missing parameters in $parameterfile_name" - exit $return_code + echo "Missing parameters in $parameterfile_name" + exit $return_code fi region=$(echo "${region}" | tr "[:upper:]" "[:lower:]") if valid_region_name "${region}"; then - # Convert the region to the correct code - get_region_code "${region}" + # Convert the region to the correct code + get_region_code "${region}" else - echo "Invalid region: $region" - exit 2 + echo "Invalid region: $region" + exit 2 fi key=$(echo "${parameterfile_name}" | cut -d. -f1) if [ -z "${environment}" ]; then - echo "#########################################################################################" - echo "# #" - echo "# Incorrect parameter file. #" - echo "# #" - echo "# The file needs to contain the environment attribute!! #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 64 + echo "#########################################################################################" + echo "# #" + echo "# Incorrect parameter file. #" + echo "# #" + echo "# The file needs to contain the environment attribute!! #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 64 fi if [ -z "${region}" ]; then - echo "#########################################################################################" - echo "# #" - echo "# Incorrect parameter file. #" - echo "# #" - echo "# The file needs to contain the infrastructure.region attribute!! #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 64 + echo "#########################################################################################" + echo "# #" + echo "# Incorrect parameter file. #" + echo "# #" + echo "# The file needs to contain the infrastructure.region attribute!! #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 64 fi # Convert the region to the correct code @@ -170,16 +170,16 @@ region=$(echo "${region}" | tr "[:upper:]" "[:lower:]") get_region_code "$region" if [ true == "$use_deployer" ]; then - if [ ! -d "${deployer_statefile_foldername}" ]; then - printf -v val %-40.40s "$deployer_statefile_foldername" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Directory does not exist: ${deployer_statefile_foldername} #" - echo "# #" - echo "#########################################################################################" - exit - fi + if [ ! -d "${deployer_statefile_foldername}" ]; then + printf -v val %-40.40s "$deployer_statefile_foldername" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Directory does not exist: ${deployer_statefile_foldername} #" + echo "# #" + echo "#########################################################################################" + exit + fi fi #Persisting the parameters across executions @@ -189,14 +189,14 @@ library_config_information="${automation_config_directory}${environment}${region # Terraform Plugins if checkIfCloudShell; then - mkdir -p "${HOME}/.terraform.d/plugin-cache" - export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" + mkdir -p "${HOME}/.terraform.d/plugin-cache" + export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" else - if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then - mkdir -p /opt/terraform/.terraform.d/plugin-cache - sudo chown -R "$USER" /opt/terraform - fi - export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache + if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then + sudo mkdir -p /opt/terraform/.terraform.d/plugin-cache + sudo chown -R "$USER" /opt/terraform + fi + export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache fi param_dirname=$(pwd) @@ -207,127 +207,149 @@ export TF_DATA_DIR="${param_dirname}"/.terraform var_file="${param_dirname}"/"${parameterfile_name}" if [ -z "${SAP_AUTOMATION_REPO_PATH}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Missing environment variables (SAP_AUTOMATION_REPO_PATH)!!! #" - echo "# #" - echo "# Please export the following variables: #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" - echo "# #" - echo "#########################################################################################" - unset TF_DATA_DIR - exit 4 + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Missing environment variables (SAP_AUTOMATION_REPO_PATH)!!! #" + echo "# #" + echo "# Please export the following variables: #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" + echo "# #" + echo "#########################################################################################" + unset TF_DATA_DIR + exit 4 fi if [ -z "$ARM_SUBSCRIPTION_ID" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Missing environment variables (ARM_SUBSCRIPTION_ID)!!! #" - echo "# #" - echo "# Please export the following variables: #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" - echo "# #" - echo "#########################################################################################" - unset TF_DATA_DIR - exit 3 + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Missing environment variables (ARM_SUBSCRIPTION_ID)!!! #" + echo "# #" + echo "# Please export the following variables: #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" + echo "# #" + echo "#########################################################################################" + unset TF_DATA_DIR + exit 3 fi terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/"${deployment_system}"/ if [ ! -d "${terraform_module_directory}" ]; then - echo "#########################################################################################" - echo "# #" - echo "# Incorrect system deployment type specified :" ${deployment_system} " #" - echo "# #" - echo "# Valid options are: #" - echo "# sap_library #" - echo "# #" - echo "#########################################################################################" - echo "" - unset TF_DATA_DIR - exit 64 + echo "#########################################################################################" + echo "# #" + echo "# Incorrect system deployment type specified :" ${deployment_system} " #" + echo "# #" + echo "# Valid options are: #" + echo "# sap_library #" + echo "# #" + echo "#########################################################################################" + echo "" + unset TF_DATA_DIR + exit 64 fi if [ -f ./backend-config.tfvars ]; then - echo "#########################################################################################" - echo "# #" - echo "# The bootstrapping has already been done! #" - echo "# #" - echo "#########################################################################################" + echo "#########################################################################################" + echo "# #" + echo "# The bootstrapping has already been done! #" + echo "# #" + echo "#########################################################################################" else - sed -i /REMOTE_STATE_RG/d "${library_config_information}" - sed -i /REMOTE_STATE_SA/d "${library_config_information}" - sed -i /tfstate_resource_id/d "${library_config_information}" + sed -i /REMOTE_STATE_RG/d "${library_config_information}" + sed -i /REMOTE_STATE_SA/d "${library_config_information}" + sed -i /tfstate_resource_id/d "${library_config_information}" fi TF_VAR_subscription_id="$ARM_SUBSCRIPTION_ID" export TF_VAR_subscription_id if [ -n "${keyvault}" ]; then - TF_VAR_deployer_kv_user_arm_id=$(az resource list --name "${keyvault}" --subscription "$ARM_SUBSCRIPTION_ID" --resource-type Microsoft.KeyVault/vaults --query "[].id | [0]" -o tsv) - export TF_VAR_spn_keyvault_id="${TF_VAR_deployer_kv_user_arm_id}" - + TF_VAR_deployer_kv_user_arm_id=$(az resource list --name "${keyvault}" --subscription "$ARM_SUBSCRIPTION_ID" --resource-type Microsoft.KeyVault/vaults --query "[].id | [0]" -o tsv) + export TF_VAR_spn_keyvault_id="${TF_VAR_deployer_kv_user_arm_id}" fi if [ ! -d ./.terraform/ ]; then - echo "#########################################################################################" - echo "# #" - echo "# New deployment #" - echo "# #" - echo "#########################################################################################" - terraform -chdir="${terraform_module_directory}" init -backend-config "path=${param_dirname}/terraform.tfstate" - sed -i /REMOTE_STATE_RG/d "${library_config_information}" - sed -i /REMOTE_STATE_SA/d "${library_config_information}" - sed -i /tfstate_resource_id/d "${library_config_information}" + echo "#########################################################################################" + echo "# #" + echo "# New deployment #" + echo "# #" + echo "#########################################################################################" + terraform -chdir="${terraform_module_directory}" init -upgrade=true -backend-config "path=${param_dirname}/terraform.tfstate" + sed -i /REMOTE_STATE_RG/d "${library_config_information}" + sed -i /REMOTE_STATE_SA/d "${library_config_information}" + sed -i /tfstate_resource_id/d "${library_config_information}" else - if [ -f ./.terraform/terraform.tfstate ]; then - azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) - if [ -n "$azure_backend" ]; then - echo "#########################################################################################" - echo "# #" - echo "# The state is already migrated to Azure!!! #" - echo "# #" - echo "#########################################################################################" - - REINSTALL_SUBSCRIPTION=$(grep -m1 "subscription_id" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d '", \r' | xargs || true) - REINSTALL_ACCOUNTNAME=$(grep -m1 "storage_account_name" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) - REINSTALL_RESOURCE_GROUP=$(grep -m1 "resource_group_name" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) - - tfstate_resource_id=$(az resource list --name "$REINSTALL_ACCOUNTNAME" --subscription "$REINSTALL_SUBSCRIPTION" --resource-type Microsoft.Storage/storageAccounts --query "[].id | [0]" -o tsv) - if [ -n "${tfstate_resource_id}" ]; then - echo "Reinitializing against remote state" - this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 - az storage account network-rule add --account-name "$REINSTALL_ACCOUNTNAME" --resource-group "$REINSTALL_RESOURCE_GROUP" --ip-address "${this_ip}" --only-show-errors --output none - echo "Sleeping for 30 seconds to allow the network rule to take effect" - sleep 30 - export TF_VAR_tfstate_resource_id=$tfstate_resource_id - - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}/deploy/terraform/run/sap_library"/ - - if terraform -chdir="${terraform_module_directory}" init \ - --backend-config "subscription_id=$REINSTALL_SUBSCRIPTION" \ - --backend-config "resource_group_name=$REINSTALL_RESOURCE_GROUP" \ - --backend-config "storage_account_name=$REINSTALL_ACCOUNTNAME" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate"; then - terraform -chdir="${terraform_module_directory}" refresh -var-file="${var_file}" -input=false \ - -var deployer_statefile_foldername="${deployer_statefile_foldername}" - else - return 10 - fi - else - terraform -chdir="${terraform_module_directory}" init -reconfigure --backend-config "path=${param_dirname}/terraform.tfstate" - terraform -chdir="${terraform_module_directory}" refresh -var-file="${var_file}" - fi - fi - else - terraform -chdir="${terraform_module_directory}" init -upgrade=true -backend-config "path=${param_dirname}/terraform.tfstate" - fi + if [ -f ./.terraform/terraform.tfstate ]; then + azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) + if [ -n "$azure_backend" ]; then + echo "#########################################################################################" + echo "# #" + echo "# The state is already migrated to Azure!!! #" + echo "# #" + echo "#########################################################################################" + + REINSTALL_SUBSCRIPTION=$(grep -m1 "subscription_id" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d '", \r' | xargs || true) + REINSTALL_ACCOUNTNAME=$(grep -m1 "storage_account_name" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) + REINSTALL_RESOURCE_GROUP=$(grep -m1 "resource_group_name" "${param_dirname}/.terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) + + tfstate_resource_id=$(az resource list --name "$REINSTALL_ACCOUNTNAME" --subscription "$REINSTALL_SUBSCRIPTION" --resource-type Microsoft.Storage/storageAccounts --query "[].id | [0]" -o tsv) + if [ -n "${tfstate_resource_id}" ]; then + echo "Reinitializing against remote state" + this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 + az storage account network-rule add --account-name "$REINSTALL_ACCOUNTNAME" --resource-group "$REINSTALL_RESOURCE_GROUP" --ip-address "${this_ip}" --only-show-errors --output none + echo "Sleeping for 30 seconds to allow the network rule to take effect" + sleep 30 + export TF_VAR_tfstate_resource_id=$tfstate_resource_id + + terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}/deploy/terraform/run/sap_library"/ + + if terraform -chdir="${terraform_module_directory}" init \ + --backend-config "subscription_id=$REINSTALL_SUBSCRIPTION" \ + --backend-config "resource_group_name=$REINSTALL_RESOURCE_GROUP" \ + --backend-config "storage_account_name=$REINSTALL_ACCOUNTNAME" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + + terraform -chdir="${terraform_module_directory}" refresh -var-file="${var_file}" -input=false \ + -var deployer_statefile_foldername="${deployer_statefile_foldername}" + else + echo "" + echo -e "${bold_red}Terraform init: succeeded$reset_formatting" + echo "" + return 10 + fi + else + if terraform -chdir="${terraform_module_directory}" init -reconfigure --backend-config "path=${param_dirname}/terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + terraform -chdir="${terraform_module_directory}" refresh -var-file="${var_file}" + else + echo "" + echo -e "${bold_red}Terraform init: succeeded$reset_formatting" + echo "" + return 10 + fi + fi + fi + else + if terraform -chdir="${terraform_module_directory}" init -upgrade=true -backend-config "path=${param_dirname}/terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + echo "" + echo -e "${bold_red}Terraform init: succeeded$reset_formatting" + echo "" + return 10 + fi + fi fi echo "" @@ -339,50 +361,64 @@ echo "########################################################################## echo "" if [ -f terraform.tfvars ]; then - extra_vars=" -var-file=${param_dirname}/terraform.tfvars " + extra_vars=" -var-file=${param_dirname}/terraform.tfvars " else - unset extra_vars + unset extra_vars fi if [ -n "${deployer_statefile_foldername}" ]; then - echo "Deployer folder specified: ${deployer_statefile_foldername}" - if ! terraform -chdir="${terraform_module_directory}" plan -no-color -detailed-exitcode \ - -var-file="${var_file}" -input=false \ - -var deployer_statefile_foldername="${deployer_statefile_foldername}" | tee -a plan_output.log 2>&1; then - return_value=$? - fi - allParameters=$(printf " -var-file=%s -var deployer_statefile_foldername=%s %s " "${var_file}" "${deployer_statefile_foldername}" "${extra_vars}") - allImportParameters=$(printf " -var-file=%s -var deployer_statefile_foldername=%s %s " "${var_file}" "${deployer_statefile_foldername}" "${extra_vars}") + echo "Deployer folder specified: ${deployer_statefile_foldername}" + if ! terraform -chdir="${terraform_module_directory}" plan -no-color -detailed-exitcode \ + -var-file="${var_file}" -input=false \ + -var deployer_statefile_foldername="${deployer_statefile_foldername}" | tee -a plan_output.log 2>&1; then + echo "" + echo -e "${bold_red}Terraform plan: failed$reset_formatting" + echo "" + return_value=$? + else + echo "" + echo -e "${cyan}Terraform plan: succeeded$reset_formatting" + echo "" + fi + allParameters=$(printf " -var-file=%s -var deployer_statefile_foldername=%s %s " "${var_file}" "${deployer_statefile_foldername}" "${extra_vars}") + allImportParameters=$(printf " -var-file=%s -var deployer_statefile_foldername=%s %s " "${var_file}" "${deployer_statefile_foldername}" "${extra_vars}") else - if ! terraform -chdir="${terraform_module_directory}" plan -no-color -detailed-exitcode \ - -var-file="${var_file}" -input=false | tee -a plan_output.log 2>&1; then - return_value=$? - fi - allParameters=$(printf " -var-file=%s %s" "${var_file}" "${extra_vars}") - allImportParameters=$(printf " -var-file=%s %s" "${var_file}" "${extra_vars}") + if ! terraform -chdir="${terraform_module_directory}" plan -no-color -detailed-exitcode \ + -var-file="${var_file}" -input=false | tee -a plan_output.log 2>&1; then + return_value=$? + echo "" + echo -e "${bold_red}Terraform plan: failed$reset_formatting" + echo "" + else + echo "" + echo -e "${cyan}Terraform plan: succeeded$reset_formatting" + echo "" + fi + allParameters=$(printf " -var-file=%s %s" "${var_file}" "${extra_vars}") + allImportParameters=$(printf " -var-file=%s %s" "${var_file}" "${extra_vars}") fi return_value=$? if [ 1 == $return_value ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore Errors during the plan phase $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - unset TF_DATA_DIR - exit $return_value + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore Errors during the plan phase $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + unset TF_DATA_DIR + exit $return_value fi parallelism=10 #Provide a way to limit the number of parallell tasks for Terraform if [[ -n "$TF_PARALLELLISM" ]]; then - parallelism=$TF_PARALLELLISM + parallelism=$TF_PARALLELLISM fi echo "Parallelism count: $parallelism" @@ -398,116 +434,130 @@ echo "########################################################################## echo "" if [ -n "${approve}" ]; then - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" -no-color -compact-warnings -json -input=false $allParameters --auto-approve | tee -a apply_output.json; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - else - return_value=0 - fi + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" -no-color -compact-warnings -json -input=false $allParameters --auto-approve | tee -a apply_output.json; then + return_value=$? + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform apply: $reset_formatting failed" + echo "" + else + # return code 2 is ok + echo "" + echo -e "${cyan}Terraform apply: $reset_formatting succeeded" + echo "" + return_value=0 + fi + else + + return_value=0 + echo "" + echo -e "${cyan}Terraform apply: $reset_formatting succeeded" + echo "" + fi else - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" -input=false $allParameters; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - fi + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" -input=false $allParameters; then + return_value=$? + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform apply: $reset_formatting failed" + echo "" + else + # return code 2 is ok + return_value=0 + echo "" + echo -e "${cyan}Terraform apply: $reset_formatting succeeded" + echo "" + fi + fi fi if [ -f apply_output.json ]; then - errors_occurred=$(jq 'select(."@level" == "error") | length' apply_output.json) - - if [[ -n $errors_occurred ]]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - fi + errors_occurred=$(jq 'select(."@level" == "error") | length' apply_output.json) + + if [[ -n $errors_occurred ]]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + fi fi if [ -f apply_output.json ]; then - rm apply_output.json + rm apply_output.json fi if [ 1 == $return_value ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore Errors during the apply phase $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - unset TF_DATA_DIR - exit $return_value + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore Errors during the apply phase $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + unset TF_DATA_DIR + exit $return_value fi if ! terraform -chdir="${terraform_module_directory}" refresh $allParameters; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform refresh" - else - # return code 2 is ok - return_value=0 - fi + return_value=$? + if [ $return_value -eq 1 ]; then + echo "Errors when running Terraform refresh" + else + # return code 2 is ok + return_value=0 + fi else - return_value=0 + return_value=0 fi if [ "$DEBUG" = True ]; then - terraform -chdir="${terraform_module_directory}" output + terraform -chdir="${terraform_module_directory}" output fi if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - tfstate_resource_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw tfstate_resource_id | tr -d \") - STATE_SUBSCRIPTION=$(echo "$tfstate_resource_id" | cut -d/ -f3 | tr -d \" | xargs) + tfstate_resource_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw tfstate_resource_id | tr -d \") + STATE_SUBSCRIPTION=$(echo "$tfstate_resource_id" | cut -d/ -f3 | tr -d \" | xargs) - az account set --sub "$STATE_SUBSCRIPTION" + az account set --sub "$STATE_SUBSCRIPTION" - REMOTE_STATE_SA=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw remote_state_storage_account_name | tr -d \") - export REMOTE_STATE_SA + REMOTE_STATE_SA=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw remote_state_storage_account_name | tr -d \") + export REMOTE_STATE_SA - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${library_config_information}" - return_value=0 + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${library_config_information}" + return_value=0 else - return_value=20 + return_value=20 fi exit $return_value diff --git a/deploy/scripts/install_workloadzone.sh b/deploy/scripts/install_workloadzone.sh index 7f045ddfb5..64bfe7f82e 100755 --- a/deploy/scripts/install_workloadzone.sh +++ b/deploy/scripts/install_workloadzone.sh @@ -26,8 +26,8 @@ source "${script_directory}/deploy_utils.sh" source "${script_directory}/helpers/script_helpers.sh" if [ "$DEBUG" = True ]; then - set -x - set -o errexit + set -x + set -o errexit fi force=0 @@ -37,78 +37,78 @@ deploy_using_msi_only=0 INPUT_ARGUMENTS=$(getopt -n install_workloadzone -o p:d:e:k:o:s:c:n:t:v:aifhm --longoptions parameterfile:,deployer_tfstate_key:,deployer_environment:,subscription:,spn_id:,spn_secret:,tenant_id:,state_subscription:,keyvault:,storageaccountname:,ado,auto-approve,force,help,msi -- "$@") VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp + showhelp fi eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -a | --ado) - called_from_ado=1 - shift - ;; - -c | --spn_id) - client_id="$2" - shift 2 - ;; - -d | --deployer_tfstate_key) - deployer_tfstate_key="$2" - shift 2 - ;; - -e | --deployer_environment) - deployer_environment="$2" - shift 2 - ;; - -f | --force) - force=1 - shift - ;; - -i | --auto-approve) - approve="--auto-approve" - shift - ;; - -k | --state_subscription) - STATE_SUBSCRIPTION="$2" - shift 2 - ;; - -m | --msi) - deploy_using_msi_only=1 - shift - ;; - -n | --spn_secret) - spn_secret="$2" - shift 2 - ;; - -o | --storageaccountname) - REMOTE_STATE_SA="$2" - shift 2 - ;; - -p | --parameterfile) - parameterfile="$2" - shift 2 - ;; - -s | --subscription) - subscription="$2" - shift 2 - ;; - -t | --tenant_id) - tenant_id="$2" - shift 2 - ;; - -v | --keyvault) - keyvault="$2" - shift 2 - ;; - - -h | --help) - workload_zone_showhelp - exit 3 - ;; - --) - shift - break - ;; - esac + case "$1" in + -a | --ado) + called_from_ado=1 + shift + ;; + -c | --spn_id) + client_id="$2" + shift 2 + ;; + -d | --deployer_tfstate_key) + deployer_tfstate_key="$2" + shift 2 + ;; + -e | --deployer_environment) + deployer_environment="$2" + shift 2 + ;; + -f | --force) + force=1 + shift + ;; + -i | --auto-approve) + approve="--auto-approve" + shift + ;; + -k | --state_subscription) + STATE_SUBSCRIPTION="$2" + shift 2 + ;; + -m | --msi) + deploy_using_msi_only=1 + shift + ;; + -n | --spn_secret) + spn_secret="$2" + shift 2 + ;; + -o | --storageaccountname) + REMOTE_STATE_SA="$2" + shift 2 + ;; + -p | --parameterfile) + parameterfile="$2" + shift 2 + ;; + -s | --subscription) + subscription="$2" + shift 2 + ;; + -t | --tenant_id) + tenant_id="$2" + shift 2 + ;; + -v | --keyvault) + keyvault="$2" + shift 2 + ;; + + -h | --help) + workload_zone_showhelp + exit 3 + ;; + --) + shift + break + ;; + esac done tfstate_resource_id="" tfstate_parameter="" @@ -126,9 +126,9 @@ deployer_environment=$(echo "${deployer_environment}" | tr "[:lower:]" "[:upper: echo "Deployer environment: $deployer_environment" if [ 1 == $called_from_ado ]; then - this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 - export TF_VAR_Agent_IP=$this_ip - echo "Agent IP: $this_ip" + this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 + export TF_VAR_Agent_IP=$this_ip + echo "Agent IP: $this_ip" fi @@ -137,79 +137,79 @@ workload_file_parametername=$(basename "${parameterfile}") param_dirname=$(dirname "${parameterfile}") if [ "$param_dirname" != '.' ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Please run this command from the folder containing the parameter file$reset_formatting #" - echo "# #" - echo "#########################################################################################" - exit 3 + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Please run this command from the folder containing the parameter file$reset_formatting #" + echo "# #" + echo "#########################################################################################" + exit 3 fi if [ ! -f "${workload_file_parametername}" ]; then - printf -v val %-40.40s "$workload_file_parametername" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore Parameter file does not exist: ${val}$reset_formatting #" - echo "# #" - echo "#########################################################################################" - exit 3 + printf -v val %-40.40s "$workload_file_parametername" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore Parameter file does not exist: ${val}$reset_formatting #" + echo "# #" + echo "#########################################################################################" + exit 3 fi # Check that the exports ARM_SUBSCRIPTION_ID and SAP_AUTOMATION_REPO_PATH are defined validate_exports return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi # Check that Terraform and Azure CLI is installed validate_dependencies return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi # Check that parameter files have environment and location defined validate_key_parameters "$workload_file_parametername" return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi # Convert the region to the correct code get_region_code "$region" if [ "${region_code}" == 'UNKN' ]; then - LOCATION_CODE_IN_FILENAME=$(echo "$workload_file_parametername" | awk -F'-' '{print $2}') - region_code=$(echo "${LOCATION_CODE_IN_FILENAME}" | tr "[:lower:]" "[:upper:]" | xargs) + LOCATION_CODE_IN_FILENAME=$(echo "$workload_file_parametername" | awk -F'-' '{print $2}') + region_code=$(echo "${LOCATION_CODE_IN_FILENAME}" | tr "[:lower:]" "[:upper:]" | xargs) fi echo "Region code: ${region_code}" load_config_vars "$workload_file_parametername" "network_logical_name" -network_logical_name=$(echo "${network_logical_name}" | tr "[:lower:]" "[:upper:]" | tr -d ' \t\n\r\f"') +network_logical_name=$(echo "$workload_file_parametername" | awk -F'-' '{print $3}') if [ -z "${network_logical_name}" ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Incorrect parameter file. $reset_formatting #" - echo "# #" - echo "# The file must contain the network_logical_name attribute!! #" - echo "# #" - echo "#########################################################################################" - echo "" - return 64 #script usage wrong + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Incorrect parameter file. $reset_formatting #" + echo "# #" + echo "# The file must contain the network_logical_name attribute!! #" + echo "# #" + echo "#########################################################################################" + echo "" + return 64 #script usage wrong fi key=$(echo "${workload_file_parametername}" | cut -d. -f1) landscape_tfstate_key=${key}.terraform.tfstate if [ -f terraform.tfvars ]; then - extra_vars="-var-file=${param_dirname}/terraform.tfvars" + extra_vars="-var-file=${param_dirname}/terraform.tfvars" else - unset extra_vars + unset extra_vars fi #Persisting the parameters across executions @@ -218,24 +218,25 @@ automation_config_directory=$CONFIG_REPO_PATH/.sap_deployment_automation generic_config_information="${automation_config_directory}"/config if [ "$deployer_environment" != "$environment" ]; then - if [ -f "${automation_config_directory}/${environment}${region_code}" ]; then - # Add support for having multiple vnets in the same environment and zone - rename exiting file to support seamless transition - if [ -f "${automation_config_directory}/${environment}${region_code}${network_logical_name}" ]; then - mv "${automation_config_directory}/${environment}${region_code}" "${automation_config_directory}/${environment}${region_code}${network_logical_name}" - fi - fi + if [ -f "${automation_config_directory}/${environment}${region_code}" ]; then + # Add support for having multiple vnets in the same environment and zone - rename exiting file to support seamless transition + if [ -f "${automation_config_directory}/${environment}${region_code}${network_logical_name}" ]; then + mv "${automation_config_directory}/${environment}${region_code}" "${automation_config_directory}/${environment}${region_code}${network_logical_name}" + fi + fi fi workload_config_information="${automation_config_directory}/${environment}${region_code}${network_logical_name}" +touch "${workload_config_information}" deployer_config_information="${automation_config_directory}/${deployer_environment}${region_code}" save_config_vars "${workload_config_information}" \ - STATE_SUBSCRIPTION REMOTE_STATE_SA subscription + STATE_SUBSCRIPTION REMOTE_STATE_SA subscription if [ "${force}" == 1 ]; then - if [ -f "${workload_config_information}" ]; then - rm "${workload_config_information}" - fi - rm -Rf .terraform terraform.tfstate* + if [ -f "${workload_config_information}" ]; then + rm "${workload_config_information}" + fi + rm -Rf .terraform terraform.tfstate* fi echo "" @@ -249,112 +250,112 @@ echo "Remote state storage account: $REMOTE_STATE_SA" echo "Target Subscription: $subscription" if [[ -n $STATE_SUBSCRIPTION ]]; then - if is_valid_guid "$STATE_SUBSCRIPTION"; then - - save_config_vars "${workload_config_information}" \ - STATE_SUBSCRIPTION - - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Changing the subscription to: $STATE_SUBSCRIPTION $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - az account set --sub "${STATE_SUBSCRIPTION}" - - else - printf -v val %-40.40s "$STATE_SUBSCRIPTION" - echo "#########################################################################################" - echo "# #" - echo -e "#The provided state_subscription is not valid:$bold_red ${val} $reset_formatting#" - echo "# #" - echo "#########################################################################################" - echo "The provided subscription for the terraform storage is not valid: ${val}" >"${workload_config_information}".err - exit 65 - fi + if is_valid_guid "$STATE_SUBSCRIPTION"; then + + save_config_vars "${workload_config_information}" \ + STATE_SUBSCRIPTION + + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Changing the subscription to: $STATE_SUBSCRIPTION $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + az account set --sub "${STATE_SUBSCRIPTION}" + + else + printf -v val %-40.40s "$STATE_SUBSCRIPTION" + echo "#########################################################################################" + echo "# #" + echo -e "#The provided state_subscription is not valid:$bold_red ${val} $reset_formatting#" + echo "# #" + echo "#########################################################################################" + echo "The provided subscription for the terraform storage is not valid: ${val}" >"${workload_config_information}".err + exit 65 + fi fi if [ -n "$REMOTE_STATE_SA" ]; then - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" fi if [ -n "$keyvault" ]; then - if valid_kv_name "$keyvault"; then - save_config_var "keyvault" "${workload_config_information}" - else - printf -v val %-40.40s "$keyvault" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided keyvault is not valid:$bold_red ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - - echo "The provided keyvault is not valid: ${val}" >"${workload_config_information}".err - exit 65 - fi + if valid_kv_name "$keyvault"; then + save_config_var "keyvault" "${workload_config_information}" + else + printf -v val %-40.40s "$keyvault" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided keyvault is not valid:$bold_red ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + + echo "The provided keyvault is not valid: ${val}" >"${workload_config_information}".err + exit 65 + fi fi if [ ! -f "${workload_config_information}" ]; then - # Ask for deployer environment name and try to read the deployer state file and resource group details from the configuration file - if [ -z "$deployer_environment" ]; then - read -r -p "Deployer environment name: " deployer_environment - fi - - deployer_config_information="${automation_config_directory}"/"${deployer_environment}""${region_code}" - if [ -f "$deployer_config_information" ]; then - if [ -z "${keyvault}" ]; then - load_config_vars "${deployer_config_information}" "keyvault" - fi - - load_config_vars "${deployer_config_information}" "REMOTE_STATE_RG" - if [ -z "${REMOTE_STATE_SA}" ]; then - load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" - fi - load_config_vars "${deployer_config_information}" "tfstate_resource_id" - load_config_vars "${deployer_config_information}" "deployer_tfstate_key" - - save_config_vars "${workload_config_information}" \ - keyvault \ - subscription \ - deployer_tfstate_key \ - tfstate_resource_id \ - REMOTE_STATE_SA \ - REMOTE_STATE_RG - fi + # Ask for deployer environment name and try to read the deployer state file and resource group details from the configuration file + if [ -z "$deployer_environment" ]; then + read -r -p "Deployer environment name: " deployer_environment + fi + + deployer_config_information="${automation_config_directory}"/"${deployer_environment}""${region_code}" + if [ -f "$deployer_config_information" ]; then + if [ -z "${keyvault}" ]; then + load_config_vars "${deployer_config_information}" "keyvault" + fi + + load_config_vars "${deployer_config_information}" "REMOTE_STATE_RG" + if [ -z "${REMOTE_STATE_SA}" ]; then + load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" + fi + load_config_vars "${deployer_config_information}" "tfstate_resource_id" + load_config_vars "${deployer_config_information}" "deployer_tfstate_key" + + save_config_vars "${workload_config_information}" \ + keyvault \ + subscription \ + deployer_tfstate_key \ + tfstate_resource_id \ + REMOTE_STATE_SA \ + REMOTE_STATE_RG + fi fi if [ -z "$tfstate_resource_id" ]; then - echo "No tfstate_resource_id" - if [ -n "$deployer_environment" ]; then - deployer_config_information="${automation_config_directory}"/"${deployer_environment}""${region_code}" - echo "Deployer config file: $deployer_config_information" - if [ -f "$deployer_config_information" ]; then - load_config_vars "${deployer_config_information}" "keyvault" - load_config_vars "${deployer_config_information}" "REMOTE_STATE_RG" - load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" - load_config_vars "${deployer_config_information}" "tfstate_resource_id" - load_config_vars "${deployer_config_information}" "deployer_tfstate_key" - - save_config_vars "${workload_config_information}" \ - tfstate_resource_id - - save_config_vars "${workload_config_information}" \ - keyvault \ - subscription \ - deployer_tfstate_key \ - REMOTE_STATE_SA \ - REMOTE_STATE_RG - fi - fi + echo "No tfstate_resource_id" + if [ -n "$deployer_environment" ]; then + deployer_config_information="${automation_config_directory}"/"${deployer_environment}""${region_code}" + echo "Deployer config file: $deployer_config_information" + if [ -f "$deployer_config_information" ]; then + load_config_vars "${deployer_config_information}" "keyvault" + load_config_vars "${deployer_config_information}" "REMOTE_STATE_RG" + load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" + load_config_vars "${deployer_config_information}" "tfstate_resource_id" + load_config_vars "${deployer_config_information}" "deployer_tfstate_key" + + save_config_vars "${workload_config_information}" \ + tfstate_resource_id + + save_config_vars "${workload_config_information}" \ + keyvault \ + subscription \ + deployer_tfstate_key \ + REMOTE_STATE_SA \ + REMOTE_STATE_RG + fi + fi else - echo "Terraform Storage Account Id: $tfstate_resource_id" + echo "Terraform Storage Account Id: $tfstate_resource_id" - save_config_vars "${workload_config_information}" \ - tfstate_resource_id + save_config_vars "${workload_config_information}" \ + tfstate_resource_id fi echo "" @@ -367,275 +368,273 @@ export TF_DATA_DIR="${param_dirname}/.terraform" extra_vars="" if [ -f terraform.tfvars ]; then - extra_vars=" -var-file=${param_dirname}/terraform.tfvars " + extra_vars=" -var-file=${param_dirname}/terraform.tfvars " fi if [ -n "$subscription" ]; then - if is_valid_guid "$subscription"; then - echo "" - export ARM_SUBSCRIPTION_ID="${subscription}" - else - printf -v val %-40.40s "$subscription" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided subscription is not valid:$bold_red ${val} $reset_formatting# " - echo "# #" - echo "#########################################################################################" - - echo "The provided subscription is not valid: ${val}" >"${workload_config_information}".err - - exit 65 - fi + if is_valid_guid "$subscription"; then + echo "" + export ARM_SUBSCRIPTION_ID="${subscription}" + else + printf -v val %-40.40s "$subscription" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided subscription is not valid:$bold_red ${val} $reset_formatting# " + echo "# #" + echo "#########################################################################################" + + echo "The provided subscription is not valid: ${val}" >"${workload_config_information}".err + + exit 65 + fi fi if [ 0 = "${deploy_using_msi_only:-}" ]; then - if [ -n "$client_id" ]; then - if is_valid_guid "$client_id"; then - echo "" - else - printf -v val %-40.40s "$client_id" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided spn_id is not valid:$bold_red ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - exit 65 - fi - fi - - if [ -n "$tenant_id" ]; then - if is_valid_guid "$tenant_id"; then - echo "" - else - printf -v val %-40.40s "$tenant_id" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided tenant_id is not valid:$bold_red ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - exit 65 - fi - - fi - #setting the user environment variables - if [ -n "${spn_secret}" ]; then - set_executing_user_environment_variables "${spn_secret}" - else - set_executing_user_environment_variables "none" - fi + if [ -n "$client_id" ]; then + if is_valid_guid "$client_id"; then + echo "" + else + printf -v val %-40.40s "$client_id" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided spn_id is not valid:$bold_red ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + exit 65 + fi + fi + + if [ -n "$tenant_id" ]; then + if is_valid_guid "$tenant_id"; then + echo "" + else + printf -v val %-40.40s "$tenant_id" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided tenant_id is not valid:$bold_red ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + exit 65 + fi + + fi +fi + +#setting the user environment variables +if [ -n "${spn_secret}" ]; then + set_executing_user_environment_variables "${spn_secret}" else - #setting the user environment variables - set_executing_user_environment_variables "N/A" + set_executing_user_environment_variables "none" fi if [[ -z ${REMOTE_STATE_SA} ]]; then - load_config_vars "${workload_config_information}" "REMOTE_STATE_SA" + load_config_vars "${workload_config_information}" "REMOTE_STATE_SA" fi load_config_vars "${workload_config_information}" "REMOTE_STATE_RG" load_config_vars "${workload_config_information}" "tfstate_resource_id" if [[ -z ${STATE_SUBSCRIPTION} ]]; then - load_config_vars "${workload_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${workload_config_information}" "STATE_SUBSCRIPTION" fi if [[ -z ${subscription} ]]; then - load_config_vars "${workload_config_information}" "subscription" + load_config_vars "${workload_config_information}" "subscription" fi if [[ -z ${deployer_tfstate_key} ]]; then - load_config_vars "${workload_config_information}" "deployer_tfstate_key" + load_config_vars "${workload_config_information}" "deployer_tfstate_key" fi if [ -n "$tfstate_resource_id" ]; then - REMOTE_STATE_RG=$(echo "$tfstate_resource_id" | cut -d / -f5) - REMOTE_STATE_SA=$(echo "$tfstate_resource_id" | cut -d / -f9) - STATE_SUBSCRIPTION=$(echo "$tfstate_resource_id" | cut -d / -f3) - - save_config_vars "${workload_config_information}" \ - REMOTE_STATE_SA \ - REMOTE_STATE_RG \ - STATE_SUBSCRIPTION + REMOTE_STATE_RG=$(echo "$tfstate_resource_id" | cut -d / -f5) + REMOTE_STATE_SA=$(echo "$tfstate_resource_id" | cut -d / -f9) + STATE_SUBSCRIPTION=$(echo "$tfstate_resource_id" | cut -d / -f3) + + save_config_vars "${workload_config_information}" \ + REMOTE_STATE_SA \ + REMOTE_STATE_RG \ + STATE_SUBSCRIPTION else - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" fi if [ -z "$subscription" ]; then - subscription="${STATE_SUBSCRIPTION}" + subscription="${STATE_SUBSCRIPTION}" fi if [ -z "$REMOTE_STATE_SA" ]; then - if [ -z "$REMOTE_STATE_RG" ]; then - load_config_vars "${workload_config_information}" "tfstate_resource_id" - if [ -n "${tfstate_resource_id}" ]; then - REMOTE_STATE_RG=$(echo "$tfstate_resource_id" | cut -d / -f5) - REMOTE_STATE_SA=$(echo "$tfstate_resource_id" | cut -d / -f9) - STATE_SUBSCRIPTION=$(echo "$tfstate_resource_id" | cut -d / -f3) - fi - fi - - tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" - export TF_VAR_tfstate_resource_id=${tfstate_resource_id} + if [ -z "$REMOTE_STATE_RG" ]; then + load_config_vars "${workload_config_information}" "tfstate_resource_id" + if [ -n "${tfstate_resource_id}" ]; then + REMOTE_STATE_RG=$(echo "$tfstate_resource_id" | cut -d / -f5) + REMOTE_STATE_SA=$(echo "$tfstate_resource_id" | cut -d / -f9) + STATE_SUBSCRIPTION=$(echo "$tfstate_resource_id" | cut -d / -f3) + fi + fi + + tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" + export TF_VAR_tfstate_resource_id=${tfstate_resource_id} else - if [ -z "$REMOTE_STATE_RG" ]; then - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" - load_config_vars "${workload_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${workload_config_information}" "REMOTE_STATE_RG" - load_config_vars "${workload_config_information}" "tfstate_resource_id" - fi + if [ -z "$REMOTE_STATE_RG" ]; then + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" + load_config_vars "${workload_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${workload_config_information}" "REMOTE_STATE_RG" + load_config_vars "${workload_config_information}" "tfstate_resource_id" + fi fi useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --query allowSharedKeyAccess --subscription "${STATE_SUBSCRIPTION}" --out tsv) if [ "$useSAS" = "true" ]; then - echo "Storage Account authentication: key" - export ARM_USE_AZUREAD=false + echo "Storage Account authentication: key" + export ARM_USE_AZUREAD=false else - echo "Storage Account authentication: Entra ID" - export ARM_USE_AZUREAD=true + echo "Storage Account authentication: Entra ID" + export ARM_USE_AZUREAD=true fi if [ 1 = "${deploy_using_msi_only:-}" ]; then - if [ -n "${keyvault}" ]; then - echo "Setting the secrets" + if [ -n "${keyvault}" ]; then + echo "Setting the secrets" - echo "Calling set_secrets with: --workload --environment ${environment} --region ${region_code} --vault ${keyvault} \ + echo "Calling set_secrets with: --workload --environment ${environment} --region ${region_code} --vault ${keyvault} \ --keyvault_subscription ${STATE_SUBSCRIPTION} --subscription ${ARM_SUBSCRIPTION_ID} --msi" - "${SAP_AUTOMATION_REPO_PATH}"/deploy/scripts/set_secrets.sh --workload --environment "${environment}" --region "${region_code}" \ - --vault "${keyvault}" --keyvault_subscription "${STATE_SUBSCRIPTION}" --subscription "${ARM_SUBSCRIPTION_ID}" --msi + "${SAP_AUTOMATION_REPO_PATH}"/deploy/scripts/set_secrets.sh --workload --environment "${environment}" --region "${region_code}" \ + --vault "${keyvault}" --keyvault_subscription "${STATE_SUBSCRIPTION}" --subscription "${ARM_SUBSCRIPTION_ID}" --msi - if [ -f secret.err ]; then - error_message=$(cat secret.err) - echo "##vso[task.logissue type=error]${error_message}" - rm secret.err - exit 65 - fi - fi + if [ -f secret.err ]; then + error_message=$(cat secret.err) + echo "##vso[task.logissue type=error]${error_message}" + rm secret.err + exit 65 + fi + fi else - if [ -n "${keyvault}" ]; then - echo "Setting the secrets" - - save_config_var "client_id" "${workload_config_information}" - save_config_var "tenant_id" "${workload_config_information}" - - if [ -n "$spn_secret" ]; then - fixed_allParameters=$(printf " --workload --environment %s --region %s --vault %s --subscription %s --spn_secret ***** --keyvault_subscription %s --spn_id %s --tenant_id %s " "${environment}" "${region_code}" "${keyvault}" "${ARM_SUBSCRIPTION_ID}" "${STATE_SUBSCRIPTION}" "${client_id}" "${tenant_id}") - - echo "Calling set_secrets with: ${fixed_allParameters}" - - "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/set_secrets.sh" --workload --environment "${environment}" --region "${region_code}" --vault "${keyvault}" --subscription "$ARM_SUBSCRIPTION_ID" --keyvault_subscription "${STATE_SUBSCRIPTION}" --spn_id "${client_id}" --tenant_id "${tenant_id}" --spn_secret "${spn_secret}" - - if [ -f secret.err ]; then - error_message=$(cat secret.err) - echo "##vso[task.logissue type=error]${error_message}" - - exit 65 - fi - else - read -r -p "Do you want to specify the Workload SPN Details Y/N?" ans - answer=${ans^^} - if [ "${answer}" == 'Y' ]; then - allParameters=$(printf " --workload --environment %s --region %s --vault %s --subscription %s --spn_id %s " "${environment}" "${region_code}" "${keyvault}" "${STATE_SUBSCRIPTION}" "${client_id}") - - "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/set_secrets.sh ${allParameters}" - if [ $? -eq 255 ]; then - exit $? - fi - fi - fi - - if [ -f kv.log ]; then - rm kv.log - fi - fi + if [ -n "${keyvault}" ]; then + echo "Setting the secrets" + + save_config_var "client_id" "${workload_config_information}" + save_config_var "tenant_id" "${workload_config_information}" + + if [ -n "$spn_secret" ]; then + fixed_allParameters=$(printf " --workload --environment %s --region %s --vault %s --subscription %s --spn_secret ***** --keyvault_subscription %s --spn_id %s --tenant_id %s " "${environment}" "${region_code}" "${keyvault}" "${ARM_SUBSCRIPTION_ID}" "${STATE_SUBSCRIPTION}" "${client_id}" "${tenant_id}") + + echo "Calling set_secrets with: ${fixed_allParameters}" + + "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/set_secrets.sh" --workload --environment "${environment}" --region "${region_code}" --vault "${keyvault}" --subscription "$ARM_SUBSCRIPTION_ID" --keyvault_subscription "${STATE_SUBSCRIPTION}" --spn_id "${client_id}" --tenant_id "${tenant_id}" --spn_secret "${spn_secret}" + + if [ -f secret.err ]; then + error_message=$(cat secret.err) + echo "##vso[task.logissue type=error]${error_message}" + + exit 65 + fi + else + read -r -p "Do you want to specify the Workload SPN Details Y/N? " ans + answer=${ans^^} + if [ "${answer}" == 'Y' ]; then + allParameters=$(printf " --workload --environment %s --region %s --vault %s --subscription %s --spn_id %s " "${environment}" "${region_code}" "${keyvault}" "${STATE_SUBSCRIPTION}" "${client_id}") + + "${SAP_AUTOMATION_REPO_PATH}/deploy/scripts/set_secrets.sh ${allParameters}" + if [ $? -eq 255 ]; then + exit $? + fi + fi + fi + + if [ -f kv.log ]; then + rm kv.log + fi + fi fi if [ -z "${deployer_tfstate_key}" ]; then - load_config_vars "${workload_config_information}" "deployer_tfstate_key" - if [ -n "${deployer_tfstate_key}" ]; then - # Deployer state was specified in $CONFIG_REPO_PATH/.sap_deployment_automation library config - deployer_tfstate_key_parameter=" -var deployer_tfstate_key=${deployer_tfstate_key}" - export TF_VAR_deployer_tfstate_key_parameter=${deployer_tfstate_key} + load_config_vars "${workload_config_information}" "deployer_tfstate_key" + if [ -n "${deployer_tfstate_key}" ]; then + # Deployer state was specified in $CONFIG_REPO_PATH/.sap_deployment_automation library config + deployer_tfstate_key_parameter=" -var deployer_tfstate_key=${deployer_tfstate_key}" + export TF_VAR_deployer_tfstate_key_parameter=${deployer_tfstate_key} - fi + fi else - deployer_tfstate_key_parameter=" -var deployer_tfstate_key=${deployer_tfstate_key}" - export TF_VAR_deployer_tfstate_key_parameter=${deployer_tfstate_key} - save_config_vars "${workload_config_information}" deployer_tfstate_key + deployer_tfstate_key_parameter=" -var deployer_tfstate_key=${deployer_tfstate_key}" + export TF_VAR_deployer_tfstate_key_parameter=${deployer_tfstate_key} + save_config_vars "${workload_config_information}" deployer_tfstate_key fi if [ -z "${REMOTE_STATE_SA}" ]; then - read -p -r "Terraform state storage account name:" REMOTE_STATE_SA - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" - load_config_vars "${workload_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${workload_config_information}" "REMOTE_STATE_RG" - load_config_vars "${workload_config_information}" "tfstate_resource_id" - - tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" - export TF_VAR_tfstate_resource_id=${tfstate_resource_id} - - if [ -n "${STATE_SUBSCRIPTION}" ]; then - if [ "$account_set" == 0 ]; then - az account set --sub "${STATE_SUBSCRIPTION}" - account_set=1 - fi - fi + read -r -p "Terraform state storage account name: " REMOTE_STATE_SA + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" + load_config_vars "${workload_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${workload_config_information}" "REMOTE_STATE_RG" + load_config_vars "${workload_config_information}" "tfstate_resource_id" + + tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" + export TF_VAR_tfstate_resource_id=${tfstate_resource_id} + + if [ -n "${STATE_SUBSCRIPTION}" ]; then + if [ "$account_set" == 0 ]; then + az account set --sub "${STATE_SUBSCRIPTION}" + account_set=1 + fi + fi fi if [ -z "${REMOTE_STATE_RG}" ]; then - if [ -n "${REMOTE_STATE_SA}" ]; then - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" - load_config_vars "${workload_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${workload_config_information}" "REMOTE_STATE_RG" - load_config_vars "${workload_config_information}" "tfstate_resource_id" - - tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" - else - option="REMOTE_STATE_RG" - read -p -r "Remote state resource group name:" REMOTE_STATE_RG - save_config_vars "${workload_config_information}" REMOTE_STATE_RG - fi + if [ -n "${REMOTE_STATE_SA}" ]; then + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" + load_config_vars "${workload_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${workload_config_information}" "REMOTE_STATE_RG" + load_config_vars "${workload_config_information}" "tfstate_resource_id" + + tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" + else + option="REMOTE_STATE_RG" + read -r -p "Remote state resource group name: " REMOTE_STATE_RG + save_config_vars "${workload_config_information}" REMOTE_STATE_RG + fi fi if [ -n "${tfstate_resource_id}" ]; then - tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" - export TF_VAR_tfstate_resource_id=${tfstate_resource_id} + tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" + export TF_VAR_tfstate_resource_id=${tfstate_resource_id} else - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" - load_config_vars "${workload_config_information}" "tfstate_resource_id" - tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" - export TF_VAR_tfstate_resource_id=${tfstate_resource_id} + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${workload_config_information}" + load_config_vars "${workload_config_information}" "tfstate_resource_id" + tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id}" + export TF_VAR_tfstate_resource_id=${tfstate_resource_id} fi terraform_module_directory="$(realpath "${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/run/"${deployment_system}")" if [ ! -d "${terraform_module_directory}" ]; then - printf -v val %-40.40s "$deployment_system" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Incorrect system deployment type specified: ${val}$reset_formatting#" - echo "# #" - echo "# Valid options are: #" - echo "# sap_landscape #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 1 + printf -v val %-40.40s "$deployment_system" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Incorrect system deployment type specified: ${val}$reset_formatting#" + echo "# #" + echo "# Valid options are: #" + echo "# sap_landscape #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 1 fi apply_needed=false #Plugins if checkIfCloudShell; then - mkdir -p "${HOME}/.terraform.d/plugin-cache" - export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" + mkdir -p "${HOME}/.terraform.d/plugin-cache" + export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" else - if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then - mkdir -p /opt/terraform/.terraform.d/plugin-cache - sudo chown -R "$USER" /opt/terraform - fi - export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache + if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then + sudo mkdir -p /opt/terraform/.terraform.d/plugin-cache + sudo chown -R "$USER" /opt/terraform + fi + export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache fi echo "" @@ -645,54 +644,79 @@ echo "Subscription: ${STATE_SUBSCRIPTION}" echo "Storage Account: ${REMOTE_STATE_SA}" echo "Resource Group: ${REMOTE_STATE_RG}" echo "State file: ${key}.terraform.tfstate" -echo "Target subscription: ${ARM_SUBSCRIPTION_ID}" +echo "Target subscription: $ARM_SUBSCRIPTION_ID" + +TF_VAR_subscription_id="$ARM_SUBSCRIPTION_ID" +export TF_VAR_subscription_id if [ ! -d .terraform/ ]; then - terraform -chdir="${terraform_module_directory}" init -upgrade=true \ - --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ - --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ - --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate" - return_value=$? + if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true \ + --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ + --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ + --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + else + return_value=0 + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + fi else - check_output=1 - local_backend=$(grep "\"type\": \"local\"" .terraform/terraform.tfstate || true) - if [ -n "${local_backend}" ]; then - - terraform -chdir="${terraform_module_directory}" init -upgrade=true -force-copy \ - --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ - --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ - --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate" - return_value=$? - else - terraform -chdir="${terraform_module_directory}" init -upgrade=true -reconfigure \ - --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ - --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ - --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate" - return_value=$? - fi + check_output=1 + local_backend=$(grep "\"type\": \"local\"" .terraform/terraform.tfstate || true) + if [ -n "${local_backend}" ]; then + + if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true -force-copy \ + --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ + --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ + --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + else + return_value=0 + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + fi + else + if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true; then + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + else + return_value=0 + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + fi + + fi fi if [ 0 != $return_value ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore!!! Error when Initializing !!!$reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "Terraform initialization failed" - exit $return_value + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore!!! Error when Initializing !!!$reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "Terraform initialization failed" + exit $return_value fi - if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - check_output=1 + check_output=1 else - check_output=0 + check_output=0 fi save_config_var "REMOTE_STATE_SA" "${workload_config_information}" @@ -700,69 +724,71 @@ save_config_var "subscription" "${workload_config_information}" save_config_var "STATE_SUBSCRIPTION" "${workload_config_information}" save_config_var "tfstate_resource_id" "${workload_config_information}" +allParameters=$(printf " -var-file=%s %s %s %s " "${var_file}" "${extra_vars}" "${tfstate_parameter}" "${deployer_tfstate_key_parameter}") + if [ 1 == $check_output ]; then - if terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - - check_output=0 - apply_needed=1 - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan New deployment $reset_formatting #" - echo "# #" - echo "#########################################################################################" - else - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Existing deployment was detected $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - workloadkeyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw workloadzone_kv_name | tr -d \") - if valid_kv_name "$workloadkeyvault"; then - save_config_var "workloadkeyvault" "${workload_config_information}" - fi - - deployed_using_version=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw automation_version) - if [ -z "${deployed_using_version}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red The environment was deployed using an older version of the Terrafrom templates $reset_formatting #" - echo "# #" - echo "# !!! Risk for Data loss !!! #" - echo "# #" - echo "# Please inspect the output of Terraform plan carefully before proceeding #" - echo "# #" - echo "#########################################################################################" - if [ 1 == $called_from_ado ]; then - unset TF_DATA_DIR - echo "The environment was deployed using an older version of the Terrafrom templates, Risk for data loss" >"${workload_config_information}".err - - exit 1 - fi - - read -p -r "Do you want to continue Y/N?" ans - answer=${ans^^} - if [ "$answer" == 'Y' ]; then - apply_needed=1 - else - unset TF_DATA_DIR - exit 1 - fi - else - printf -v val %-.20s "$deployed_using_version" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Deployed using the Terraform templates version: $val $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - #Add version logic here - fi - fi + if terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then + + check_output=0 + apply_needed=1 + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan New deployment $reset_formatting #" + echo "# #" + echo "#########################################################################################" + else + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Existing deployment was detected $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + workloadkeyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw workloadzone_kv_name | tr -d \") + if valid_kv_name "$workloadkeyvault"; then + save_config_var "workloadkeyvault" "${workload_config_information}" + fi + + deployed_using_version=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw automation_version) + if [ -z "${deployed_using_version}" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red The environment was deployed using an older version of the Terrafrom templates $reset_formatting #" + echo "# #" + echo "# !!! Risk for Data loss !!! #" + echo "# #" + echo "# Please inspect the output of Terraform plan carefully before proceeding #" + echo "# #" + echo "#########################################################################################" + if [ 1 == $called_from_ado ]; then + unset TF_DATA_DIR + echo "The environment was deployed using an older version of the Terraform templates, Risk for data loss" >"${workload_config_information}".err + + exit 1 + fi + + read -r -p "Do you want to continue Y/N? " ans + answer=${ans^^} + if [ "$answer" == 'Y' ]; then + apply_needed=1 + else + unset TF_DATA_DIR + exit 1 + fi + else + printf -v val %-.20s "$deployed_using_version" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Deployed using the Terraform templates version: $val $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + #Add version logic here + fi + fi fi export TF_VAR_tfstate_resource_id="${tfstate_resource_id}" @@ -770,60 +796,82 @@ export TF_VAR_subscription="${subscription}" export TF_VAR_management_subscription="${STATE_SUBSCRIPTION}" if [ 1 == $check_output ]; then - deployed_using_version=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw automation_version) - if [ -n "${deployed_using_version}" ]; then - printf -v val %-.20s "$deployed_using_version" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Deployed using the Terraform templates version: $val $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - version_compare "${deployed_using_version}" "3.13.2.0" - older_version=$? - if [ 2 == $older_version ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Deployed using an older version $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - # Remeadiating the Storage Accounts and File Shares - - moduleID='module.sap_landscape.azurerm_storage_account.storage_bootdiag[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" - - moduleID='module.sap_landscape.azurerm_storage_account.witness_storage[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" - - moduleID='module.sap_landscape.azurerm_storage_account.install[0]' - azureResourceID=$(terraform -chdir="${terraform_module_directory}" state show "${moduleID}" | grep -m1 " id " | xargs | cut -d "=" -f2 | xargs) - - resourceGroupName=$(az resource show --ids "${azureResourceID}" --query "resourceGroup" --output tsv) - resourceType=$(az resource show --ids "${azureResourceID}" --query "type" --output tsv) - resourceName=$(az resource show --ids "${azureResourceID}" --query "name" --output tsv) - az resource lock create --lock-type CanNotDelete -n "SAP Installation Media account delete lock" --subscription "${subscription}" \ - --resource-group "${resourceGroupName}" --resource "${resourceName}" --resource-type "${resourceType}" - - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" - - moduleID='module.sap_landscape.azurerm_storage_account.transport[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" - - moduleID='module.sap_landscape.azurerm_storage_share.transport[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" - - moduleID='module.sap_landscape.azurerm_storage_share.install[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" - - moduleID='module.sap_landscape.azurerm_storage_share.install_smb[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" - - fi - fi + deployed_using_version=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw automation_version) + if [ -n "${deployed_using_version}" ]; then + printf -v val %-.20s "$deployed_using_version" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Deployed using the Terraform templates version: $val $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + version_compare "${deployed_using_version}" "3.13.2.0" + older_version=$? + + if [ 2 == $older_version ]; then + + if terraform -chdir="${terraform_module_directory}" state rm module.sap_landscape.azurerm_private_dns_a_record.transport[0]; then + echo "Removed the transport private DNS record" + fi + if terraform -chdir="${terraform_module_directory}" state rm module.sap_landscape.azurerm_private_dns_a_record.install[0]; then + echo "Removed the transport private DNS record" + fi + if terraform -chdir="${terraform_module_directory}" state rm module.sap_landscape.azurerm_private_dns_a_record.keyvault[0]; then + echo "Removed the transport private DNS record" + fi + + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Deployed using an older version $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + # Remediating the Storage Accounts and File Shares + + moduleID='module.sap_landscape.azurerm_storage_account.storage_bootdiag[0]' + storage_account_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw storageaccount_name) + storage_account_rg_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw storageaccount_rg_name) + STORAGE_ACCOUNT_ID=$(az storage account show --name "${storage_account_name}" --resource-group "${storage_account_rg_name}" --query "id" --output tsv) + export STORAGE_ACCOUNT_ID + + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "providers/Microsoft.Storage/storageAccounts" + + moduleID='module.sap_landscape.azurerm_storage_account.witness_storage[0]' + storage_account_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw witness_storage_account) + STORAGE_ACCOUNT_ID=$(az storage account show --name "${storage_account_name}" --resource-group "${storage_account_rg_name}" --query "id" --output tsv) + export STORAGE_ACCOUNT_ID + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "providers/Microsoft.Storage/storageAccounts" + unset STORAGE_ACCOUNT_ID + + moduleID='module.sap_landscape.azurerm_storage_account.install[0]' + azureResourceID=$(terraform -chdir="${terraform_module_directory}" state show "${moduleID}" | grep -m1 providers/Microsoft.Storage/storageAccounts | xargs | cut -d "=" -f2 | xargs) + + resourceGroupName=$(az resource show --ids "${azureResourceID}" --query "resourceGroup" --output tsv) + resourceType=$(az resource show --ids "${azureResourceID}" --query "type" --output tsv) + resourceName=$(az resource show --ids "${azureResourceID}" --query "name" --output tsv) + az resource lock create --lock-type CanNotDelete -n "SAP Installation Media account delete lock" --subscription "${subscription}" \ + --resource-group "${resourceGroupName}" --resource "${resourceName}" --resource-type "${resourceType}" + + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" + + moduleID='module.sap_landscape.azurerm_storage_account.transport[0]' + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "providers/Microsoft.Storage/storageAccounts" + + moduleID='module.sap_landscape.azurerm_storage_share.transport[0]' + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" + + moduleID='module.sap_landscape.azurerm_storage_share.install[0]' + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" + + moduleID='module.sap_landscape.azurerm_storage_share.install_smb[0]' + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" + + fi + fi fi echo "" @@ -838,239 +886,241 @@ allParameters=$(printf " -var-file=%s %s %s %s " "${var_file}" "${extra_vars}" " # shellcheck disable=SC2086 if ! terraform -chdir="$terraform_module_directory" plan -detailed-exitcode $allParameters -input=false | tee -a plan_output.log; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore !!! Error when running plan !!! $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - if [ -f plan_output.log ]; then - rm plan_output.log - fi - exit $return_value - fi + return_value=$? + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform plan: failed$reset_formatting" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore !!! Error when running plan !!! $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + if [ -f plan_output.log ]; then + rm plan_output.log + fi + exit $return_value + fi else - return_value=$? + return_value=$? + echo "" + echo -e "${cyan}Terraform plan: succeeded$reset_formatting" + echo "" fi if [ $check_output == 0 ]; then - if [ -f plan_output.log ]; then - rm plan_output.log - fi - return_code=2 + if [ -f plan_output.log ]; then + rm plan_output.log + fi + return_code=2 fi echo "Terraform Plan return code: $return_value" apply_needed=1 if [ "${TEST_ONLY}" == "True" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Running plan only. $reset_formatting #" - echo "# #" - echo "# No deployment performed. #" - echo "# #" - echo "#########################################################################################" - echo "" - if [ -f plan_output.log ]; then - rm plan_output.log - fi - exit 0 + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Running plan only. $reset_formatting #" + echo "# #" + echo "# No deployment performed. #" + echo "# #" + echo "#########################################################################################" + echo "" + if [ -f plan_output.log ]; then + rm plan_output.log + fi + exit 0 fi if [ -f plan_output.log ]; then - cat plan_output.log - LASTERROR=$(grep -m1 'Error: ' plan_output.log || true) - - if [ -n "${LASTERROR}" ]; then - echo "3" - if [ 1 == $called_from_ado ]; then - echo "##vso[task.logissue type=error]$LASTERROR" - fi - - return_value=1 - fi - if [ 1 != $return_value ]; then - test=$(grep -m1 "replaced" plan_output.log | grep kv_user || true) - if [ -n "${test}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red !!! Risk for Data loss !!! $reset_formatting #" - echo "# #" - echo "# Please inspect the output of Terraform plan carefully before proceeding #" - echo "# #" - echo "#########################################################################################" - echo "" - if [ 1 == $called_from_ado ]; then - unset TF_DATA_DIR - exit 11 - fi - read -n 1 -r -s -p $'Press enter to continue...\n' - - cat plan_output.log - read -p -r "Do you want to continue with the deployment Y/N?" ans - answer=${ans^^} - if [ "${answer}" == 'Y' ]; then - apply_needed=1 - else - unset TF_DATA_DIR - - exit 0 - fi - else - apply_needed=1 - fi - fi + cat plan_output.log + LASTERROR=$(grep -m1 'Error: ' plan_output.log || true) + + if [ -n "${LASTERROR}" ]; then + echo "3" + if [ 1 == $called_from_ado ]; then + echo "##vso[task.logissue type=error]$LASTERROR" + fi + + return_value=1 + fi + if [ 1 != $return_value ]; then + test=$(grep -m1 "replaced" plan_output.log | grep kv_user || true) + if [ -n "${test}" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red !!! Risk for Data loss !!! $reset_formatting #" + echo "# #" + echo "# Please inspect the output of Terraform plan carefully before proceeding #" + echo "# #" + echo "#########################################################################################" + echo "" + if [ 1 == $called_from_ado ]; then + unset TF_DATA_DIR + exit 11 + fi + read -n 1 -r -s -p $'Press enter to continue...\n' + + cat plan_output.log + read -r -p "Do you want to continue with the deployment Y/N? " ans + answer=${ans^^} + if [ "${answer}" == 'Y' ]; then + apply_needed=1 + else + unset TF_DATA_DIR + + exit 0 + fi + else + apply_needed=1 + fi + fi fi if [ 0 == $return_value ]; then - if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - workloadkeyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw workloadzone_kv_name | tr -d \") - if valid_kv_name "$workloadkeyvault"; then - save_config_var "workloadkeyvault" "${workload_config_information}" - fi - save_config_vars "landscape_tfstate_key" "${workload_config_information}" - - fi + if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then + workloadkeyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw workloadzone_kv_name | tr -d \") + if valid_kv_name "$workloadkeyvault"; then + save_config_var "workloadkeyvault" "${workload_config_information}" + fi + save_config_vars "landscape_tfstate_key" "${workload_config_information}" + + fi fi if [ 1 == $apply_needed ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Running Terraform apply $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - parallelism=10 - - #Provide a way to limit the number of parallell tasks for Terraform - if [[ -n "${TF_PARALLELLISM}" ]]; then - parallelism=$TF_PARALLELLISM - fi - - allParameters=$(printf " -var-file=%s %s %s %s" "${var_file}" "${extra_vars}" "${tfstate_parameter}" "${deployer_tfstate_key_parameter}") - allImportParameters=$(printf " -var-file=%s %s %s %s" "${var_file}" "${extra_vars}" "${tfstate_parameter}" "${deployer_tfstate_key_parameter}") - - # shellcheck disable=SC2086 - - if [ -n "${approve}" ]; then - # Using if so that no zero return codes don't fail -o errexit - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply "${approve}" -parallelism="${parallelism}" -no-color -json $allParameters -input=false | tee -a apply_output.json; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - else - return_value=$? - fi - else - # Using if so that no zero return codes don't fail -o errexit - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply "${approve}" -parallelism="${parallelism}" $allParameters -input=false; then - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - else - return_value=$? - fi - fi - - return_value=$? + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Running Terraform apply $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + parallelism=10 + + #Provide a way to limit the number of parallell tasks for Terraform + if [[ -n "${TF_PARALLELLISM}" ]]; then + parallelism=$TF_PARALLELLISM + fi + + allParameters=$(printf " -var-file=%s %s %s %s" "${var_file}" "${extra_vars}" "${tfstate_parameter}" "${deployer_tfstate_key_parameter}") + allImportParameters=$(printf " -var-file=%s %s %s %s" "${var_file}" "${extra_vars}" "${tfstate_parameter}" "${deployer_tfstate_key_parameter}") + + # shellcheck disable=SC2086 + + if [ -n "${approve}" ]; then + # Using if so that no zero return codes don't fail -o errexit + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply "${approve}" -parallelism="${parallelism}" -no-color -json $allParameters -input=false | tee -a apply_output.json; then + return_value=$? + if [ $return_value -eq 1 ]; then + echo "Errors when running Terraform apply" + else + # return code 2 is ok + return_value=0 + fi + else + return_value=$? + fi + else + # Using if so that no zero return codes don't fail -o errexit + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" $allParameters -input=false; then + if [ $return_value -eq 1 ]; then + echo "Errors when running Terraform apply" + else + # return code 2 is ok + return_value=0 + fi + else + return_value=$? + fi + fi + + return_value=$? fi if [ -f apply_output.json ]; then - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - if [ -f apply_output.json ]; then - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - if [ -f apply_output.json ]; then - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - if [ -f apply_output.json ]; then - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - if [ -f apply_output.json ]; then - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - if [ -f apply_output.json ]; then - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - if [ -f apply_output.json ]; then - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + if [ -f apply_output.json ]; then + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + if [ -f apply_output.json ]; then + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + if [ -f apply_output.json ]; then + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + if [ -f apply_output.json ]; then + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + if [ -f apply_output.json ]; then + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + if [ -f apply_output.json ]; then + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi fi if [ -f apply_output.json ]; then - rm apply_output.json + rm apply_output.json fi save_config_var "landscape_tfstate_key" "${workload_config_information}" -if [ 0 == $return_value ]; then - - if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - - workload_zone_prefix=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw workload_zone_prefix | tr -d \") - save_config_var "workload_zone_prefix" "${workload_config_information}" - save_config_vars "landscape_tfstate_key" "${workload_config_information}" - workloadkeyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw workloadzone_kv_name | tr -d \") +if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - resourceGroupName=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") + workload_zone_prefix=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw workload_zone_prefix | tr -d \") + save_config_var "workload_zone_prefix" "${workload_config_information}" + save_config_vars "landscape_tfstate_key" "${workload_config_information}" + workloadkeyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw workloadzone_kv_name | tr -d \") - temp=$(echo "${workloadkeyvault}" | grep "Warning" || true) - if [ -z "${temp}" ]; then - temp=$(echo "${workloadkeyvault}" | grep "Backend reinitialization required" || true) - if [ -z "${temp}" ]; then + resourceGroupName=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") - printf -v val %-.20s "$workloadkeyvault" + temp=$(echo "${workloadkeyvault}" | grep "Warning" || true) + if [ -z "${temp}" ]; then + temp=$(echo "${workloadkeyvault}" | grep "Backend reinitialization required" || true) + if [ -z "${temp}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# Keyvault to use for System details:$cyan $val $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" + printf -v val %-.20s "$workloadkeyvault" - save_config_var "workloadkeyvault" "${workload_config_information}" - fi - fi - fi + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# Keyvault to use for System details:$cyan $val $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + save_config_var "workloadkeyvault" "${workload_config_information}" + fi + fi fi if [ 0 != $return_value ]; then - unset TF_DATA_DIR - exit $return_value + unset TF_DATA_DIR + exit $return_value fi echo "" @@ -1085,8 +1135,8 @@ full_script_path="$(realpath "${BASH_SOURCE[0]}")" script_directory="$(dirname "${full_script_path}")" if [ -n "${resourceGroupName}" ]; then - az deployment group create --resource-group "${resourceGroupName}" --name "SAP-WORKLOAD-ZONE_${resourceGroupName}" --subscription "${subscription}" \ - --template-file "${script_directory}/templates/empty-deployment.json" --output none + az deployment group create --resource-group "${resourceGroupName}" --name "SAP-WORKLOAD-ZONE_${resourceGroupName}" --subscription "$ARM_SUBSCRIPTION_ID" \ + --template-file "${script_directory}/templates/empty-deployment.json" --output none --only-show-errors --no-wait fi now=$(date) @@ -1115,7 +1165,7 @@ echo "# echo "#########################################################################################" if [ -f "${workload_config_information}".err ]; then - cat "${workload_config_information}".err + cat "${workload_config_information}".err fi unset TF_DATA_DIR @@ -1128,25 +1178,25 @@ unset TF_DATA_DIR ################################################################################# if [ "$useSAS" = "true" ]; then - container_exists=$(az storage container exists --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors --query exists) + container_exists=$(az storage container exists --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors --query exists) else - container_exists=$(az storage container exists --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors --query exists --auth-mode login) + container_exists=$(az storage container exists --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors --query exists --auth-mode login) fi if [ "${container_exists}" == "false" ]; then - if [ "$useSAS" = "true" ]; then - az storage container create --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors - else - az storage container create --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --auth-mode login --only-show-errors - fi + if [ "$useSAS" = "true" ]; then + az storage container create --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors + else + az storage container create --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --auth-mode login --only-show-errors + fi fi if [ "$useSAS" = "true" ]; then - az storage blob upload --file "${parameterfile}" --container-name tfvars/LANDSCAPE/"${key}" --name "${parameterfile_name}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none + az storage blob upload --file "${parameterfile}" --container-name tfvars/LANDSCAPE/"${key}" --name "${parameterfile_name}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none else - az storage blob upload --file "${parameterfile}" --container-name tfvars/LANDSCAPE/"${key}" --name "${parameterfile_name}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --auth-mode login --only-show-errors --output none + az storage blob upload --file "${parameterfile}" --container-name tfvars/LANDSCAPE/"${key}" --name "${parameterfile_name}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --auth-mode login --only-show-errors --output none fi exit $return_value diff --git a/deploy/scripts/installer.sh b/deploy/scripts/installer.sh index 2ef3d79ffd..d944eccd6d 100755 --- a/deploy/scripts/installer.sh +++ b/deploy/scripts/installer.sh @@ -23,66 +23,66 @@ source "${script_directory}/deploy_utils.sh" source "${script_directory}/helpers/script_helpers.sh" function showhelp { - echo "" - echo "#########################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to deploy the different systems #" - echo "# The script experts the following exports: #" - echo "# #" - echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" - echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing the cloned sap-automation#" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" - echo "# #" - echo "# #" - echo "# Usage: installer.sh #" - echo "# -p or --parameterfile parameter file #" - echo "# -t or --type type of system to remove #" - echo "# valid options: #" - echo "# sap_deployer #" - echo "# sap_library #" - echo "# sap_landscape #" - echo "# sap_system #" - echo "# #" - echo "# Optional parameters #" - echo "# #" - echo "# -o or --storageaccountname Storage account name for state file #" - echo "# -d or --deployer_tfstate_key Deployer terraform state file name #" - echo "# -l or --landscape_tfstate_key Workload zone terraform state file name #" - echo "# -s or --state_subscription Subscription for tfstate storage account #" - echo "# -i or --auto-approve Silent install #" - echo "# -h or --help Show help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/installer.sh \ #" - echo "# --parameterfile DEV-WEEU-SAP01-X00 \ #" - echo "# --type sap_system #" - echo "# --auto-approve #" - echo "# #" - echo "#########################################################################################" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to deploy the different systems #" + echo "# The script experts the following exports: #" + echo "# #" + echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" + echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing the cloned sap-automation#" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config) #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" + echo "# #" + echo "# #" + echo "# Usage: installer.sh #" + echo "# -p or --parameterfile parameter file #" + echo "# -t or --type type of system to remove #" + echo "# valid options: #" + echo "# sap_deployer #" + echo "# sap_library #" + echo "# sap_landscape #" + echo "# sap_system #" + echo "# #" + echo "# Optional parameters #" + echo "# #" + echo "# -o or --storageaccountname Storage account name for state file #" + echo "# -d or --deployer_tfstate_key Deployer terraform state file name #" + echo "# -l or --landscape_tfstate_key Workload zone terraform state file name #" + echo "# -s or --state_subscription Subscription for tfstate storage account #" + echo "# -i or --auto-approve Silent install #" + echo "# -h or --help Show help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/installer.sh \ #" + echo "# --parameterfile DEV-WEEU-SAP01-X00 \ #" + echo "# --type sap_system #" + echo "# --auto-approve #" + echo "# #" + echo "#########################################################################################" } function missing { - printf -v val %-.40s "$1" - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Missing environment variables: ${option}!!! #" - echo "# #" - echo "# Please export the folloing variables: #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the automation repo folder (sap-automation)) #" - echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config)) #" - echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" - echo "# REMOTE_STATE_RG (resource group name for storage account containing state files) #" - echo "# REMOTE_STATE_SA (storage account for state file) #" - echo "# #" - echo "#########################################################################################" - return 0 + printf -v val %-.40s "$1" + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Missing environment variables: ${option}!!! #" + echo "# #" + echo "# Please export the folloing variables: #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the automation repo folder (sap-automation)) #" + echo "# CONFIG_REPO_PATH (path to the configuration repo folder (sap-config)) #" + echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" + echo "# REMOTE_STATE_RG (resource group name for storage account containing state files) #" + echo "# REMOTE_STATE_SA (storage account for state file) #" + echo "# #" + echo "#########################################################################################" + return 0 } force=0 @@ -91,67 +91,67 @@ INPUT_ARGUMENTS=$(getopt -n installer -o p:t:o:d:l:s:ahif --longoptions type:,pa VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp - exit 3 + showhelp + exit 3 fi called_from_ado=0 eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -t | --type) - deployment_system="$2" - shift 2 - ;; - -p | --parameterfile) - parameterfile="$2" - shift 2 - ;; - -o | --storageaccountname) - REMOTE_STATE_SA="$2" - shift 2 - ;; - -s | --state_subscription) - STATE_SUBSCRIPTION="$2" - shift 2 - ;; - -d | --deployer_tfstate_key) - deployer_tfstate_key="$2" - shift 2 - ;; - -l | --landscape_tfstate_key) - landscape_tfstate_key="$2" - shift 2 - ;; - -a | --ado) - called_from_ado=1 - approve="--auto-approve" - TF_IN_AUTOMATION=true - export TF_IN_AUTOMATION - shift - ;; - -f | --force) - force=1 - shift - ;; - -i | --auto-approve) - approve="--auto-approve" - shift - ;; - -h | --help) - showhelp - exit 3 - ;; - --) - shift - break - ;; - esac + case "$1" in + -t | --type) + deployment_system="$2" + shift 2 + ;; + -p | --parameterfile) + parameterfile="$2" + shift 2 + ;; + -o | --storageaccountname) + REMOTE_STATE_SA="$2" + shift 2 + ;; + -s | --state_subscription) + STATE_SUBSCRIPTION="$2" + shift 2 + ;; + -d | --deployer_tfstate_key) + deployer_tfstate_key="$2" + shift 2 + ;; + -l | --landscape_tfstate_key) + landscape_tfstate_key="$2" + shift 2 + ;; + -a | --ado) + called_from_ado=1 + approve="--auto-approve" + TF_IN_AUTOMATION=true + export TF_IN_AUTOMATION + shift + ;; + -f | --force) + force=1 + shift + ;; + -i | --auto-approve) + approve="--auto-approve" + shift + ;; + -h | --help) + showhelp + exit 3 + ;; + --) + shift + break + ;; + esac done if [ "$DEBUG" = True ]; then - echo -e "$cyanEnabling debug mode$reset_formatting" - set -x - set -o errexit + echo -e "${cyan}Enabling debug mode$reset_formatting" + set -x + set -o errexit fi echo "Parameter file: $parameterfile" @@ -165,85 +165,85 @@ parameterfile_name=$(basename "${parameterfile}") param_dirname=$(dirname "${parameterfile}") if [ "${param_dirname}" != '.' ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Please run this command from the folder containing the parameter file $reset_formatting #" - echo "# #" - echo "#########################################################################################" - exit 3 + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Please run this command from the folder containing the parameter file $reset_formatting #" + echo "# #" + echo "#########################################################################################" + exit 3 fi if [ ! -f "${parameterfile}" ]; then - printf -v val %-35.35s "$parameterfile" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Parameter file does not exist: ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" + printf -v val %-35.35s "$parameterfile" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Parameter file does not exist: ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" - echo "Parameter file does not exist: ${val}" >"${system_config_information}".err + echo "Parameter file does not exist: ${val}" >"${system_config_information}".err - exit 2 #No such file or directory + exit 2 #No such file or directory fi if [ -z "${deployment_system}" ]; then - printf -v val %-40.40s "$deployment_system" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Incorrect system deployment type specified: ${val}$reset_formatting#" - echo "# #" - echo "# Valid options are: #" - echo "# sap_deployer #" - echo "# sap_library #" - echo "# sap_landscape #" - echo "# sap_system #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 64 #script usage wrong + printf -v val %-40.40s "$deployment_system" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Incorrect system deployment type specified: ${val}$reset_formatting#" + echo "# #" + echo "# Valid options are: #" + echo "# sap_deployer #" + echo "# sap_library #" + echo "# sap_landscape #" + echo "# sap_system #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 64 #script usage wrong fi # Check that the exports ARM_SUBSCRIPTION_ID and SAP_AUTOMATION_REPO_PATH are defined validate_exports return_code=$? if [ 0 != $return_code ]; then - echo "Missing exports" >"${system_config_information}".err - exit $return_code + echo "Missing exports" >"${system_config_information}".err + exit $return_code fi # Check that Terraform and Azure CLI is installed validate_dependencies return_code=$? if [ 0 != $return_code ]; then - echo "Missing software" >"${system_config_information}".err - exit $return_code + echo "Missing software" >"${system_config_information}".err + exit $return_code fi # Check that parameter files have environment and location defined validate_key_parameters "$parameterfile_name" return_code=$? if [ 0 != $return_code ]; then - echo "Missing parameters in $parameterfile_name" >"${system_config_information}".err - exit $return_code + echo "Missing parameters in $parameterfile_name" >"${system_config_information}".err + exit $return_code fi region=$(echo "${region}" | tr "[:upper:]" "[:lower:]") if valid_region_name "${region}"; then - # Convert the region to the correct code - get_region_code "${region}" + # Convert the region to the correct code + get_region_code "${region}" else - echo "Invalid region: $region" - exit 2 + echo "Invalid region: $region" + exit 2 fi key=$(echo "${parameterfile_name}" | cut -d. -f1) network_logical_name="" if [ "${deployment_system}" == sap_system ]; then - load_config_vars "$parameterfile_name" "network_logical_name" - network_logical_name=$(echo "${network_logical_name}" | tr "[:lower:]" "[:upper:]") + load_config_vars "$parameterfile_name" "network_logical_name" + network_logical_name=$(echo "${network_logical_name}" | tr "[:lower:]" "[:upper:]") fi #Persisting the parameters across executions @@ -257,28 +257,28 @@ echo "Deployment region: $region" echo "Deployment region code: $region_code" if [ 1 == $called_from_ado ]; then - this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 - export TF_VAR_Agent_IP=$this_ip - echo "Agent IP: $this_ip" + this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 + export TF_VAR_Agent_IP=$this_ip + echo "Agent IP: $this_ip" fi # Terraform Plugins if checkIfCloudShell; then - mkdir -p "${HOME}/.terraform.d/plugin-cache" - export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" + mkdir -p "${HOME}/.terraform.d/plugin-cache" + export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" else - if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then - mkdir -p /opt/terraform/.terraform.d/plugin-cache - sudo chown -R "$USER" /opt/terraform - fi - export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache + if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then + sudo mkdir -p /opt/terraform/.terraform.d/plugin-cache + sudo chown -R "$USER" /opt/terraform + fi + export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache fi parallelism=10 #Provide a way to limit the number of parallell tasks for Terraform if [[ -n "$TF_PARALLELLISM" ]]; then - parallelism=$TF_PARALLELLISM + parallelism=$TF_PARALLELLISM fi echo "Parallelism count: $parallelism" @@ -295,164 +295,164 @@ export TF_VAR_tfstate_resource_id var_file="${param_dirname}"/"${parameterfile}" if [ -f terraform.tfvars ]; then - extra_vars="-var-file=${param_dirname}/terraform.tfvars" + extra_vars="-var-file=${param_dirname}/terraform.tfvars" else - unset extra_vars + unset extra_vars fi if [ "${deployment_system}" == sap_deployer ]; then - deployer_tfstate_key=${key}.terraform.tfstate - ARM_SUBSCRIPTION_ID=$STATE_SUBSCRIPTION - export ARM_SUBSCRIPTION_ID + deployer_tfstate_key=${key}.terraform.tfstate + ARM_SUBSCRIPTION_ID=$STATE_SUBSCRIPTION + export ARM_SUBSCRIPTION_ID fi if [[ -z $STATE_SUBSCRIPTION ]]; then - STATE_SUBSCRIPTION=$ARM_SUBSCRIPTION_ID + STATE_SUBSCRIPTION=$ARM_SUBSCRIPTION_ID fi if [[ -n $STATE_SUBSCRIPTION ]]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Changing the subscription to: $STATE_SUBSCRIPTION $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - az account set --sub "${STATE_SUBSCRIPTION}" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Changing the subscription to: $STATE_SUBSCRIPTION $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + az account set --sub "${STATE_SUBSCRIPTION}" - return_code=$? - if [ 0 != $return_code ]; then + return_code=$? + if [ 0 != $return_code ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red The deployment account (MSI or SPN) does not have access to $reset_formatting #" - echo -e "# $bold_red ${STATE_SUBSCRIPTION} $reset_formatting #" - echo "# #" - echo "#########################################################################################" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red The deployment account (MSI or SPN) does not have access to $reset_formatting #" + echo -e "# $bold_red ${STATE_SUBSCRIPTION} $reset_formatting #" + echo "# #" + echo "#########################################################################################" - echo "##vso[task.logissue type=error]The deployment account (MSI or SPN) does not have access to ${STATE_SUBSCRIPTION}" - exit $return_code - fi + echo "##vso[task.logissue type=error]The deployment account (MSI or SPN) does not have access to ${STATE_SUBSCRIPTION}" + exit $return_code + fi - account_set=1 + account_set=1 fi if [[ -z $REMOTE_STATE_SA ]]; then - load_config_vars "${system_config_information}" "REMOTE_STATE_SA" - load_config_vars "${system_config_information}" "REMOTE_STATE_RG" - load_config_vars "${system_config_information}" "tfstate_resource_id" - load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${system_config_information}" "ARM_SUBSCRIPTION_ID" + load_config_vars "${system_config_information}" "REMOTE_STATE_SA" + load_config_vars "${system_config_information}" "REMOTE_STATE_RG" + load_config_vars "${system_config_information}" "tfstate_resource_id" + load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${system_config_information}" "ARM_SUBSCRIPTION_ID" else - save_config_vars "${system_config_information}" REMOTE_STATE_SA + save_config_vars "${system_config_information}" REMOTE_STATE_SA fi deployer_tfstate_key_parameter="" if [[ -z $deployer_tfstate_key ]]; then - load_config_vars "${system_config_information}" "deployer_tfstate_key" + load_config_vars "${system_config_information}" "deployer_tfstate_key" else - echo "Deployer state file name: ${deployer_tfstate_key}" - echo "Target subscription: $ARM_SUBSCRIPTION_ID" - TF_VAR_deployer_tfstate_key="${deployer_tfstate_key}" - export TF_VAR_deployer_tfstate_key + echo "Deployer state file name: ${deployer_tfstate_key}" + echo "Target subscription: $ARM_SUBSCRIPTION_ID" + TF_VAR_deployer_tfstate_key="${deployer_tfstate_key}" + export TF_VAR_deployer_tfstate_key fi export TF_VAR_deployer_tfstate_key="${deployer_tfstate_key}" if [ "${deployment_system}" != sap_deployer ]; then - if [ -z "${deployer_tfstate_key}" ]; then - if [ 1 != $called_from_ado ]; then - read -p -r "Deployer terraform statefile name :" deployer_tfstate_key - - save_config_var "deployer_tfstate_key" "${system_config_information}" - else - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore!Deployer state file name is missing!$reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - echo "Deployer terraform statefile name is missing" >"${system_config_information}".err - unset TF_DATA_DIR - exit 2 - fi - else - - echo "Deployer state file name: ${deployer_tfstate_key}" - fi + if [ -z "${deployer_tfstate_key}" ]; then + if [ 1 != $called_from_ado ]; then + read -r -p "Deployer terraform statefile name: " deployer_tfstate_key + + save_config_var "deployer_tfstate_key" "${system_config_information}" + else + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore!Deployer state file name is missing!$reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + echo "Deployer terraform statefile name is missing" >"${system_config_information}".err + unset TF_DATA_DIR + exit 2 + fi + else + + echo "Deployer state file name: ${deployer_tfstate_key}" + fi else - load_config_vars "${system_config_information}" "keyvault" - TF_VAR_deployer_kv_user_arm_id=$(az resource list --name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --resource-type Microsoft.KeyVault/vaults --query "[].id | [0]" -o tsv) - export TF_VAR_spn_keyvault_id="${TF_VAR_deployer_kv_user_arm_id}" + load_config_vars "${system_config_information}" "keyvault" + TF_VAR_deployer_kv_user_arm_id=$(az resource list --name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --resource-type Microsoft.KeyVault/vaults --query "[].id | [0]" -o tsv) + export TF_VAR_spn_keyvault_id="${TF_VAR_deployer_kv_user_arm_id}" - echo "Deployer Keyvault ID: $TF_VAR_deployer_kv_user_arm_id" - deployer_parameter=" -var subscription_id=${STATE_SUBSCRIPTION} " + echo "Deployer Keyvault ID: $TF_VAR_deployer_kv_user_arm_id" + deployer_parameter=" -var subscription_id=${STATE_SUBSCRIPTION} " - export ARM_SUBSCRIPTION_ID=$STATE_SUBSCRIPTION + export ARM_SUBSCRIPTION_ID=$STATE_SUBSCRIPTION fi useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --query allowSharedKeyAccess --subscription "${STATE_SUBSCRIPTION}" --out tsv) if [ "$useSAS" = "true" ]; then - echo "Storage Account Authentication: Key" - export ARM_USE_AZUREAD=false + echo "Storage Account Authentication: Key" + export ARM_USE_AZUREAD=false else - echo "Storage Account Authentication: Entra ID" - export ARM_USE_AZUREAD=true + echo "Storage Account Authentication: Entra ID" + export ARM_USE_AZUREAD=true fi landscape_tfstate_key_parameter='' if [[ -z $landscape_tfstate_key ]]; then - load_config_vars "${system_config_information}" "landscape_tfstate_key" + load_config_vars "${system_config_information}" "landscape_tfstate_key" else - echo "Workload zone state file: ${landscape_tfstate_key}" - save_config_vars "${system_config_information}" landscape_tfstate_key + echo "Workload zone state file: ${landscape_tfstate_key}" + save_config_vars "${system_config_information}" landscape_tfstate_key fi if [ "${deployment_system}" == sap_system ]; then - if [ -z "${landscape_tfstate_key}" ]; then - if [ 1 != $called_from_ado ]; then - read -p -r "Workload terraform statefile name :" landscape_tfstate_key + if [ -z "${landscape_tfstate_key}" ]; then + if [ 1 != $called_from_ado ]; then + read -r -p "Workload terraform statefile name: " landscape_tfstate_key - save_config_var "landscape_tfstate_key" "${system_config_information}" + save_config_var "landscape_tfstate_key" "${system_config_information}" - else - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Workload zone terraform statefile name is missing $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" + else + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Workload zone terraform statefile name is missing $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" - echo "Workload zone terraform statefile name is missing" + echo "Workload zone terraform statefile name is missing" - unset TF_DATA_DIR - exit 2 - fi - fi + unset TF_DATA_DIR + exit 2 + fi + fi fi if [[ -z $STATE_SUBSCRIPTION ]]; then - load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" else - if is_valid_guid "$STATE_SUBSCRIPTION"; then - save_config_var "STATE_SUBSCRIPTION" "${system_config_information}" - else - printf -v val %-40.40s "$STATE_SUBSCRIPTION" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided state_subscription is not valid:$bold_red ${val}$reset_formatting#" - echo "# #" - echo "#########################################################################################" - echo "The provided subscription for Terraform remote state is not valid:${val}" >"${system_config_information}".err - exit 65 - fi + if is_valid_guid "$STATE_SUBSCRIPTION"; then + save_config_var "STATE_SUBSCRIPTION" "${system_config_information}" + else + printf -v val %-40.40s "$STATE_SUBSCRIPTION" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided state_subscription is not valid:$bold_red ${val}$reset_formatting#" + echo "# #" + echo "#########################################################################################" + echo "The provided subscription for Terraform remote state is not valid:${val}" >"${system_config_information}".err + exit 65 + fi fi @@ -460,19 +460,19 @@ fi set_executing_user_environment_variables "none" if [[ -n ${subscription} ]]; then - if is_valid_guid "${subscription}"; then - echo "Valid subscription format" - else - printf -v val %-40.40s "$subscription" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided subscription is not valid:$bold_red ${val} $reset_formatting# " - echo "# #" - echo "#########################################################################################" - echo "The provided subscription is not valid:${val}" >"${system_config_information}".err - exit 65 - fi - export ARM_SUBSCRIPTION_ID="${subscription}" + if is_valid_guid "${subscription}"; then + echo "Valid subscription format" + else + printf -v val %-40.40s "$subscription" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided subscription is not valid:$bold_red ${val} $reset_formatting# " + echo "# #" + echo "#########################################################################################" + echo "The provided subscription is not valid:${val}" >"${system_config_information}".err + exit 65 + fi + export ARM_SUBSCRIPTION_ID="${subscription}" fi load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" @@ -480,69 +480,69 @@ load_config_vars "${system_config_information}" "REMOTE_STATE_RG" load_config_vars "${system_config_information}" "tfstate_resource_id" if [[ -z ${REMOTE_STATE_SA} ]]; then - if [ 1 != $called_from_ado ]; then - read -p -r "Terraform state storage account name:" REMOTE_STATE_SA + if [ 1 != $called_from_ado ]; then + read -r -p "Terraform state storage account name: " REMOTE_STATE_SA - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" - load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${system_config_information}" "REMOTE_STATE_RG" - load_config_vars "${system_config_information}" "tfstate_resource_id" - fi + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" + load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${system_config_information}" "REMOTE_STATE_RG" + load_config_vars "${system_config_information}" "tfstate_resource_id" + fi fi if [ -z "${REMOTE_STATE_SA}" ]; then - missing "REMOTE_STATE_SA" - exit 1 + missing "REMOTE_STATE_SA" + exit 1 fi if [[ -z ${REMOTE_STATE_RG} ]]; then - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" - load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${system_config_information}" "REMOTE_STATE_RG" - load_config_vars "${system_config_information}" "tfstate_resource_id" + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" + load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${system_config_information}" "REMOTE_STATE_RG" + load_config_vars "${system_config_information}" "tfstate_resource_id" fi if [[ -z ${tfstate_resource_id} ]]; then - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" - load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${system_config_information}" "REMOTE_STATE_RG" - load_config_vars "${system_config_information}" "tfstate_resource_id" + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" + load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${system_config_information}" "REMOTE_STATE_RG" + load_config_vars "${system_config_information}" "tfstate_resource_id" fi if [ -n "${tfstate_resource_id}" ]; then - TF_VAR_tfstate_resource_id="${tfstate_resource_id}" - export TF_VAR_tfstate_resource_id + TF_VAR_tfstate_resource_id="${tfstate_resource_id}" + export TF_VAR_tfstate_resource_id fi if [ -n "${landscape_tfstate_key}" ]; then - TF_VAR_landscape_tfstate_key="${landscape_tfstate_key}" - export TF_VAR_landscape_tfstate_key + TF_VAR_landscape_tfstate_key="${landscape_tfstate_key}" + export TF_VAR_landscape_tfstate_key fi if [ -n "${deployer_tfstate_key}" ]; then - TF_VAR_deployer_tfstate_key="${deployer_tfstate_key}" - export TF_VAR_deployer_tfstate_key + TF_VAR_deployer_tfstate_key="${deployer_tfstate_key}" + export TF_VAR_deployer_tfstate_key fi terraform_module_directory="$SAP_AUTOMATION_REPO_PATH/deploy/terraform/run/${deployment_system}" cd "${param_dirname}" || exit if [ ! -d "${terraform_module_directory}" ]; then - printf -v val %-40.40s "$deployment_system" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Incorrect system deployment type specified: ${val}$reset_formatting#" - echo "# #" - echo "# Valid options are: #" - echo "# sap_deployer #" - echo "# sap_library #" - echo "# sap_landscape #" - echo "# sap_system #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 1 + printf -v val %-40.40s "$deployment_system" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Incorrect system deployment type specified: ${val}$reset_formatting#" + echo "# #" + echo "# Valid options are: #" + echo "# sap_deployer #" + echo "# sap_library #" + echo "# sap_landscape #" + echo "# sap_system #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 1 fi # This is used to tell Terraform if this is a new deployment or an update @@ -566,43 +566,18 @@ echo "Workload zone state file: ${landscape_tfstate_key}" echo "Terraform state resource ID: ${tfstate_resource_id}" echo "" +TF_VAR_subscription_id="$ARM_SUBSCRIPTION_ID" +export TF_VAR_subscription_id + check_output=0 if [ -f terraform.tfstate ]; then - echo "Local Terraform state file exists" - if [ -f ./.terraform/terraform.tfstate ]; then - if ! grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate; then - - if [ "${deployment_system}" == sap_deployer ]; then - - echo "" - echo -e "$cyan Reinitializing deployer in case of on a new deployer $reset_formatting" - - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/"${deployment_system}"/ - if ! terraform -chdir="${terraform_module_directory}" init -backend-config "path=${param_dirname}/terraform.tfstate" -reconfigure -input=false; then - echo "Error when initializing Terraform" - fi - echo "" - key_vault_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_kv_user_arm_id | tr -d \") - - if [ -n "${key_vault_id}" ]; then - export TF_VAR_deployer_kv_user_arm_id="${key_vault_id}" - echo "Deployer Keyvault ID: $TF_VAR_deployer_kv_user_arm_id" - fi - fi - - if [ "${deployment_system}" == sap_library ]; then - echo "Reinitializing library in case of on a new deployer" - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/"${deployment_system}"/ - - if ! terraform -chdir="${terraform_module_directory}" init -backend-config "path=${param_dirname}/terraform.tfstate" -reconfigure -input=false; then - return_value=$? - echo "Error when initializing Terraform" - else - return_value=$? - fi - fi - fi - fi + echo "Local Terraform state file exists" + if [ -f ./.terraform/terraform.tfstate ]; then + if ! grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate; then + echo "State file is in Azure" + + fi + fi fi terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/run/"${deployment_system}"/ @@ -611,212 +586,268 @@ export TF_DATA_DIR="${param_dirname}/.terraform" new_deployment=0 if [ ! -d ./.terraform/ ]; then - echo "New deployment" - deployment_parameter=" -var deployment=new " - check_output=false - - if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true -input=false \ - --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ - --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ - --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate"; then - return_value=$? - echo "Error when initializing Terraform" - else - return_value=$? - fi + echo "New deployment" + deployment_parameter=" -var deployment=new " + check_output=false + + if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true -input=false \ + --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ + --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ + --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + fi else - new_deployment=1 - check_output=true - - local_backend=$(grep "\"type\": \"local\"" .terraform/terraform.tfstate || true) - if [ -n "$local_backend" ]; then - if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true -force-copy \ - --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ - --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ - --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate"; then - return_value=$? - echo "Error when initializing Terraform" - else - return_value=$? - fi - - else - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan The system has already been deployed and the statefile is in Azure $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - check_output=true - if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true -reconfigure \ - --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ - --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ - --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate"; then - return_value=$? - echo "Error when initializing Terraform" - else - return_value=$? - fi - - fi + new_deployment=1 + check_output=true + + if [ -f .terraform/terraform.tfstate ]; then + + local_backend=$(grep "\"type\": \"local\"" .terraform/terraform.tfstate || true) + if [ -n "$local_backend" ]; then + if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true -force-copy \ + --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ + --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ + --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + exit $return_value + else + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + fi + + else + STATE_SUBSCRIPTION=$(grep -m1 "subscription_id" ".terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d '", \r' | xargs || true) + REMOTE_STATE_SA=$(grep -m1 "storage_account_name" ".terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) + REMOTE_STATE_RG=$(grep -m1 "resource_group_name" ".terraform/terraform.tfstate" | cut -d ':' -f2 | tr -d ' ",\r' | xargs || true) + + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan The system has already been deployed and the statefile is in Azure $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + check_output=true + if ! terraform -chdir="${terraform_module_directory}" init -upgrade=true \ + -reconfigure \ + --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ + --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ + --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + exit $return_value + else + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + fi + + fi + else + if ! terraform -chdir="${terraform_module_directory}" init \ + -upgrade=true -reconfigure \ + --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ + --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ + --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + exit $return_value + else + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + fi + fi fi if [ "true" == "$check_output" ]; then - if terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan New deployment $reset_formatting #" - echo "# #" - echo "#########################################################################################" - - deployment_parameter=" -var deployment=new " - new_deployment=1 - check_output=false - - else - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Existing deployment was detected$reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - deployment_parameter="" - new_deployment=0 - check_output=true - fi + if terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan New deployment $reset_formatting #" + echo "# #" + echo "#########################################################################################" + + deployment_parameter=" -var deployment=new " + new_deployment=1 + check_output=false + + else + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Existing deployment was detected$reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + deployment_parameter="" + new_deployment=0 + check_output=true + fi else - new_deployment=1 + new_deployment=1 fi if [ 0 == $new_deployment ]; then - deployed_using_version=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw automation_version | tr -d \" || true) - if [ -z "${deployed_using_version}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red The environment was deployed using an older version of the Terrafrom templates$reset_formatting #" - echo "# #" - echo "# !!! Risk for Data loss !!! #" - echo "# #" - echo "# Please inspect the output of Terraform plan carefully before proceeding #" - echo "# #" - echo "#########################################################################################" - - if [ 1 == $called_from_ado ]; then - unset TF_DATA_DIR - exit 1 - fi - read -p -r "Do you want to continue Y/N?" ans - answer=${ans^^} - if [ "$answer" != 'Y' ]; then - unset TF_DATA_DIR - exit 1 - fi - else - version_parameter="-var terraform_template_version=${deployed_using_version}" - - printf -v val %-.20s "$deployed_using_version" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Deployed using the Terraform templates version: $val $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - version_compare "${deployed_using_version}" "3.13.2.0" - older_version=$? - if [ 2 == $older_version ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Deployed using an older version $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "##vso[task.logissue type=warning]Deployed using an older version ${deployed_using_version}. Performing state management operations" - - # Remeadiating the Storage Accounts and File Shares - if [ "${deployment_system}" == sap_library ]; then - moduleID='module.sap_library.azurerm_storage_account.storage_sapbits[0]' - azureResourceID=$(terraform -chdir="${terraform_module_directory}" state show "${moduleID}" | grep -m1 " id " | xargs | cut -d "=" -f2 | xargs) - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" - - resourceGroupName=$(az resource show --ids "${azureResourceID}" --query "resourceGroup" --output tsv) - resourceType=$(az resource show --ids "${azureResourceID}" --query "type" --output tsv) - resourceName=$(az resource show --ids "${azureResourceID}" --query "name" --output tsv) - az resource lock create --lock-type CanNotDelete -n "SAP Media account delete lock" --resource-group "${resourceGroupName}" --resource "${resourceName}" --resource-type "${resourceType}" --output none - - moduleID='module.sap_library.azurerm_storage_container.storagecontainer_sapbits[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" - - moduleID='module.sap_library.azurerm_storage_account.storage_tfstate[0]' - azureResourceID=$(terraform -chdir="${terraform_module_directory}" state show "${moduleID}" | grep -m1 " id " | xargs | cut -d "=" -f2 | xargs) - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" - - resourceGroupName=$(az resource show --ids "${azureResourceID}" --query "resourceGroup" --output tsv) - resourceType=$(az resource show --ids "${azureResourceID}" --query "type" --output tsv) - resourceName=$(az resource show --ids "${azureResourceID}" --query "name" --output tsv) - az resource lock create --lock-type CanNotDelete -n "Terraform state account delete lock" --resource-group "${resourceGroupName}" --resource "${resourceName}" --resource-type "${resourceType}" --output none - - moduleID='module.sap_library.azurerm_storage_container.storagecontainer_tfstate[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" - - moduleID='module.sap_library.azurerm_storage_container.storagecontainer_tfvars[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" - - fi - - if [ "${deployment_system}" == sap_deployer ]; then - - moduleID='module.sap_deployer.azurerm_storage_account.deployer[0]' - azureResourceID=$(terraform -chdir="${terraform_module_directory}" state show "${moduleID}" | grep -m1 " id " | xargs | cut -d "=" -f2 | xargs) - echo "Terraform resource ID: $moduleID" - echo "Azure resource ID: $azureResourceID" - if [ -n "${azureResourceID}" ]; then - echo "Removing storage account state object: ${moduleID} " - if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then - echo "Importing storage account state object: ${moduleID}" - echo "terraform -chdir=${terraform_module_directory} import -var-file=${var_file} ${moduleID} ${azureResourceID}" - if ! terraform -chdir="${terraform_module_directory}" import -var-file="${var_file}" "${moduleID}" "${azureResourceID}"; then - echo -e "$bold_red Importing storage account state object: ${moduleID} failed $reset_formatting" - exit 65 - fi - fi - fi - fi - - if [ "${deployment_system}" == sap_system ]; then - - moduleID='module.common_infrastructure.azurerm_storage_account.sapmnt[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" "${landscape_tfstate_key_parameter}" - - moduleID='module.common_infrastructure.azurerm_storage_share.sapmnt[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" "${landscape_tfstate_key_parameter}" - - moduleID='module.hdb_node.azurerm_storage_account.hanashared[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" "${landscape_tfstate_key_parameter}" - moduleID='module.hdb_node.azurerm_storage_share.hanashared[0]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" "${landscape_tfstate_key_parameter}" - - moduleID='module.hdb_node.azurerm_storage_account.hanashared[1]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "id" "${landscape_tfstate_key_parameter}" - moduleID='module.hdb_node.azurerm_storage_share.hanashared[1]' - ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" "${landscape_tfstate_key_parameter}" - - fi - - fi - fi + deployed_using_version=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw automation_version | tr -d \" || true) + if [ -z "${deployed_using_version}" ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red The environment was deployed using an older version of the Terrafrom templates$reset_formatting #" + echo "# #" + echo "# !!! Risk for Data loss !!! #" + echo "# #" + echo "# Please inspect the output of Terraform plan carefully before proceeding #" + echo "# #" + echo "#########################################################################################" + + if [ 1 == $called_from_ado ]; then + unset TF_DATA_DIR + exit 1 + fi + read -r -p "Do you want to continue Y/N? " ans + answer=${ans^^} + if [ "$answer" != 'Y' ]; then + unset TF_DATA_DIR + exit 1 + fi + else + version_parameter="-var terraform_template_version=${deployed_using_version}" + + printf -v val %-.20s "$deployed_using_version" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Deployed using the Terraform templates version: $val $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + version_compare "${deployed_using_version}" "3.13.2.0" + older_version=$? + if [ 2 == $older_version ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Deployed using an older version $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "##vso[task.logissue type=warning]Deployed using an older version ${deployed_using_version}. Performing state management operations" + + # Remediating the Storage Accounts and File Shares + if [ "${deployment_system}" == sap_library ]; then + moduleID='module.sap_library.azurerm_storage_account.storage_sapbits[0]' + storage_account_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sapbits_storage_account_name) + storage_account_rg_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sapbits_sa_resource_group_name) + STORAGE_ACCOUNT_ID=$(az storage account show --name "${storage_account_name}" --resource-group "${storage_account_rg_name}" --query "id" --output tsv) + export STORAGE_ACCOUNT_ID + + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "providers/Microsoft.Storage/storageAccounts" + + + resourceGroupName=$(az resource show --ids "${STORAGE_ACCOUNT_ID}" --query "resourceGroup" --output tsv) + resourceType=$(az resource show --ids "${STORAGE_ACCOUNT_ID}" --query "type" --output tsv) + resourceName=$(az resource show --ids "${STORAGE_ACCOUNT_ID}" --query "name" --output tsv) + + az resource lock create --lock-type CanNotDelete -n "SAP Media account delete lock" --resource-group "${resourceGroupName}" --resource "${resourceName}" --resource-type "${resourceType}" --output none + unset STORAGE_ACCOUNT_ID + + moduleID='module.sap_library.azurerm_storage_container.storagecontainer_sapbits[0]' + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" + + moduleID='module.sap_library.azurerm_storage_account.storage_tfstate[0]' + + STORAGE_ACCOUNT_ID=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw tfstate_resource_id) + export STORAGE_ACCOUNT_ID + + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "providers/Microsoft.Storage/storageAccounts" + + resourceGroupName=$(az resource show --ids "${STORAGE_ACCOUNT_ID}" --query "resourceGroup" --output tsv) + resourceType=$(az resource show --ids "${STORAGE_ACCOUNT_ID}" --query "type" --output tsv) + resourceName=$(az resource show --ids "${STORAGE_ACCOUNT_ID}" --query "name" --output tsv) + az resource lock create --lock-type CanNotDelete -n "Terraform state account delete lock" --resource-group "${resourceGroupName}" --resource "${resourceName}" --resource-type "${resourceType}" --output none + unset STORAGE_ACCOUNT_ID + + moduleID='module.sap_library.azurerm_storage_container.storagecontainer_tfstate[0]' + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" + + moduleID='module.sap_library.azurerm_storage_container.storagecontainer_tfvars[0]' + ReplaceResourceInStateFile "${moduleID}" "${terraform_module_directory}" "resource_manager_id" + + fi + + if [ "${deployment_system}" == sap_deployer ]; then + + moduleID='module.sap_deployer.azurerm_storage_account.deployer[0]' + if terraform -chdir="${terraform_module_directory}" state rm ${moduleID}; then + echo "Removed the diagnostics storage account state object" + fi + fi + + if [ "${deployment_system}" == sap_system ]; then + + moduleID='module.common_infrastructure.azurerm_storage_account.sapmnt[0]' + if terraform -chdir="${terraform_module_directory}" state rm ${moduleID}; then + echo "Removed the transport private DNS record" + fi + + moduleID='module.common_infrastructure.azurerm_storage_share.sapmnt[0]' + if terraform -chdir="${terraform_module_directory}" state rm ${moduleID}; then + echo "Removed the transport private DNS record" + fi + + moduleID='module.hdb_node.azurerm_storage_account.hanashared[0]' + if terraform -chdir="${terraform_module_directory}" state rm ${moduleID}; then + echo "Removed the transport private DNS record" + fi + moduleID='module.hdb_node.azurerm_storage_share.hanashared[0]' + if terraform -chdir="${terraform_module_directory}" state rm ${moduleID}; then + echo "Removed the transport private DNS record" + fi + + moduleID='module.hdb_node.azurerm_storage_account.hanashared[1]' + if terraform -chdir="${terraform_module_directory}" state rm ${moduleID}; then + echo "Removed the transport private DNS record" + fi + moduleID='module.hdb_node.azurerm_storage_share.hanashared[1]' + if terraform -chdir="${terraform_module_directory}" state rm ${moduleID}; then + echo "Removed the transport private DNS record" + fi + + fi + + fi + fi fi echo "" @@ -828,533 +859,575 @@ echo "########################################################################## echo "" if [ -f plan_output.log ]; then - rm plan_output.log + rm plan_output.log fi allParameters=$(printf " -var-file=%s %s %s %s %s" "${var_file}" "${extra_vars}" "${deployment_parameter}" "${version_parameter}" "${deployer_parameter}") # shellcheck disable=SC2086 -if ! terraform -chdir="$terraform_module_directory" plan $allParameters -input=false -detailed-exitcode | tee -a plan_output.log; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore !!! Error when running plan !!! $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - exit $return_value - fi +if ! terraform -chdir="$terraform_module_directory" plan $allParameters -input=false -detailed-exitcode -compact-warnings | tee -a plan_output.log; then + return_value=$? + echo "Terraform Plan return code: $return_value" + + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform plan: failed$reset_formatting" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore !!! Error when running plan !!! $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + exit $return_value + fi else - return_value=$? -fi + return_value=$? + echo "Terraform Plan return code: $return_value" -echo "Terraform Plan return code: $return_value" + echo "" + echo -e "${cyan}Terraform plan: succeeded$reset_formatting" + echo "" + +fi apply_needed=1 state_path="SYSTEM" if [ 1 != $return_value ]; then - if [ "${deployment_system}" == sap_deployer ]; then - state_path="DEPLOYER" - - if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - - deployer_public_ip_address=$(terraform -chdir="${terraform_module_directory}" output deployer_public_ip_address | tr -d \") - save_config_var "deployer_public_ip_address" "${system_config_information}" - - keyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_kv_user_name | tr -d \") - save_config_var "keyvault" "${system_config_information}" - if [ 1 == $called_from_ado ]; then - - if [[ "$TF_VAR_use_webapp" == "true" && $IS_PIPELINE_DEPLOYMENT = "true" ]]; then - webapp_url_base=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_url_base | tr -d \") - - if [ -n "$webapp_url_base" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_URL_BASE.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_URL_BASE --value "$webapp_url_base" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_URL_BASE --value "$webapp_url_base" --output none --only-show-errors - fi - fi - - webapp_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_id | tr -d \") - if [ -n "$webapp_id" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_ID.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_ID --value "$webapp_id" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_ID --value "$webapp_id" --output none --only-show-errors - fi - fi - - msi_object_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_user_assigned_identity | tr -d \") - - if [ -n "$msi_object_id" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "MSI_ID.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name MSI_ID --value "$msi_object_id" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name MSI_ID --value "$msi_object_id" --output none --only-show-errors - fi - fi - - fi - fi - - fi - - fi - - if [ "${deployment_system}" == sap_landscape ]; then - state_path="LANDSCAPE" - if [ $landscape_tfstate_key_exists == false ]; then - save_config_vars "${system_config_information}" \ - landscape_tfstate_key - fi - fi - - if [ "${deployment_system}" == sap_library ]; then - state_path="LIBRARY" - if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then - tfstate_resource_id=$(terraform -chdir="${terraform_module_directory}" output tfstate_resource_id | tr -d \") - STATE_SUBSCRIPTION=$(echo "$tfstate_resource_id" | cut -d/ -f3 | tr -d \" | xargs) - - az account set --sub "${STATE_SUBSCRIPTION}" - - REMOTE_STATE_SA=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw remote_state_storage_account_name | tr -d \") - - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" - - if [ 1 == "$called_from_ado" ]; then - SAPBITS=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sapbits_storage_account_name | tr -d \") - if [ -n "${SAPBITS}" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "INSTALLATION_MEDIA_ACCOUNT.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name INSTALLATION_MEDIA_ACCOUNT --value "$SAPBITS" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name INSTALLATION_MEDIA_ACCOUNT --value "$SAPBITS" --output none --only-show-errors - fi - fi - fi - fi - fi - - apply_needed=1 + if [ "${deployment_system}" == sap_deployer ]; then + state_path="DEPLOYER" + + if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then + + deployer_public_ip_address=$(terraform -chdir="${terraform_module_directory}" output deployer_public_ip_address | tr -d \") + save_config_var "deployer_public_ip_address" "${system_config_information}" + + keyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_kv_user_name | tr -d \") + if [ -n "$keyvault" ]; then + save_config_var "keyvault" "${system_config_information}" + fi + if [ 1 == $called_from_ado ]; then + + if [[ "$TF_VAR_use_webapp" == "true" && $IS_PIPELINE_DEPLOYMENT = "true" ]]; then + webapp_url_base=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_url_base | tr -d \") + + if [ -n "$webapp_url_base" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_URL_BASE.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_URL_BASE --value "$webapp_url_base" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_URL_BASE --value "$webapp_url_base" --output none --only-show-errors + fi + fi + + webapp_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_id | tr -d \") + if [ -n "$webapp_id" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_ID.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_ID --value "$webapp_id" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_ID --value "$webapp_id" --output none --only-show-errors + fi + fi + + msi_object_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_user_assigned_identity | tr -d \") + + if [ -n "$msi_object_id" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "MSI_ID.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name MSI_ID --value "$msi_object_id" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name MSI_ID --value "$msi_object_id" --output none --only-show-errors + fi + fi + + fi + fi + + fi + + fi + + if [ "${deployment_system}" == sap_landscape ]; then + state_path="LANDSCAPE" + if [ $landscape_tfstate_key_exists == false ]; then + save_config_vars "${system_config_information}" \ + landscape_tfstate_key + fi + fi + + if [ "${deployment_system}" == sap_library ]; then + state_path="LIBRARY" + if ! terraform -chdir="${terraform_module_directory}" output | grep "No outputs"; then + tfstate_resource_id=$(terraform -chdir="${terraform_module_directory}" output tfstate_resource_id | tr -d \") + STATE_SUBSCRIPTION=$(echo "$tfstate_resource_id" | cut -d/ -f3 | tr -d \" | xargs) + + az account set --sub "${STATE_SUBSCRIPTION}" + + REMOTE_STATE_SA=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw remote_state_storage_account_name | tr -d \") + + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" + + if [ 1 == "$called_from_ado" ]; then + SAPBITS=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sapbits_storage_account_name | tr -d \") + if [ -n "${SAPBITS}" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "INSTALLATION_MEDIA_ACCOUNT.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name INSTALLATION_MEDIA_ACCOUNT --value "$SAPBITS" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name INSTALLATION_MEDIA_ACCOUNT --value "$SAPBITS" --output none --only-show-errors + fi + fi + fi + fi + fi + + apply_needed=1 fi useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --query allowSharedKeyAccess --subscription "${STATE_SUBSCRIPTION}" --out tsv) if [ "$useSAS" = "true" ]; then - echo "Storage Account authentication: key" - export ARM_USE_AZUREAD=false + echo "Storage Account authentication: key" + export ARM_USE_AZUREAD=false else - echo "Storage Account authentication: Entra ID" - export ARM_USE_AZUREAD=true + echo "Storage Account authentication: Entra ID" + export ARM_USE_AZUREAD=true fi if [ "$useSAS" = "true" ]; then - container_exists=$(az storage container exists --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors --query exists) + container_exists=$(az storage container exists --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors --query exists) else - container_exists=$(az storage container exists --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors --query exists --auth-mode login) + container_exists=$(az storage container exists --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors --query exists --auth-mode login) fi if [ "${container_exists}" == "false" ]; then - if [ "$useSAS" = "true" ]; then - az storage container create --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors - else - az storage container create --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --auth-mode login --only-show-errors - fi + if [ "$useSAS" = "true" ]; then + az storage container create --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --only-show-errors + else + az storage container create --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --name tfvars --auth-mode login --only-show-errors + fi fi if [ "$useSAS" = "true" ]; then - az storage blob upload --file "${parameterfile}" --container-name tfvars/LANDSCAPE/"${key}" --name "${parameterfile_name}" --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none + az storage blob upload --file "${parameterfile}" --container-name tfvars/LANDSCAPE/"${key}" --name "${parameterfile_name}" --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none else - az storage blob upload --file "${parameterfile}" --container-name tfvars/LANDSCAPE/"${key}" --name "${parameterfile_name}" --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --auth-mode login --only-show-errors --output none + az storage blob upload --file "${parameterfile}" --container-name tfvars/LANDSCAPE/"${key}" --name "${parameterfile_name}" --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --auth-mode login --only-show-errors --output none fi fatal_errors=0 # SAP Library if ! testIfResourceWouldBeRecreated "module.sap_library.azurerm_storage_account.storage_sapbits" "plan_output.log" "SAP Library Storage Account"; then - fatal_errors=1 + fatal_errors=1 fi # SAP Library sapbits if ! testIfResourceWouldBeRecreated "module.sap_library.azurerm_storage_container.storagecontainer_sapbits" "plan_output.log" "SAP Library Storage Account container"; then - fatal_errors=1 + fatal_errors=1 fi # Terraform State Library if ! testIfResourceWouldBeRecreated "module.sap_library.azurerm_storage_account.storage_tfstate" "plan_output.log" "Terraform State Storage Account"; then - fatal_errors=1 + fatal_errors=1 fi # Terraform state container if ! testIfResourceWouldBeRecreated "module.sap_library.azurerm_storage_container.storagecontainer_tfstate" "plan_output.log" "Terraform State Storage Account"; then - fatal_errors=1 + fatal_errors=1 fi # HANA VM if ! testIfResourceWouldBeRecreated "vm_dbnode" "plan_output.log" "Database server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # HANA VM disks if ! testIfResourceWouldBeRecreated "azurerm_managed_disk.data_disk" "plan_output.log" "Database server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # AnyDB server if ! testIfResourceWouldBeRecreated "dbserver" "plan_output.log" "Database server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # AnyDB disks if ! testIfResourceWouldBeRecreated "azurerm_managed_disk.disks" "plan_output.log" "Database server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # App server if ! testIfResourceWouldBeRecreated "virtual_machine.app" "plan_output.log" "Application server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # App server disks if ! testIfResourceWouldBeRecreated "azurerm_managed_disk.app" "plan_output.log" "Application server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # SCS server if ! testIfResourceWouldBeRecreated "virtual_machine.scs" "plan_output.log" "Application server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # SCS server disks if ! testIfResourceWouldBeRecreated "azurerm_managed_disk.scs" "plan_output.log" "Application server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # Web server if ! testIfResourceWouldBeRecreated "virtual_machine.web" "plan_output.log" "Application server(s)"; then - fatal_errors=1 + fatal_errors=1 fi # Web dispatcher server disks if ! testIfResourceWouldBeRecreated "azurerm_managed_disk.web" "plan_output.log" "Application server(s)"; then - fatal_errors=1 + fatal_errors=1 fi echo "TEST_ONLY: $TEST_ONLY" if [ "${TEST_ONLY}" == "True" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Running plan only. $reset_formatting #" - echo "# #" - echo "# No deployment performed. #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 0 + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Running plan only. $reset_formatting #" + echo "# #" + echo "# No deployment performed. #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 0 fi if [ $fatal_errors == 1 ]; then - apply_needed=0 - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore!!! Risk for Data loss !!!$reset_formatting #" - echo "# #" - echo "# Please inspect the output of Terraform plan carefully before proceeding #" - echo "# #" - echo "#########################################################################################" - echo "" - if [ 1 == "$called_from_ado" ]; then - unset TF_DATA_DIR - echo "Risk for data loss, Please inspect the output of Terraform plan carefully. Run manually from deployer" >"${system_config_information}".err - echo ##vso[task.logissue type=error]Risk for data loss, Please inspect the output of Terraform plan carefully. Run manually from deployer - exit 1 - fi - - if [ 1 == $force ]; then - apply_needed=1 - else - read -p -r "Do you want to continue with the deployment Y/N?" ans - answer=${ans^^} - if [ "$answer" == 'Y' ]; then - apply_needed=true - else - unset TF_DATA_DIR - exit 1 - fi - fi + apply_needed=0 + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore!!! Risk for Data loss !!!$reset_formatting #" + echo "# #" + echo "# Please inspect the output of Terraform plan carefully before proceeding #" + echo "# #" + echo "#########################################################################################" + echo "" + if [ 1 == "$called_from_ado" ]; then + unset TF_DATA_DIR + echo "Risk for data loss, Please inspect the output of Terraform plan carefully. Run manually from deployer" >"${system_config_information}".err + echo ##vso[task.logissue type=error]Risk for data loss, Please inspect the output of Terraform plan carefully. Run manually from deployer + exit 1 + fi + + if [ 1 == $force ]; then + apply_needed=1 + else + read -r -p "Do you want to continue with the deployment Y/N? " ans + answer=${ans^^} + if [ "$answer" == 'Y' ]; then + apply_needed=true + else + unset TF_DATA_DIR + exit 1 + fi + fi fi if [ 1 == $apply_needed ]; then - if [ -f error.log ]; then - rm error.log - fi - if [ -f plan_output.log ]; then - rm plan_output.log - fi - - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Running Terraform apply $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - allParameters=$(printf " -var-file=%s %s %s %s %s " "${var_file}" "${extra_vars}" "${deployment_parameter}" "${version_parameter}" "${approve}") - allImportParameters=$(printf " -var-file=%s %s %s %s " "${var_file}" "${extra_vars}" "${deployment_parameter}" "${version_parameter}") - - if [ -n "${approve}" ]; then - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" -no-color -compact-warnings -json -input=false $allParameters | tee -a apply_output.json; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - else - return_value=0 - fi - - else - # shellcheck disable=SC2086 - if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" -input=false $allParameters; then - return_value=$? - if [ $return_value -eq 1 ]; then - echo "Errors when running Terraform apply" - else - # return code 2 is ok - return_value=0 - fi - fi - fi - - if [ -f apply_output.json ]; then - errors_occurred=$(jq 'select(."@level" == "error") | length' apply_output.json) - - if [[ -n $errors_occurred ]]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - fi - - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - - fi - - if [ -f apply_output.json ]; then - # shellcheck disable=SC2086 - if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then - return_value=$? - fi - - fi - fi + if [ -f error.log ]; then + rm error.log + fi + if [ -f plan_output.log ]; then + rm plan_output.log + fi + + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Running Terraform apply $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + allParameters=$(printf " -var-file=%s %s %s %s %s " "${var_file}" "${extra_vars}" "${deployment_parameter}" "${version_parameter}" "${approve}") + allImportParameters=$(printf " -var-file=%s %s %s %s " "${var_file}" "${extra_vars}" "${deployment_parameter}" "${version_parameter}") + + if [ -n "${approve}" ]; then + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" -no-color -compact-warnings -json -input=false $allParameters | tee -a apply_output.json; then + return_value=$? + echo "" + echo "Terraform return code: $return_value" + echo "" + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform apply: failed$reset_formatting" + echo "" + exit $return_value + else + # return code 2 is ok + echo "" + echo -e "${cyan}Terraform apply: succeeded$reset_formatting" + echo "" + return_value=0 + fi + else + return_value=0 + fi + + else + # shellcheck disable=SC2086 + if ! terraform -chdir="${terraform_module_directory}" apply -parallelism="${parallelism}" -input=false $allParameters | tee -a apply_output.json; then + return_value=$? + if [ $return_value -eq 1 ]; then + echo "" + echo -e "${bold_red}Terraform apply: failed$reset_formatting" + echo "" + exit $return_value + else + # return code 2 is ok + echo "" + echo -e "${cyan}Terraform apply: succeeded$reset_formatting" + echo "" + return_value=0 + fi + fi + fi + + if [ -f apply_output.json ]; then + errors_occurred=$(jq 'select(."@level" == "error") | length' apply_output.json) + + if [[ -n $errors_occurred ]]; then + if [ -n "${approve}" ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + + fi + + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + if [ -f apply_output.json ]; then + # shellcheck disable=SC2086 + if ! ImportAndReRunApply "apply_output.json" "${terraform_module_directory}" "$allImportParameters" "$allParameters" $parallelism; then + return_value=$? + fi + fi + else + return_value=10 + fi + + fi + fi fi if [ -f apply_output.json ]; then - rm apply_output.json + rm apply_output.json fi if [ 1 == $return_value ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore!Errors during the apply phase!$reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - unset TF_DATA_DIR - exit $return_value + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore!Errors during the apply phase!$reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + unset TF_DATA_DIR + exit $return_value fi if [ "${deployment_system}" == sap_deployer ]; then - # terraform -chdir="${terraform_module_directory}" output - - deployer_public_ip_address=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_public_ip_address | tr -d \") - keyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_kv_user_name | tr -d \") - - created_resource_group_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Capturing telemetry $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "" - - full_script_path="$(realpath "${BASH_SOURCE[0]}")" - script_directory="$(dirname "${full_script_path}")" - az deployment group create --resource-group "${created_resource_group_name}" --name "ControlPlane_Deployer_${created_resource_group_name}" \ - --template-file "${script_directory}/templates/empty-deployment.json" --output none - return_value=0 - if [ 1 == $called_from_ado ]; then - - terraform -chdir="${terraform_module_directory}" output -json -no-color deployer_uai - - if [ -n "${created_resource_group_name}" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_RESOURCE_GROUP.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_RESOURCE_GROUP --value "$created_resource_group_name" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_RESOURCE_GROUP --value "$created_resource_group_name" --output none --only-show-errors - fi - fi - - if [[ "${TF_VAR_use_webapp}" == "true" && $IS_PIPELINE_DEPLOYMENT = "true" ]]; then - webapp_url_base=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_url_base | tr -d \") - if [ -n "${webapp_url_base}" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_URL_BASE.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_URL_BASE --value "$webapp_url_base" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_URL_BASE --value "$webapp_url_base" --output none --only-show-errors - fi - fi - - webapp_identity=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_identity | tr -d \") - if [ -n "${webapp_identity}" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_IDENTITY.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_IDENTITY --value "$webapp_identity" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_IDENTITY --value "$webapp_identity" --output none --only-show-errors - fi - fi - - webapp_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_id | tr -d \") - if [ -n "${webapp_id}" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_ID.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_ID --value "$webapp_id" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_ID --value "$webapp_id" --output none --only-show-errors - fi - fi - fi - fi + # terraform -chdir="${terraform_module_directory}" output + + deployer_public_ip_address=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_public_ip_address | tr -d \") + keyvault=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw deployer_kv_user_name | tr -d \") + + created_resource_group_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Capturing telemetry $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "" + + full_script_path="$(realpath "${BASH_SOURCE[0]}")" + script_directory="$(dirname "${full_script_path}")" + az deployment group create --resource-group "${created_resource_group_name}" --name "ControlPlane_Deployer_${created_resource_group_name}" \ + --template-file "${script_directory}/templates/empty-deployment.json" --output none + return_value=0 + if [ 1 == $called_from_ado ]; then + + terraform -chdir="${terraform_module_directory}" output -json -no-color deployer_uai + + if [ -n "${created_resource_group_name}" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_RESOURCE_GROUP.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_RESOURCE_GROUP --value "$created_resource_group_name" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_RESOURCE_GROUP --value "$created_resource_group_name" --output none --only-show-errors + fi + fi + + if [[ "${TF_VAR_use_webapp}" == "true" && $IS_PIPELINE_DEPLOYMENT = "true" ]]; then + webapp_url_base=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_url_base | tr -d \") + if [ -n "${webapp_url_base}" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_URL_BASE.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_URL_BASE --value "$webapp_url_base" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_URL_BASE --value "$webapp_url_base" --output none --only-show-errors + fi + fi + + webapp_identity=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_identity | tr -d \") + if [ -n "${webapp_identity}" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_IDENTITY.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_IDENTITY --value "$webapp_identity" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_IDENTITY --value "$webapp_identity" --output none --only-show-errors + fi + fi + + webapp_id=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw webapp_id | tr -d \") + if [ -n "${webapp_id}" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "WEBAPP_ID.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_ID --value "$webapp_id" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name WEBAPP_ID --value "$webapp_id" --output none --only-show-errors + fi + fi + fi + fi fi if valid_kv_name "$keyvault"; then - save_config_var "keyvault" "${system_config_information}" + save_config_var "keyvault" "${system_config_information}" else - printf -v val %-40.40s "$keyvault" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided keyvault is not valid:$bold_red ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "The provided keyvault is not valid " "${val}" >secret.err + printf -v val %-40.40s "$keyvault" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided keyvault is not valid:$bold_red ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "The provided keyvault is not valid " "${val}" >secret.err fi save_config_var "deployer_public_ip_address" "${system_config_information}" if [ "${deployment_system}" == sap_system ]; then - rg_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") + rg_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Capturing telemetry $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "" - full_script_path="$(realpath "${BASH_SOURCE[0]}")" - script_directory="$(dirname "${full_script_path}")" - az deployment group create --resource-group "${rg_name}" --name "SAP_${rg_name}" --subscription "$ARM_SUBSCRIPTION_ID" \ - --template-file "${script_directory}/templates/empty-deployment.json" --output none + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Capturing telemetry $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "" + full_script_path="$(realpath "${BASH_SOURCE[0]}")" + script_directory="$(dirname "${full_script_path}")" + az deployment group create --resource-group "${rg_name}" --name "SAP_${rg_name}" --subscription "$ARM_SUBSCRIPTION_ID" \ + --template-file "${script_directory}/templates/empty-deployment.json" --output none fi if [ "${deployment_system}" == sap_landscape ]; then - save_config_vars "${system_config_information}" \ - landscape_tfstate_key - - rg_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Capturing telemetry $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "" - full_script_path="$(realpath "${BASH_SOURCE[0]}")" - script_directory="$(dirname "${full_script_path}")" - az deployment group create --resource-group "${rg_name}" --name "SAP-WORKLOAD-ZONE_${rg_name}" --subscription "$ARM_SUBSCRIPTION_ID" \ - --template-file "${script_directory}/templates/empty-deployment.json" --output none + save_config_vars "${system_config_information}" \ + landscape_tfstate_key + + rg_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Capturing telemetry $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "" + full_script_path="$(realpath "${BASH_SOURCE[0]}")" + script_directory="$(dirname "${full_script_path}")" + az deployment group create --resource-group "${rg_name}" --name "SAP-WORKLOAD-ZONE_${rg_name}" --subscription "$ARM_SUBSCRIPTION_ID" \ + --template-file "${script_directory}/templates/empty-deployment.json" --output none fi if [ "${deployment_system}" == sap_library ]; then - REMOTE_STATE_SA=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw remote_state_storage_account_name | tr -d \") - sapbits_storage_account_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sapbits_storage_account_name | tr -d \") + REMOTE_STATE_SA=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw remote_state_storage_account_name | tr -d \") + sapbits_storage_account_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw sapbits_storage_account_name | tr -d \") - if [ 1 == $called_from_ado ]; then + if [ 1 == $called_from_ado ]; then - if [ -n "${sapbits_storage_account_name}" ]; then - az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "INSTALLATION_MEDIA_ACCOUNT.value") - if [ -z "${az_var}" ]; then - az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name INSTALLATION_MEDIA_ACCOUNT --value "${sapbits_storage_account_name}" --output none --only-show-errors - else - az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name INSTALLATION_MEDIA_ACCOUNT --value "${sapbits_storage_account_name}" --output none --only-show-errors - fi - fi + if [ -n "${sapbits_storage_account_name}" ]; then + az_var=$(az pipelines variable-group variable list --group-id "${VARIABLE_GROUP_ID}" --query "INSTALLATION_MEDIA_ACCOUNT.value") + if [ -z "${az_var}" ]; then + az pipelines variable-group variable create --group-id "${VARIABLE_GROUP_ID}" --name INSTALLATION_MEDIA_ACCOUNT --value "${sapbits_storage_account_name}" --output none --only-show-errors + else + az pipelines variable-group variable update --group-id "${VARIABLE_GROUP_ID}" --name INSTALLATION_MEDIA_ACCOUNT --value "${sapbits_storage_account_name}" --output none --only-show-errors + fi + fi - fi + fi - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" - rg_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" + rg_name=$(terraform -chdir="${terraform_module_directory}" output -no-color -raw created_resource_group_name | tr -d \") - echo "" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Capturing telemetry $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - echo "" + echo "" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Capturing telemetry $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + echo "" - full_script_path="$(realpath "${BASH_SOURCE[0]}")" - script_directory="$(dirname "${full_script_path}")" - az deployment group create --resource-group "${rg_name}" --name "SAP-LIBRARY_${rg_name}" --template-file "${script_directory}/templates/empty-deployment.json" --output none + full_script_path="$(realpath "${BASH_SOURCE[0]}")" + script_directory="$(dirname "${full_script_path}")" + az deployment group create --resource-group "${rg_name}" --name "SAP-LIBRARY_${rg_name}" --template-file "${script_directory}/templates/empty-deployment.json" --output none fi if [ -f "${system_config_information}".err ]; then - cat "${system_config_information}".err - rm "${system_config_information}".err + cat "${system_config_information}".err + rm "${system_config_information}".err fi unset TF_DATA_DIR @@ -1368,53 +1441,55 @@ unset TF_DATA_DIR useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --query allowSharedKeyAccess --subscription "${STATE_SUBSCRIPTION}" --out tsv) if [ "$useSAS" = "true" ]; then - echo "Storage Account authentication: key" - az storage blob upload --file "${parameterfile}" --container-name tfvars/"${state_path}"/"${key}" --name "${parameterfile_name}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none + echo "Storage Account authentication: key" + az storage blob upload --file "${parameterfile}" --container-name tfvars/"${state_path}"/"${key}" --name "${parameterfile_name}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none else - echo "Storage Account authentication: Entra ID" - az storage blob upload --file "${parameterfile}" --container-name tfvars/"${state_path}"/"${key}" --name "${parameterfile_name}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none -fi - -if [ "${deployment_system}" == sap_system ]; then - echo "Uploading the yaml files from ${param_dirname} to the storage account" - if [ "$useSAS" = "true" ]; then - az storage blob upload --file sap-parameters.yaml --container-name tfvars/"${state_path}"/"${key}" --name sap-parameters.yaml \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none - else - az storage blob upload --file sap-parameters.yaml --container-name tfvars/"${state_path}"/"${key}" --name sap-parameters.yaml \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none - fi - - hosts_file=$(ls *_hosts.yaml) - if [ "$useSAS" = "true" ]; then - az storage blob upload --file "${hosts_file}" --container-name tfvars/"${state_path}"/"${key}" --name "${hosts_file}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none - else - az storage blob upload --file "${hosts_file}" --container-name tfvars/"${state_path}"/"${key}" --name "${hosts_file}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none - fi + echo "Storage Account authentication: Entra ID" + az storage blob upload --file "${parameterfile}" --container-name tfvars/"${state_path}"/"${key}" --name "${parameterfile_name}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none +fi + +if [ -f sap-parameters.yaml ]; then + if [ "${deployment_system}" == sap_system ]; then + echo "Uploading the yaml files from ${param_dirname} to the storage account" + if [ "$useSAS" = "true" ]; then + az storage blob upload --file sap-parameters.yaml --container-name tfvars/"${state_path}"/"${key}" --name sap-parameters.yaml \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none + else + az storage blob upload --file sap-parameters.yaml --container-name tfvars/"${state_path}"/"${key}" --name sap-parameters.yaml \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none + fi + + hosts_file=$(ls *_hosts.yaml) + if [ "$useSAS" = "true" ]; then + az storage blob upload --file "${hosts_file}" --container-name tfvars/"${state_path}"/"${key}" --name "${hosts_file}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none + else + az storage blob upload --file "${hosts_file}" --container-name tfvars/"${state_path}"/"${key}" --name "${hosts_file}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none + fi + fi fi if [ "${deployment_system}" == sap_landscape ]; then - if [ "$useSAS" = "true" ]; then - az storage blob upload --file "${system_config_information}" --container-name tfvars/.sap_deployment_automation --name "${environment}${region_code}${network_logical_name}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none - else - az storage blob upload --file "${system_config_information}" --container-name tfvars/.sap_deployment_automation --name "${environment}${region_code}${network_logical_name}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none - fi + if [ "$useSAS" = "true" ]; then + az storage blob upload --file "${system_config_information}" --container-name tfvars/.sap_deployment_automation --name "${environment}${region_code}${network_logical_name}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none + else + az storage blob upload --file "${system_config_information}" --container-name tfvars/.sap_deployment_automation --name "${environment}${region_code}${network_logical_name}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none + fi fi if [ "${deployment_system}" == sap_library ]; then - deployer_config_information="${automation_config_directory}"/"${environment}""${region_code}" - if [ "$useSAS" = "true" ]; then - az storage blob upload --file "${deployer_config_information}" --container-name tfvars/.sap_deployment_automation --name "${environment}${region_code}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none - else - az storage blob upload --file "${deployer_config_information}" --container-name tfvars/.sap_deployment_automation --name "${environment}${region_code}" \ - --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none - fi + deployer_config_information="${automation_config_directory}"/"${environment}""${region_code}" + if [ "$useSAS" = "true" ]; then + az storage blob upload --file "${deployer_config_information}" --container-name tfvars/.sap_deployment_automation --name "${environment}${region_code}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --no-progress --overwrite --only-show-errors --output none + else + az storage blob upload --file "${deployer_config_information}" --container-name tfvars/.sap_deployment_automation --name "${environment}${region_code}" \ + --subscription "${STATE_SUBSCRIPTION}" --account-name "${REMOTE_STATE_SA}" --auth-mode login --no-progress --overwrite --only-show-errors --output none + fi fi echo "" diff --git a/deploy/scripts/pipeline_scripts/01-control-plane-deploy.sh b/deploy/scripts/pipeline_scripts/01-control-plane-deploy.sh index be1b2a612f..b1959dea39 100644 --- a/deploy/scripts/pipeline_scripts/01-control-plane-deploy.sh +++ b/deploy/scripts/pipeline_scripts/01-control-plane-deploy.sh @@ -13,13 +13,13 @@ script_directory="$(dirname "${full_script_path}")" #call stack has full scriptname when using source source "${script_directory}/helper.sh" -debug=False +DEBUG=False if [ "$SYSTEM_DEBUG" = True ]; then set -x DEBUG=True - export DEBUG fi +export DEBUG set -eu ENVIRONMENT=$(echo "$DEPLOYER_FOLDERNAME" | awk -F'-' '{print $1}' | xargs) @@ -389,7 +389,7 @@ fi if [ 1 = $added ]; then git config --global user.email "$BUILD_REQUESTEDFOREMAIL" git config --global user.name "$BUILD_REQUESTEDFOR" - if [ $debug = True ]; then + if [ $DEBUG = True ]; then git status --verbose if git commit --message --verbose "Added updates from Control Plane Deployment for $DEPLOYER_FOLDERNAME $LIBRARY_FOLDERNAME $BUILD_BUILDNUMBER [skip ci]"; then if git -c http.extraheader="AUTHORIZATION: bearer $SYSTEM_ACCESSTOKEN" push --set-upstream origin "$BRANCH" --force-with-lease; then diff --git a/deploy/scripts/pipeline_scripts/01-control-plane-prepare.sh b/deploy/scripts/pipeline_scripts/01-control-plane-prepare.sh index c08b4d1e57..68ccaf1102 100644 --- a/deploy/scripts/pipeline_scripts/01-control-plane-prepare.sh +++ b/deploy/scripts/pipeline_scripts/01-control-plane-prepare.sh @@ -13,15 +13,15 @@ script_directory="$(dirname "${full_script_path}")" #call stack has full scriptname when using source source "${script_directory}/helper.sh" +DEBUG=false if [ "$SYSTEM_DEBUG" = True ]; then set -x - debug=true - export debug - + DEBUG=true echo "Environment variables:" printenv - fi + +export DEBUG set -eu file_deployer_tfstate_key=$DEPLOYER_FOLDERNAME.tfstate diff --git a/deploy/scripts/pipeline_scripts/03-sap-system-deployment.sh b/deploy/scripts/pipeline_scripts/03-sap-system-deployment.sh index 3cdb551f39..f71c0fa4a2 100644 --- a/deploy/scripts/pipeline_scripts/03-sap-system-deployment.sh +++ b/deploy/scripts/pipeline_scripts/03-sap-system-deployment.sh @@ -15,9 +15,9 @@ source "${script_directory}/helper.sh" DEBUG=False if [ "$SYSTEM_DEBUG" = True ]; then - set -x - set -o errexit - DEBUG=True + set -x + set -o errexit + DEBUG=True fi export DEBUG @@ -34,58 +34,53 @@ mkdir -p .sap_deployment_automation git checkout -q "$BRANCH" if [ ! -f "$CONFIG_REPO_PATH/SYSTEM/$SAP_SYSTEM_FOLDERNAME/$SAP_SYSTEM_TFVARS_FILENAME" ]; then - echo -e "$bold_red--- $SAP_SYSTEM_TFVARS_FILENAME was not found ---$reset" - echo "##vso[task.logissue type=error]File $SAP_SYSTEM_TFVARS_FILENAME was not found." - exit 2 + echo -e "$bold_red--- $SAP_SYSTEM_TFVARS_FILENAME was not found ---$reset" + echo "##vso[task.logissue type=error]File $SAP_SYSTEM_TFVARS_FILENAME was not found." + exit 2 fi echo -e "$green--- Validations ---$reset" if [ "$USE_MSI" != "true" ]; then - if [ -z "$WL_ARM_SUBSCRIPTION_ID" ]; then - echo "##vso[task.logissue type=error]Variable ARM_SUBSCRIPTION_ID was not defined in the $VARIABLE_GROUP variable group." - exit 2 - fi - - if [ "$WL_ARM_SUBSCRIPTION_ID" == '$$(ARM_SUBSCRIPTION_ID)' ]; then - echo "##vso[task.logissue type=error]Variable ARM_SUBSCRIPTION_ID was not defined in the $VARIABLE_GROUP variable group." - exit 2 - fi - - if [ -z "$WL_ARM_CLIENT_ID" ]; then - echo "##vso[task.logissue type=error]Variable ARM_CLIENT_ID was not defined in the $VARIABLE_GROUP variable group." - exit 2 - fi - - if [ "$WL_ARM_CLIENT_ID" == '$$(ARM_CLIENT_ID)' ]; then - echo "##vso[task.logissue type=error]Variable ARM_CLIENT_ID was not defined in the $VARIABLE_GROUP variable group." - exit 2 - fi - - if [ -z "$WL_ARM_CLIENT_SECRET" ]; then - echo "##vso[task.logissue type=error]Variable ARM_CLIENT_SECRET was not defined in the $VARIABLE_GROUP variable group." - exit 2 - fi - - if [ "$WL_ARM_CLIENT_SECRET" == '$$(ARM_CLIENT_SECRET)' ]; then - echo "##vso[task.logissue type=error]Variable ARM_CLIENT_SECRET was not defined in the $VARIABLE_GROUP variable group." - exit 2 - fi - - if [ -z "$WL_ARM_TENANT_ID" ]; then - echo "##vso[task.logissue type=error]Variable ARM_TENANT_ID was not defined in the $VARIABLE_GROUP variable group." - exit 2 - fi - - if [ "$WL_ARM_TENANT_ID" == '$$(ARM_TENANT_ID)' ]; then - echo "##vso[task.logissue type=error]Variable ARM_TENANT_ID was not defined in the $VARIABLE_GROUP variable group." - exit 2 - fi - - if [ -z "$CP_ARM_SUBSCRIPTION_ID" ]; then - echo "##vso[task.logissue type=error]Variable CP_ARM_SUBSCRIPTION_ID was not defined in the $(parent_variable_group) variable group." - exit 2 - fi + if [ -z "$WL_ARM_SUBSCRIPTION_ID" ]; then + echo "##vso[task.logissue type=error]Variable ARM_SUBSCRIPTION_ID was not defined in the $VARIABLE_GROUP variable group." + exit 2 + fi + + if [ "$WL_ARM_SUBSCRIPTION_ID" == '$$(ARM_SUBSCRIPTION_ID)' ]; then + echo "##vso[task.logissue type=error]Variable ARM_SUBSCRIPTION_ID was not defined in the $VARIABLE_GROUP variable group." + exit 2 + fi + + if [ -z "$WL_ARM_CLIENT_ID" ]; then + echo "##vso[task.logissue type=error]Variable ARM_CLIENT_ID was not defined in the $VARIABLE_GROUP variable group." + exit 2 + fi + + if [ "$WL_ARM_CLIENT_ID" == '$$(ARM_CLIENT_ID)' ]; then + echo "##vso[task.logissue type=error]Variable ARM_CLIENT_ID was not defined in the $VARIABLE_GROUP variable group." + exit 2 + fi + + if [ -z "$WL_ARM_CLIENT_SECRET" ]; then + echo "##vso[task.logissue type=error]Variable ARM_CLIENT_SECRET was not defined in the $VARIABLE_GROUP variable group." + exit 2 + fi + + if [ "$WL_ARM_CLIENT_SECRET" == '$$(ARM_CLIENT_SECRET)' ]; then + echo "##vso[task.logissue type=error]Variable ARM_CLIENT_SECRET was not defined in the $VARIABLE_GROUP variable group." + exit 2 + fi + + if [ -z "$WL_ARM_TENANT_ID" ]; then + echo "##vso[task.logissue type=error]Variable ARM_TENANT_ID was not defined in the $VARIABLE_GROUP variable group." + exit 2 + fi + + if [ "$WL_ARM_TENANT_ID" == '$$(ARM_TENANT_ID)' ]; then + echo "##vso[task.logissue type=error]Variable ARM_TENANT_ID was not defined in the $VARIABLE_GROUP variable group." + exit 2 + fi fi # Set logon variables @@ -100,17 +95,17 @@ export ARM_SUBSCRIPTION_ID # Check if running on deployer if [[ ! -f /etc/profile.d/deploy_server.sh ]]; then - configureNonDeployer "$(tf_version)" || true - echo -e "$green--- az login ---$reset" - LogonToAzure false || true + configureNonDeployer "$(tf_version)" || true + echo -e "$green--- az login ---$reset" + LogonToAzure false || true else - LogonToAzure "$USE_MSI" || true + LogonToAzure "$USE_MSI" || true fi return_code=$? if [ 0 != $return_code ]; then - echo -e "$bold_red--- Login failed ---$reset" - echo "##vso[task.logissue type=error]az login failed." - exit $return_code + echo -e "$bold_red--- Login failed ---$reset" + echo "##vso[task.logissue type=error]az login failed." + exit $return_code fi ARM_SUBSCRIPTION_ID=$WL_ARM_SUBSCRIPTION_ID @@ -156,23 +151,23 @@ echo "-------------------------------------------------" az --version if [ "$ENVIRONMENT" != "$ENVIRONMENT_IN_FILENAME" ]; then - echo "##vso[task.logissue type=error]The environment setting in $SAP_SYSTEM_TFVARS_FILENAME '$ENVIRONMENT' does not match the $SAP_SYSTEM_TFVARS_FILENAME file name '$ENVIRONMENT_IN_FILENAME'. Filename should have the pattern [ENVIRONMENT]-[REGION_CODE]-[NETWORK_LOGICAL_NAME]-INFRASTRUCTURE" - exit 2 + echo "##vso[task.logissue type=error]The environment setting in $SAP_SYSTEM_TFVARS_FILENAME '$ENVIRONMENT' does not match the $SAP_SYSTEM_TFVARS_FILENAME file name '$ENVIRONMENT_IN_FILENAME'. Filename should have the pattern [ENVIRONMENT]-[REGION_CODE]-[NETWORK_LOGICAL_NAME]-INFRASTRUCTURE" + exit 2 fi if [ "$LOCATION" != "$LOCATION_IN_FILENAME" ]; then - echo "##vso[task.logissue type=error]The location setting in $SAP_SYSTEM_TFVARS_FILENAME '$LOCATION' does not match the $SAP_SYSTEM_TFVARS_FILENAME file name '$LOCATION_IN_FILENAME'. Filename should have the pattern [ENVIRONMENT]-[REGION_CODE]-[NETWORK_LOGICAL_NAME]-INFRASTRUCTURE" - exit 2 + echo "##vso[task.logissue type=error]The location setting in $SAP_SYSTEM_TFVARS_FILENAME '$LOCATION' does not match the $SAP_SYSTEM_TFVARS_FILENAME file name '$LOCATION_IN_FILENAME'. Filename should have the pattern [ENVIRONMENT]-[REGION_CODE]-[NETWORK_LOGICAL_NAME]-INFRASTRUCTURE" + exit 2 fi if [ "$NETWORK" != "$NETWORK_IN_FILENAME" ]; then - echo "##vso[task.logissue type=error]The network_logical_name setting in $SAP_SYSTEM_TFVARS_FILENAME '$NETWORK' does not match the $SAP_SYSTEM_TFVARS_FILENAME file name '$NETWORK_IN_FILENAME-. Filename should have the pattern [ENVIRONMENT]-[REGION_CODE]-[NETWORK_LOGICAL_NAME]-INFRASTRUCTURE" - exit 2 + echo "##vso[task.logissue type=error]The network_logical_name setting in $SAP_SYSTEM_TFVARS_FILENAME '$NETWORK' does not match the $SAP_SYSTEM_TFVARS_FILENAME file name '$NETWORK_IN_FILENAME-. Filename should have the pattern [ENVIRONMENT]-[REGION_CODE]-[NETWORK_LOGICAL_NAME]-INFRASTRUCTURE" + exit 2 fi if [ "$SID" != "$SID_IN_FILENAME" ]; then - echo "##vso[task.logissue type=error]The sid setting in $SAP_SYSTEM_TFVARS_FILENAME '$SID' does not match the $SAP_SYSTEM_TFVARS_FILENAME file name '$SID_IN_FILENAME-. Filename should have the pattern [ENVIRONMENT]-[REGION_CODE]-[NETWORK_LOGICAL_NAME]-[SID]" - exit 2 + echo "##vso[task.logissue type=error]The sid setting in $SAP_SYSTEM_TFVARS_FILENAME '$SID' does not match the $SAP_SYSTEM_TFVARS_FILENAME file name '$SID_IN_FILENAME-. Filename should have the pattern [ENVIRONMENT]-[REGION_CODE]-[NETWORK_LOGICAL_NAME]-[SID]" + exit 2 fi workload_environment_file_name="$CONFIG_REPO_PATH/.sap_deployment_automation/${ENVIRONMENT}${LOCATION_CODE_IN_FILENAME}${NETWORK}" @@ -188,8 +183,8 @@ az devops configure --defaults organization=$SYSTEM_COLLECTIONURI project='$SYST VARIABLE_GROUP_ID=$(az pipelines variable-group list --query "[?name=='$VARIABLE_GROUP'].id | [0]") if [ -z "${VARIABLE_GROUP_ID}" ]; then - echo "##vso[task.logissue type=error]Variable group $VARIABLE_GROUP could not be found." - exit 2 + echo "##vso[task.logissue type=error]Variable group $VARIABLE_GROUP could not be found." + exit 2 fi export VARIABLE_GROUP_ID @@ -237,14 +232,14 @@ echo -e "$green--- Deploy the System ---$reset" cd "$CONFIG_REPO_PATH/SYSTEM/$SAP_SYSTEM_FOLDERNAME" || exit "$SAP_AUTOMATION_REPO_PATH/deploy/scripts/installer.sh" --parameterfile $SAP_SYSTEM_TFVARS_FILENAME --type sap_system \ - --state_subscription "${STATE_SUBSCRIPTION}" --storageaccountname "${REMOTE_STATE_SA}" \ - --deployer_tfstate_key "${deployer_tfstate_key}" --landscape_tfstate_key "${landscape_tfstate_key}" \ - --ado --auto-approve + --state_subscription "${STATE_SUBSCRIPTION}" --storageaccountname "${REMOTE_STATE_SA}" \ + --deployer_tfstate_key "${deployer_tfstate_key}" --landscape_tfstate_key "${landscape_tfstate_key}" \ + --ado --auto-approve return_code=$? echo "Return code from deployment: ${return_code}" if [ 0 != $return_code ]; then - echo "##vso[task.logissue type=error]Return code from installer $return_code." + echo "##vso[task.logissue type=error]Return code from installer $return_code." fi set +o errexit @@ -262,64 +257,64 @@ git pull echo -e "$green--- Add & update files in the DevOps Repository ---$reset" if [ -f stdout.az ]; then - rm stdout.az + rm stdout.az fi added=0 if [ -f .terraform/terraform.tfstate ]; then - git add -f .terraform/terraform.tfstate - added=1 + git add -f .terraform/terraform.tfstate + added=1 fi if [ -f sap-parameters.yaml ]; then - git add sap-parameters.yaml - added=1 + git add sap-parameters.yaml + added=1 fi if [ -f "${SID}_hosts.yaml" ]; then - git add -f "${SID}_hosts.yaml" - added=1 + git add -f "${SID}_hosts.yaml" + added=1 fi if [ -f "${SID}.md" ]; then - git add "${CONFIG_REPO_PATH}/SYSTEM/$SAP_SYSTEM_FOLDERNAME/${SID}.md" - # echo "##vso[task.uploadsummary]./${SID}.md)" - added=1 + git add "${CONFIG_REPO_PATH}/SYSTEM/$SAP_SYSTEM_FOLDERNAME/${SID}.md" + # echo "##vso[task.uploadsummary]./${SID}.md)" + added=1 fi if [ -f "${SID}_inventory.md" ]; then - git add "${SID}_inventory.md" - added=1 + git add "${SID}_inventory.md" + added=1 fi if [ -f "${SID}_resource_names.json" ]; then - git add "${SID}_resource_names.json" - added=1 + git add "${SID}_resource_names.json" + added=1 fi if [ -f $SAP_SYSTEM_TFVARS_FILENAME ]; then - git add $SAP_SYSTEM_TFVARS_FILENAME - added=1 + git add $SAP_SYSTEM_TFVARS_FILENAME + added=1 fi if [ -f "${SID}_virtual_machines.json" ]; then - git add "${SID}_virtual_machines.json" - added=1 + git add "${SID}_virtual_machines.json" + added=1 fi # Pull changes git pull -q origin "$BRANCH" if [ 1 == $added ]; then - git config --global user.email "$BUILD_REQUESTEDFOREMAIL" - git config --global user.name "$BUILD_REQUESTEDFOR" - git commit -m "Added updates from SAP deployment of $SAP_SYSTEM_FOLDERNAME for $BUILD_BUILDNUMBER [skip ci]" - - if git -c http.extraheader="AUTHORIZATION: bearer SYSTEM_ACCESSTOKEN" push --set-upstream origin "$BRANCH" --force-with-lease; then - echo "##vso[task.logissue type=warning]Changes from SAP deployment of $SAP_SYSTEM_FOLDERNAME pushed to $BRANCH" - else - echo "##vso[task.logissue type=error]Failed to push changes to $BRANCH" - fi + git config --global user.email "$BUILD_REQUESTEDFOREMAIL" + git config --global user.name "$BUILD_REQUESTEDFOR" + git commit -m "Added updates from SAP deployment of $SAP_SYSTEM_FOLDERNAME for $BUILD_BUILDNUMBER [skip ci]" + + if git -c http.extraheader="AUTHORIZATION: bearer SYSTEM_ACCESSTOKEN" push --set-upstream origin "$BRANCH" --force-with-lease; then + echo "##vso[task.logissue type=warning]Changes from SAP deployment of $SAP_SYSTEM_FOLDERNAME pushed to $BRANCH" + else + echo "##vso[task.logissue type=error]Failed to push changes to $BRANCH" + fi fi # file_name=${SID}_inventory.md diff --git a/deploy/scripts/pipeline_scripts/05-DB-and-SAP-installation-prepare.sh b/deploy/scripts/pipeline_scripts/05-DB-and-SAP-installation-prepare.sh new file mode 100644 index 0000000000..c10d0d0e02 --- /dev/null +++ b/deploy/scripts/pipeline_scripts/05-DB-and-SAP-installation-prepare.sh @@ -0,0 +1,147 @@ +#!/bin/bash +green="\e[1;32m" +reset="\e[0m" +bold_red="\e[1;31m" +#External helper functions +source "sap-automation/deploy/pipelines/helper.sh" + +DEBUG=False + +if [ "$SYSTEM_DEBUG" = True ]; then + set -x + DEBUG=True +fi +export DEBUG +set -eu + +echo -e "$green--- Configure devops CLI extension ---$reset" +az config set extension.use_dynamic_install=yes_without_prompt --output none --only-show-errors +AZURE_DEVOPS_EXT_PAT=$SYSTEM_ACCESSTOKEN +export AZURE_DEVOPS_EXT_PAT + +ENVIRONMENT=$(echo "$SAP_SYSTEM_CONFIGURATION_NAME" | awk -F'-' '{print $1}' | xargs) + +LOCATION=$(echo "${SAP_SYSTEM_CONFIGURATION_NAME}" | awk -F'-' '{print $2}' | xargs) + +NETWORK=$(echo "${SAP_SYSTEM_CONFIGURATION_NAME}" | awk -F'-' '{print $3}' | xargs) + +SID=$(echo "${SAP_SYSTEM_CONFIGURATION_NAME}" | awk -F'-' '{print $4}' | xargs) + +cd "$CONFIG_REPO_PATH" || exit + +environment_file_name=".sap_deployment_automation/$ENVIRONMENT_CODE$LOCATION$NETWORK" +parameters_filename="$CONFIG_REPO_PATH/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml" + +az devops configure --defaults organization=$SYSTEM_COLLECTIONURI project='$SYSTEM_TEAMPROJECT' --output none --only-show-errors + +echo -e "$green--- Validations ---$reset" +if [ ! -f "${environment_file_name}" ]; then + echo -e "$bold_red--- ${environment_file_name} was not found ---$reset" + echo "##vso[task.logissue type=error]File ${environment_file_name} was not found." + exit 2 +fi + +if [ -z "$ARM_SUBSCRIPTION_ID" ]; then + echo "##vso[task.logissue type=error]Variable ARM_SUBSCRIPTION_ID was not defined." + exit 2 +fi + +if [ "azure pipelines" == $THIS_AGENT ]; then + echo "##vso[task.logissue type=error]Please use a self hosted agent for this playbook. Define it in the SDAF-$(environment_code) variable group" + exit 2 +fi + +echo -e "$green--- az login ---$reset" +# Check if running on deployer +if [[ ! -f /etc/profile.d/deploy_server.sh ]]; then + configureNonDeployer "$(tf_version)" + echo -e "$green--- az login ---$reset" + LogonToAzure false +else + LogonToAzure "$USE_MSI" +fi +return_code=$? +if [ 0 != $return_code ]; then + echo -e "$bold_red--- Login failed ---$reset" + echo "##vso[task.logissue type=error]az login failed." + exit $return_code +fi + +az account set --subscription "$ARM_SUBSCRIPTION_ID" --output none + +echo -e "$green--- Get key_vault name ---$reset" +VARIABLE_GROUP_ID=$(az pipelines variable-group list --query "[?name=='$VARIABLE_GROUP'].id | [0]") +export VARIABLE_GROUP_ID +printf -v val '%-15s' "$(variable_group) id:" +echo "$val $VARIABLE_GROUP_ID" +if [ -z "${VARIABLE_GROUP_ID}" ]; then + echo "##vso[task.logissue type=error]Variable group $VARIABLE_GROUP could not be found." + exit 2 +fi + +key_vault=$(getVariableFromVariableGroup "${VARIABLE_GROUP_ID}" "Deployer_Key_Vault" "${environment_file_name}" "keyvault") + +echo "##vso[build.updatebuildnumber]Deploying ${SAP_SYSTEM_CONFIGURATION_NAME} using BoM ${BOM_BASE_NAME}" + +echo "##vso[task.setvariable variable=SID;isOutput=true]${SID}" +echo "##vso[task.setvariable variable=SAP_PARAMETERS;isOutput=true]sap-parameters.yaml" +echo "##vso[task.setvariable variable=FOLDER;isOutput=true]$$CONFIG_REPO_PATH/SYSTEM/$SAP_SYSTEM_CONFIGURATION_NAME" +echo "##vso[task.setvariable variable=HOSTS;isOutput=true]${SID}_hosts.yaml" +echo "##vso[task.setvariable variable=KV_NAME;isOutput=true]$key_vault" + +echo "Environment: $ENVIRONMENT" +echo "Location: $LOCATION" +echo "Virtual network logical name: $NETWORK" +echo "Keyvault: $key_vault" +echo "SAP Application BoM: $BOM_BASE_NAME" + +echo "SID: ${SID}" +echo "Folder: $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}" +echo "Hosts file: ${SID}_hosts.yaml" +echo "sap_parameters_file: $parameters_filename" +echo "Configuration file: $environment_file_name" + +echo -e "$green--- Get Files from the DevOps Repository ---$reset" +cd "${CONFIG_REPO_PATH}/$(Deployment_Configuration_Path)/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}" + +echo -e "$green--- Add BOM Base Name and SAP FQDN to sap-parameters.yaml ---$reset" +sed -i 's|bom_base_name:.*|bom_base_name: '"$BOM_BASE_NAME"'|' sap-parameters.yaml + +echo -e "$green--- Get connection details ---$reset" +mkdir -p artifacts + +prefix="${ENVIRONMENT}${LOCATION}${NETWORK}" + +workload_key_vault=$(getVariableFromVariableGroup "${VARIABLE_GROUP_ID}" "${prefix}Workload_Key_Vault" "${environment_file_name}" "workloadkeyvault" || true) +workload_prefix=$(getVariableFromVariableGroup "${VARIABLE_GROUP_ID}" "${prefix}Workload_Secret_Prefix" "${environment_file_name}" "workload_zone_prefix" || true) +control_plane_subscription=$(getVariableFromVariableGroup "${VARIABLE_GROUP_ID}" "Terraform_Remote_Storage_Subscription" "${environment_file_name}" "STATE_SUBSCRIPTION" || true) + +echo "SID: ${SID}" +echo "Folder: $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}" +echo "Workload Key Vault: ${workload_key_vault}" + +echo "Control Plane Subscription: ${control_plane_subscription}" +echo "Workload Prefix: ${workload_prefix}" + +if [[ $EXTRA_PARAMETERS = "'$(EXTRA_PARAMETERS)'" ]]; then + new_parameters=$PIPELINE_EXTRA_PARAMETERS +else + echo "##vso[task.logissue type=warning]Extra parameters were provided - '$EXTRA_PARAMETERS'" + new_parameters="$EXTRA_PARAMETERS $PIPELINE_EXTRA_PARAMETERS" +fi + +echo "##vso[task.setvariable variable=SSH_KEY_NAME;isOutput=true]${workload_prefix}-sid-sshkey" +echo "##vso[task.setvariable variable=VAULT_NAME;isOutput=true]$workload_key_vault" +echo "##vso[task.setvariable variable=PASSWORD_KEY_NAME;isOutput=true]${workload_prefix}-sid-password" +echo "##vso[task.setvariable variable=USERNAME_KEY_NAME;isOutput=true]${workload_prefix}-sid-username" +echo "##vso[task.setvariable variable=NEW_PARAMETERS;isOutput=true]${new_parameters}" +echo "##vso[task.setvariable variable=CP_SUBSCRIPTION;isOutput=true]${control_plane_subscription}" + +az keyvault secret show --name "${workload_prefix}-sid-sshkey" --vault-name "$workload_key_vault" --subscription "$control_plane_subscription" --query value -o tsv >"artifacts/${SAP_SYSTEM_CONFIGURATION_NAME}_sshkey" +cp sap-parameters.yaml artifacts/. +cp "${SID}_hosts.yaml" artifacts/. + +2> >(while read line; do (echo >&2 "STDERROR: $line"); done) + +echo -e "$green--- Done ---$reset" +exit 0 diff --git a/deploy/scripts/pipeline_scripts/10-remover-terraform-system.sh b/deploy/scripts/pipeline_scripts/10-remover-terraform-system.sh index 35c2a8c50a..04581a2987 100644 --- a/deploy/scripts/pipeline_scripts/10-remover-terraform-system.sh +++ b/deploy/scripts/pipeline_scripts/10-remover-terraform-system.sh @@ -29,7 +29,6 @@ tfvarsFile="SYSTEM/$SAP_SYSTEM_FOLDERNAME/$SAP_SYSTEM_TFVARS_FILENAME" echo -e "$green--- Checkout $BRANCH ---$reset" cd "${CONFIG_REPO_PATH}" || exit -mkdir -p .sap_deployment_automation git checkout -q "$BRANCH" if [ ! -f "$CONFIG_REPO_PATH/SYSTEM/$SAP_SYSTEM_FOLDERNAME/$SAP_SYSTEM_TFVARS_FILENAME" ]; then diff --git a/deploy/scripts/pipeline_scripts/helper.sh b/deploy/scripts/pipeline_scripts/helper.sh index e8409e8399..f97475202f 100644 --- a/deploy/scripts/pipeline_scripts/helper.sh +++ b/deploy/scripts/pipeline_scripts/helper.sh @@ -78,6 +78,8 @@ function LogonToAzure() { echo "Deployment credential ID (SPN): $ARM_CLIENT_ID" unset ARM_USE_MSI az login --service-principal --username "$ARM_CLIENT_ID" --password="$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" --output none + echo "Logged on as:" + az account show --query user --output yaml TF_VAR_use_spn=true export TF_VAR_use_spn diff --git a/deploy/scripts/remove_controlplane.sh b/deploy/scripts/remove_controlplane.sh index 60e3c36e9c..fdf0653ad7 100755 --- a/deploy/scripts/remove_controlplane.sh +++ b/deploy/scripts/remove_controlplane.sh @@ -21,6 +21,12 @@ source "${script_directory}/helpers/script_helpers.sh" keep_agent=0 +if [ "$DEBUG" = True ]; then + echo -e "${cyan}Enabling debug mode$reset_formatting" + set -x + set -o errexit +fi + ################################################################################################ # # # This file contains the logic to deploy the environment to support SAP workloads. # @@ -38,49 +44,49 @@ keep_agent=0 ################################################################################################ function showhelp { - echo "" - echo "##################################################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to remove the deployer and library from an Azure region #" - echo "# #" - echo "# The script experts the following exports: #" - echo "# #" - echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing the cloned sap-automation #" - echo "# #" - echo "# The script is to be run from a parent folder to the folders containing the json parameter files for #" - echo "# the deployer and the library and the environment. #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" - echo "# #" - echo "# #" - echo "# Usage: remove_region.sh #" - echo "# -d or --deployer_parameter_file deployer parameter file #" - echo "# -l or --library_parameter_file library parameter file #" - echo "# #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# SAP_AUTOMATION_REPO_PATH/scripts/remove_controlplane.sh \ #" - echo "# --deployer_parameter_file DEPLOYER/PROD-WEEU-DEP00-INFRASTRUCTURE/PROD-WEEU-DEP00-INFRASTRUCTURE.tfvars \ #" - echo "# --library_parameter_file LIBRARY/PROD-WEEU-SAP_LIBRARY/PROD-WEEU-SAP_LIBRARY.tfvars \ #" - echo "# #" - echo "##################################################################################################################" + echo "" + echo "##################################################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to remove the deployer and library from an Azure region #" + echo "# #" + echo "# The script experts the following exports: #" + echo "# #" + echo "# SAP_AUTOMATION_REPO_PATH the path to the folder containing the cloned sap-automation #" + echo "# #" + echo "# The script is to be run from a parent folder to the folders containing the json parameter files for #" + echo "# the deployer and the library and the environment. #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder #" + echo "# #" + echo "# #" + echo "# Usage: remove_region.sh #" + echo "# -d or --deployer_parameter_file deployer parameter file #" + echo "# -l or --library_parameter_file library parameter file #" + echo "# #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# SAP_AUTOMATION_REPO_PATH/scripts/remove_controlplane.sh \ #" + echo "# --deployer_parameter_file DEPLOYER/PROD-WEEU-DEP00-INFRASTRUCTURE/PROD-WEEU-DEP00-INFRASTRUCTURE.tfvars \ #" + echo "# --library_parameter_file LIBRARY/PROD-WEEU-SAP_LIBRARY/PROD-WEEU-SAP_LIBRARY.tfvars \ #" + echo "# #" + echo "##################################################################################################################" } function missing { - printf -v val '%-40s' "$missing_value" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Missing : ${val} #" - echo "# #" - echo "# Usage: remove_region.sh #" - echo "# -d or --deployer_parameter_file deployer parameter file #" - echo "# -l or --library_parameter_file library parameter file #" - echo "# #" - echo "#########################################################################################" + printf -v val '%-40s' "$missing_value" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Missing : ${val} #" + echo "# #" + echo "# Usage: remove_region.sh #" + echo "# -d or --deployer_parameter_file deployer parameter file #" + echo "# -l or --library_parameter_file library parameter file #" + echo "# #" + echo "#########################################################################################" } @@ -90,94 +96,94 @@ INPUT_ARGUMENTS=$(getopt -n remove_region -o d:l:s:b:r:ihag --longoptions deploy VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp + showhelp fi echo "$INPUT_ARGUMENTS" eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -d | --deployer_parameter_file) - deployer_parameter_file="$2" - shift 2 - ;; - -l | --library_parameter_file) - library_parameter_file="$2" - shift 2 - ;; - -s | --subscription) - subscription="$2" - shift 2 - ;; - -b | --storage_account) - storage_account="$2" - shift 2 - ;; - -r | --resource_group) - resource_group="$2" - shift 2 - ;; - -a | --ado) - approve_parameter="--auto-approve;ado=1" - shift - ;; - -g | --keep_agent) - keep_agent=1 - shift - ;; - -i | --auto-approve) - approve_parameter="--auto-approve" - shift - ;; - -h | --help) - showhelp - exit 3 - ;; - --) - shift - break - ;; - esac + case "$1" in + -d | --deployer_parameter_file) + deployer_parameter_file="$2" + shift 2 + ;; + -l | --library_parameter_file) + library_parameter_file="$2" + shift 2 + ;; + -s | --subscription) + subscription="$2" + shift 2 + ;; + -b | --storage_account) + storage_account="$2" + shift 2 + ;; + -r | --resource_group) + resource_group="$2" + shift 2 + ;; + -a | --ado) + approve_parameter="--auto-approve;ado=1" + shift + ;; + -g | --keep_agent) + keep_agent=1 + shift + ;; + -i | --auto-approve) + approve_parameter="--auto-approve" + shift + ;; + -h | --help) + showhelp + exit 3 + ;; + --) + shift + break + ;; + esac done if [ -z "$deployer_parameter_file" ]; then - missing_value='deployer parameter file' - missing - exit 2 + missing_value='deployer parameter file' + missing + exit 2 fi if [ -z "$library_parameter_file" ]; then - missing_value='library parameter file' - missing - exit 2 + missing_value='library parameter file' + missing + exit 2 fi # Check that the exports ARM_SUBSCRIPTION_ID and SAP_AUTOMATION_REPO_PATH are defined validate_exports return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi # Check that Terraform and Azure CLI is installed validate_dependencies return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi # Check that parameter files have environment and location defined validate_key_parameters "$deployer_parameter_file" return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi if valid_region_name "${region}"; then - # Convert the region to the correct code - get_region_code "${region}" + # Convert the region to the correct code + get_region_code "${region}" else - echo "Invalid region: $region" - exit 2 + echo "Invalid region: $region" + exit 2 fi automation_config_directory=$CONFIG_REPO_PATH/.sap_deployment_automation @@ -186,15 +192,15 @@ deployer_config_information="${automation_config_directory}"/"${environment}""${ load_config_vars "${deployer_config_information}" "step" if [ 1 == "$step" ]; then - exit 0 + exit 0 fi if [ 0 == "$step" ]; then - exit 0 + exit 0 fi if [ -z "$deployer_config_information" ]; then - rm "$deployer_config_information" + rm "$deployer_config_information" fi root_dirname=$(pwd) @@ -206,14 +212,14 @@ this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 export TF_IN_AUTOMATION="true" # Terraform Plugins if checkIfCloudShell; then - mkdir -p "${HOME}/.terraform.d/plugin-cache" - export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" + mkdir -p "${HOME}/.terraform.d/plugin-cache" + export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" else - if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then - mkdir -p /opt/terraform/.terraform.d/plugin-cache - sudo chown -R "$USER" /opt/terraform - fi - export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache + if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then + sudo mkdir -p /opt/terraform/.terraform.d/plugin-cache + sudo chown -R "$USER" /opt/terraform + fi + export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache fi echo "Deployer environment: $environment" @@ -223,21 +229,21 @@ export TF_VAR_Agent_IP=$this_ip echo "Agent IP: $this_ip" if [ -n "${subscription}" ]; then - export ARM_SUBSCRIPTION_ID=$subscription + export ARM_SUBSCRIPTION_ID=$subscription else - subscription=$ARM_SUBSCRIPTION_ID + subscription=$ARM_SUBSCRIPTION_ID fi deployer_dirname=$(dirname "${deployer_parameter_file}") -deployer_file_parametername=$(basename "${deployer_parameter_file}") +deployer_tfvars_filename=$(basename "${deployer_parameter_file}") library_dirname=$(dirname "${library_parameter_file}") -library_file_parametername=$(basename "${library_parameter_file}") +library_tfvars_filename=$(basename "${library_parameter_file}") relative_path="${root_dirname}"/"${deployer_dirname}" export TF_DATA_DIR="${relative_path}"/.terraform -curdir=$(pwd) +current_directory=$(pwd) #we know that we have a valid az session so let us set the environment variables set_executing_user_environment_variables "none" @@ -248,42 +254,42 @@ cd "${deployer_dirname}" || exit param_dirname=$(pwd) -relative_path="${curdir}"/"${deployer_dirname}" +relative_path="${current_directory}"/"${deployer_dirname}" terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/run/sap_deployer/ export TF_DATA_DIR="${param_dirname}/.terraform" if [ -z "${storage_account}" ]; then - load_config_vars "${deployer_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" - load_config_vars "${deployer_config_information}" "REMOTE_STATE_RG" - load_config_vars "${deployer_config_information}" "tfstate_resource_id" + load_config_vars "${deployer_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${deployer_config_information}" "REMOTE_STATE_SA" + load_config_vars "${deployer_config_information}" "REMOTE_STATE_RG" + load_config_vars "${deployer_config_information}" "tfstate_resource_id" - if [ -n "${STATE_SUBSCRIPTION}" ]; then - subscription="${STATE_SUBSCRIPTION}" - az account set --sub "${STATE_SUBSCRIPTION}" + if [ -n "${STATE_SUBSCRIPTION}" ]; then + subscription="${STATE_SUBSCRIPTION}" + az account set --sub "${STATE_SUBSCRIPTION}" - fi + fi - if [ -n "${REMOTE_STATE_SA}" ]; then - storage_account="${REMOTE_STATE_SA}" - fi + if [ -n "${REMOTE_STATE_SA}" ]; then + storage_account="${REMOTE_STATE_SA}" + fi - if [ -n "${REMOTE_STATE_RG}" ]; then - resource_group="${REMOTE_STATE_RG}" - fi + if [ -n "${REMOTE_STATE_RG}" ]; then + resource_group="${REMOTE_STATE_RG}" + fi fi -key=$(echo "${deployer_file_parametername}" | cut -d. -f1) +key=$(echo "${deployer_tfvars_filename}" | cut -d. -f1) useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --query allowSharedKeyAccess --subscription "${STATE_SUBSCRIPTION}" --out tsv) if [ "$useSAS" = "true" ]; then - echo "Storage Account Authentication: Key" - export ARM_USE_AZUREAD=false + echo "Storage Account Authentication: Key" + export ARM_USE_AZUREAD=false else - echo "Storage Account Authentication: Entra ID" - export ARM_USE_AZUREAD=true + echo "Storage Account Authentication: Entra ID" + export ARM_USE_AZUREAD=true fi # Reinitialize @@ -301,64 +307,104 @@ echo "# container_name=tfstate" echo "# key=${key}.terraform.tfstate" if [ -f init_error.log ]; then - rm init_error.log + rm init_error.log fi if [ -f ./.terraform/terraform.tfstate ]; then - azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) - if [ -n "$azure_backend" ]; then - echo "State is stored in Azure" - - #Initialize the statefile and copy to local - - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_deployer/ - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Running Terraform init (deployer - local) #" - echo "# #" - echo "#########################################################################################" - echo "" - if terraform -chdir="${terraform_module_directory}" init -force-copy -migrate-state --backend-config "path=${param_dirname}/terraform.tfstate"; then - return_value=$? - else - return_value=$? - fi - else - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_deployer/ - if terraform -chdir="${terraform_module_directory}" init -reconfigure -backend-config "path=${param_dirname}/terraform.tfstate"; then - return_value=$? - else - return_value=$? - fi - fi + azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) + if [ -n "$azure_backend" ]; then + echo "State is stored in Azure" + + #Initialize the statefile and copy to local + + terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_deployer/ + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Running Terraform init (deployer - local) #" + echo "# #" + echo "#########################################################################################" + echo "" + if terraform -chdir="${terraform_module_directory}" init -force-copy -migrate-state --backend-config "path=${param_dirname}/terraform.tfstate"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + fi + else + terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_deployer/ + if terraform -chdir="${terraform_module_directory}" init -reconfigure -backend-config "path=${param_dirname}/terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + return_value=$? + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + fi + fi else - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_deployer/ - if terraform -chdir="${terraform_module_directory}" init -reconfigure -backend-config "path=${param_dirname}/terraform.tfstate"; then - return_value=$? - else - return_value=$? - fi + terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_deployer/ + if terraform -chdir="${terraform_module_directory}" init -reconfigure -backend-config "path=${param_dirname}/terraform.tfstate"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + fi fi return_value=$? deployer_statefile_foldername_path="${param_dirname}" if [ 0 != $return_value ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Error when initializing Terraform (deployer - local) $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - cat init_error.log - rm init_error.log - unset TF_DATA_DIR - exit 10 + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Error when initializing Terraform (deployer - local) $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + cat init_error.log + rm init_error.log + unset TF_DATA_DIR + exit 10 fi -cd "${curdir}" || exit +var_file="${param_dirname}/${deployer_tfvars_filename}" + +echo "" +echo "#########################################################################################" +echo "# #" +echo "# Running Terraform apply (deployer - local) #" +echo "# #" +echo "#########################################################################################" +echo "" + +if terraform -chdir="${terraform_module_directory}" apply -var-file="${var_file}" "${approve_parameter}"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform apply: succeeded$reset_formatting" + echo "" +else + return_value=$? + echo "" + echo -e "${bold_red}Terraform apply: failed$reset_formatting" + echo "" +fi + +cd "${current_directory}" || exit -key=$(echo "${library_file_parametername}" | cut -d. -f1) +key=$(echo "${library_tfvars_filename}" | cut -d. -f1) cd "${library_dirname}" || exit param_dirname=$(pwd) @@ -369,7 +415,7 @@ export TF_DATA_DIR="${param_dirname}/.terraform" #Reinitialize -key=$(echo "${library_file_parametername}" | cut -d. -f1) +key=$(echo "${library_tfvars_filename}" | cut -d. -f1) echo "" echo "#########################################################################################" @@ -386,62 +432,80 @@ echo "# container_name=tfstate" echo "# key=${key}.terraform.tfstate" if [ -f ./.terraform/terraform.tfstate ]; then - azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) - if [ -n "$azure_backend" ]; then - - echo "State is stored in Azure" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Running Terraform init (library - local) #" - echo "# #" - echo "#########################################################################################" - echo "" - - #Initialize the statefile and copy to local - if terraform -chdir="${terraform_module_directory}" init -force-copy -migrate-state --backend-config \ - "path=${param_dirname}/terraform.tfstate" -var deployer_statefile_folder="${deployer_statefile_foldername_path}"; then - return_value=$? - else - return_value=$? - fi - else - if terraform -chdir="${terraform_module_directory}" init -reconfigure --backend-config "path=${param_dirname}/terraform.tfstate" \ - -var deployer_statefile_folder="${deployer_statefile_foldername_path}"; then - return_value=$? - else - return_value=$? - fi - fi + azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) + if [ -n "$azure_backend" ]; then + + echo "State is stored in Azure" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Running Terraform init (library - local) #" + echo "# #" + echo "#########################################################################################" + echo "" + + #Initialize the statefile and copy to local + if terraform -chdir="${terraform_module_directory}" init -force-copy -migrate-state --backend-config \ + "path=${param_dirname}/terraform.tfstate" -var deployer_statefile_folder="${deployer_statefile_foldername_path}"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + fi + else + if terraform -chdir="${terraform_module_directory}" init -reconfigure --backend-config "path=${param_dirname}/terraform.tfstate" \ + -var deployer_statefile_folder="${deployer_statefile_foldername_path}"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + fi + fi else - if terraform -chdir="${terraform_module_directory}" init -reconfigure --backend-config "path=${param_dirname}/terraform.tfstate" \ - -var deployer_statefile_folder="${deployer_statefile_foldername_path}"; then - return_value=$? - else - return_value=$? - fi + if terraform -chdir="${terraform_module_directory}" init -reconfigure --backend-config "path=${param_dirname}/terraform.tfstate" \ + -var deployer_statefile_folder="${deployer_statefile_foldername_path}"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + fi fi if [ 0 != $return_code ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Error when initializing Terraform (library - local) $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - unset TF_DATA_DIR - exit 1 + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Error when initializing Terraform (library - local) $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + unset TF_DATA_DIR + exit 1 fi extra_vars="" if [ -f terraform.tfvars ]; then - extra_vars=" -var-file=${param_dirname}/terraform.tfvars " + extra_vars=" -var-file=${param_dirname}/terraform.tfvars " fi -var_file="${param_dirname}"/"${library_file_parametername}" +var_file="${param_dirname}"/"${library_tfvars_filename}" export TF_DATA_DIR="${param_dirname}/.terraform" export TF_use_spn=false @@ -455,86 +519,124 @@ echo "########################################################################## echo "" if terraform -chdir="${terraform_module_directory}" destroy -var-file="${var_file}" -var use_deployer=false \ - -var deployer_statefile_foldername="${deployer_statefile_foldername_path}" "${approve_parameter}"; then - return_value=$? + -var deployer_statefile_foldername="${deployer_statefile_foldername_path}" "${approve_parameter}"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform destroy: succeeded$reset_formatting" + echo "" + if [ -f "${param_dirname}/terraform.tfstate" ]; then + rm "${param_dirname}/terraform.tfstate" + fi + if [ -f "${param_dirname}/terraform.tfstate.backup" ]; then + rm "${param_dirname}/terraform.tfstate.backup" + fi + if [ -f "${param_dirname}/.terraform/terraform.tfstate" ]; then + rm "${param_dirname}/.terraform/terraform.tfstate" + fi else - return_value=$? + return_value=$? + echo "" + echo -e "${bold_red}Terraform destroy: failed$reset_formatting" + echo "" fi if [ 0 != $return_value ]; then - exit $return_value + exit $return_value else - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Reset settings #" - echo "# #" - echo "#########################################################################################" - echo "" - - STATE_SUBSCRIPTION='' - REMOTE_STATE_SA='' - REMOTE_STATE_RG='' - save_config_vars "${deployer_config_information}" \ - tfstate_resource_id \ - REMOTE_STATE_SA \ - REMOTE_STATE_RG \ - STATE_SUBSCRIPTION + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Reset settings #" + echo "# #" + echo "#########################################################################################" + echo "" + + STATE_SUBSCRIPTION='' + REMOTE_STATE_SA='' + REMOTE_STATE_RG='' + save_config_vars "${deployer_config_information}" \ + tfstate_resource_id \ + REMOTE_STATE_SA \ + REMOTE_STATE_RG \ + STATE_SUBSCRIPTION fi -cd "${curdir}" || exit +cd "${current_directory}" || exit if [ 1 -eq $keep_agent ]; then - echo "Keeping the Azure DevOps agent" - step=1 - save_config_var "step" "${deployer_config_information}" + echo "Keeping the Azure DevOps agent" + step=1 + save_config_var "step" "${deployer_config_information}" else - cd "${deployer_dirname}" || exit - - param_dirname=$(pwd) - - if [ -z "$keyvault" ]; then - load_config_vars "${deployer_config_information}" "keyvault" - if valid_kv_name "$keyvault"; then - az keyvault network-rule add --ip-address "$TF_VAR_Agent_IP" --name "$keyvault" - fi - - fi - - terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_deployer/ - export TF_DATA_DIR="${param_dirname}/.terraform" - - extra_vars="" - - if [ -f terraform.tfvars ]; then - extra_vars=" -var-file=${param_dirname}/terraform.tfvars " - fi - - var_file="${param_dirname}"/"${deployer_file_parametername}" - - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Running Terraform destroy (deployer) #" - echo "# #" - echo "#########################################################################################" - echo "" - - terraform -chdir="${terraform_module_directory}" destroy -var-file="${var_file}" "${approve_parameter}" - return_value=$? - step=0 - save_config_var "step" "${deployer_config_information}" - if [ 0 != $return_value ]; then - keyvault='' - deployer_tfstate_key='' - save_config_var "$keyvault" "${deployer_config_information}" - save_config_var "$deployer_tfstate_key" "${deployer_config_information}" - fi + cd "${deployer_dirname}" || exit + + param_dirname=$(pwd) + + if [ -z "$keyvault" ]; then + load_config_vars "${deployer_config_information}" "keyvault" + if valid_kv_name "$keyvault"; then + az keyvault network-rule add --ip-address "$TF_VAR_Agent_IP" --name "$keyvault" + fi + + fi + + terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/sap_deployer/ + export TF_DATA_DIR="${param_dirname}/.terraform" + + extra_vars="" + + if [ -f terraform.tfvars ]; then + extra_vars=" -var-file=${param_dirname}/terraform.tfvars " + fi + + var_file="${param_dirname}"/"${deployer_tfvars_filename}" + + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Running Terraform destroy (deployer) #" + echo "# #" + echo "#########################################################################################" + echo "" + + if terraform -chdir="${terraform_module_directory}" destroy -var-file="${var_file}" "${approve_parameter}"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform destroy: succeeded$reset_formatting" + echo "" + if [ -f "${param_dirname}/terraform.tfstate" ]; then + rm "${param_dirname}/terraform.tfstate" + fi + if [ -f "${param_dirname}/terraform.tfstate.backup" ]; then + rm "${param_dirname}/terraform.tfstate.backup" + fi + if [ -f "${param_dirname}/.terraform/terraform.tfstate" ]; then + rm "${param_dirname}/.terraform/terraform.tfstate" + fi + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform destroy: failed$reset_formatting" + echo "" + fi + + return_value=$? + step=0 + save_config_var "step" "${deployer_config_information}" + if [ 0 != $return_value ]; then + keyvault='' + deployer_tfstate_key='' + save_config_var "$keyvault" "${deployer_config_information}" + save_config_var "$deployer_tfstate_key" "${deployer_config_information}" + if [ -f "${deployer_config_information}" ]; then + rm "${deployer_config_information}" + fi + fi fi -cd "${curdir}" || exit +cd "${current_directory}" || exit unset TF_DATA_DIR exit $return_value diff --git a/deploy/scripts/remove_deployer.sh b/deploy/scripts/remove_deployer.sh index 430c2aeb37..b4fc7a0728 100755 --- a/deploy/scripts/remove_deployer.sh +++ b/deploy/scripts/remove_deployer.sh @@ -20,33 +20,33 @@ source "${script_directory}/helpers/script_helpers.sh" #Internal helper functions function showhelp { - echo "" - echo "#########################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to remove the deployer. #" - echo "# The script experts the following exports: #" - echo "# #" - echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" - echo "# DEPLOYMENT_REPO_PATH the path to the folder containing the cloned sap-automation #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# ~/.sap_deployment_automation folder #" - echo "# #" - echo "# #" - echo "# Usage: remove_deployer.sh #" - echo "# -p deployer parameter file #" - echo "# #" - echo "# -i interactive true/false setting the value to false will not prompt before apply #" - echo "# -h Show help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/remove_deployer.sh \ #" - echo "# -p PROD-WEEU-DEP00-INFRASTRUCTURE.json \ #" - echo "# -i true #" - echo "# #" - echo "#########################################################################################" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to remove the deployer. #" + echo "# The script experts the following exports: #" + echo "# #" + echo "# ARM_SUBSCRIPTION_ID to specify which subscription to deploy to #" + echo "# DEPLOYMENT_REPO_PATH the path to the folder containing the cloned sap-automation #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# ~/.sap_deployment_automation folder #" + echo "# #" + echo "# #" + echo "# Usage: remove_deployer.sh #" + echo "# -p deployer parameter file #" + echo "# #" + echo "# -i interactive true/false setting the value to false will not prompt before apply #" + echo "# -h Show help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/remove_deployer.sh \ #" + echo "# -p PROD-WEEU-DEP00-INFRASTRUCTURE.json \ #" + echo "# -i true #" + echo "# #" + echo "#########################################################################################" } #process inputs - may need to check the option i for auto approve as it is not used @@ -54,33 +54,38 @@ INPUT_ARGUMENTS=$(getopt -n remove_deployer -o p:ih --longoptions parameterfile: VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp + showhelp fi eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -p | --parameterfile) - parameterfile="$2" - shift 2 - ;; - -i | --auto-approve) - approve="--auto-approve" - shift - ;; - -h | --help) - showhelp - exit 3 - shift - ;; - --) - shift - break - ;; - esac + case "$1" in + -p | --parameterfile) + parameterfile="$2" + shift 2 + ;; + -i | --auto-approve) + approve="--auto-approve" + shift + ;; + -h | --help) + showhelp + exit 3 + shift + ;; + --) + shift + break + ;; + esac done +if [ "$DEBUG" = True ]; then + set -x + set -o errexit +fi + deployment_system=sap_deployer param_dirname=$(dirname "${parameterfile}") @@ -88,31 +93,31 @@ param_dirname=$(dirname "${parameterfile}") echo "Parameter file: ${parameterfile}" if [ ! -f "${parameterfile}" ]; then - printf -v val %-40.40s "$parameterfile" - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Parameter file does not exist: ${val} #" - echo "# #" - echo "#########################################################################################" - exit 2 #No such file or directory + printf -v val %-40.40s "$parameterfile" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Parameter file does not exist: ${val} #" + echo "# #" + echo "#########################################################################################" + exit 2 #No such file or directory fi if [ "$param_dirname" != '.' ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo "# Please run this command from the folder containing the parameter file #" - echo "# #" - echo "#########################################################################################" - exit 3 + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Please run this command from the folder containing the parameter file #" + echo "# #" + echo "#########################################################################################" + exit 3 fi # Check that parameter files have environment and location defined validate_key_parameters "$parameterfile" return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi region=$(echo "${region}" | tr "[:upper:]" "[:lower:]") @@ -135,7 +140,7 @@ var_file="${param_dirname}"/"${parameterfile}" validate_exports return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/bootstrap/"${deployment_system}"/ @@ -146,16 +151,16 @@ export TF_DATA_DIR="${param_dirname}"/.terraform validate_dependencies return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi -dir=$(pwd) +current_directory=$(pwd) -terraform -chdir="${terraform_module_directory}" init -reconfigure -backend-config "path=${dir}/terraform.tfstate" +terraform -chdir="${terraform_module_directory}" init -reconfigure -backend-config "path=${current_directory}/terraform.tfstate" extra_vars="" if [ -f terraform.tfvars ]; then - extra_vars=" -var-file=${param_dirname}/terraform.tfvars " + extra_vars=" -var-file=${param_dirname}/terraform.tfvars " fi echo "" @@ -168,55 +173,69 @@ echo "" parallelism=10 -#Provide a way to limit the number of parallell tasks for Terraform +#Provide a way to limit the number of parallel tasks for Terraform if [[ -n "$TF_PARALLELLISM" ]]; then - parallelism="$TF_PARALLELLISM" + parallelism="$TF_PARALLELLISM" fi if terraform -chdir="${terraform_module_directory}" destroy "${approve}" -lock=false -parallelism="${parallelism}" -json -var-file="${var_file}" "$extra_vars" | tee -a destroy_output.json; then - return_value=$? + return_value=$? + echo "" + echo -e "${bold_red}Terraform destroy: $reset_formatting succeeded" + echo "" else - return_value=$? - echo "Terraform destroy failed" + return_value=$? + echo "" + echo -e "${bold_red}Terraform destroy: $reset_formatting failed" + echo "" fi if [ -f destroy_output.json ]; then - errors_occurred=$(jq 'select(."@level" == "error") | length' destroy_output.json) - - if [[ -n $errors_occurred ]]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore!Errors during the destroy phase!$reset_formatting #" - - return_value=2 - all_errors=$(jq 'select(."@level" == "error") | {summary: .diagnostic.summary, detail: .diagnostic.detail}' destroy_output.json) - if [[ -n ${all_errors} ]]; then - readarray -t errors_strings < <(echo ${all_errors} | jq -c '.') - for errors_string in "${errors_strings[@]}"; do - string_to_report=$(jq -c -r '.detail ' <<<"$errors_string") - if [[ -z ${string_to_report} ]]; then - string_to_report=$(jq -c -r '.summary ' <<<"$errors_string") - fi - - echo -e "# $bold_red_underscore $string_to_report $reset_formatting" - echo "##vso[task.logissue type=error]${string_to_report}" - - done - - fi - echo "# #" - echo "#########################################################################################" - echo "" - fi + errors_occurred=$(jq 'select(."@level" == "error") | length' destroy_output.json) + + if [[ -n $errors_occurred ]]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore!Errors during the destroy phase!$reset_formatting #" + + return_value=2 + all_errors=$(jq 'select(."@level" == "error") | {summary: .diagnostic.summary, detail: .diagnostic.detail}' destroy_output.json) + if [[ -n ${all_errors} ]]; then + readarray -t errors_strings < <(echo ${all_errors} | jq -c '.') + for errors_string in "${errors_strings[@]}"; do + string_to_report=$(jq -c -r '.detail ' <<<"$errors_string") + if [[ -z ${string_to_report} ]]; then + string_to_report=$(jq -c -r '.summary ' <<<"$errors_string") + fi + + echo -e "# $bold_red_underscore $string_to_report $reset_formatting" + echo "##vso[task.logissue type=error]${string_to_report}" + + done + + fi + echo "# #" + echo "#########################################################################################" + echo "" + fi fi if [ -f destroy_output.json ]; then - rm destroy_output.json + rm destroy_output.json fi -step=0 -save_config_var "step" "${deployer_config_information}" +if [ 0 == $return_value ]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo "# Deployer removed successfully #" + echo "# #" + echo "#########################################################################################" + echo "" + step=0 + save_config_var "step" "${deployer_config_information}" +fi unset TF_DATA_DIR diff --git a/deploy/scripts/remover.sh b/deploy/scripts/remover.sh index 5903c6f5d6..1ed1226f4c 100755 --- a/deploy/scripts/remover.sh +++ b/deploy/scripts/remover.sh @@ -18,48 +18,53 @@ source "${script_directory}/deploy_utils.sh" #helper files source "${script_directory}/helpers/script_helpers.sh" +if [ "$DEBUG" = True ]; then + set -x + set -o errexit +fi + #Internal helper functions function showhelp { - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore !Warning!: This script will remove deployed systems $reset_formatting #" - echo "# #" - echo "# This file contains the logic to remove the different systems #" - echo "# The script expects the following exports: #" - echo "# #" - echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" - echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" - echo "# REMOTE_STATE_RG (resource group name for storage account containing state files) #" - echo "# REMOTE_STATE_SA (storage account for state file) #" - echo "# #" - echo "# The script will persist the parameters needed between the executions in the #" - echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder. #" - echo "# #" - echo "# #" - echo "# Usage: remover.sh #" - echo "# -p or --parameterfile parameter file #" - echo "# -t or --type type of system to remove #" - echo "# valid options: #" - echo "# sap_deployer #" - echo "# sap_library #" - echo "# sap_landscape #" - echo "# sap_system #" - echo "# -h or --help Show help #" - echo "# #" - echo "# Optional parameters #" - echo "# #" - echo "# -o or --storageaccountname Storage account name for state file #" - echo "# -s or --state_subscription Subscription for tfstate storage account #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/remover.sh \ #" - echo "# --parameterfile DEV-WEEU-SAP01-X00.tfvars \ #" - echo "# --type sap_system #" - echo "# #" - echo "#########################################################################################" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore !Warning!: This script will remove deployed systems $reset_formatting #" + echo "# #" + echo "# This file contains the logic to remove the different systems #" + echo "# The script expects the following exports: #" + echo "# #" + echo "# SAP_AUTOMATION_REPO_PATH (path to the repo folder (sap-automation)) #" + echo "# ARM_SUBSCRIPTION_ID (subscription containing the state file storage account) #" + echo "# REMOTE_STATE_RG (resource group name for storage account containing state files) #" + echo "# REMOTE_STATE_SA (storage account for state file) #" + echo "# #" + echo "# The script will persist the parameters needed between the executions in the #" + echo "# [CONFIG_REPO_PATH]/.sap_deployment_automation folder. #" + echo "# #" + echo "# #" + echo "# Usage: remover.sh #" + echo "# -p or --parameterfile parameter file #" + echo "# -t or --type type of system to remove #" + echo "# valid options: #" + echo "# sap_deployer #" + echo "# sap_library #" + echo "# sap_landscape #" + echo "# sap_system #" + echo "# -h or --help Show help #" + echo "# #" + echo "# Optional parameters #" + echo "# #" + echo "# -o or --storageaccountname Storage account name for state file #" + echo "# -s or --state_subscription Subscription for tfstate storage account #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/remover.sh \ #" + echo "# --parameterfile DEV-WEEU-SAP01-X00.tfvars \ #" + echo "# --type sap_system #" + echo "# #" + echo "#########################################################################################" } #process inputs - may need to check the option i for auto approve as it is not used @@ -67,54 +72,54 @@ INPUT_ARGUMENTS=$(getopt -n remover -o p:o:t:s:d:l:ahi --longoptions type:,param VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp + showhelp fi called_from_ado=0 eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -p | --parameterfile) - parameterfile="$2" - shift 2 - ;; - -o | --storageaccountname) - REMOTE_STATE_SA="$2" - shift 2 - ;; - -s | --state_subscription) - STATE_SUBSCRIPTION="$2" - shift 2 - ;; - -t | --type) - deployment_system="$2" - shift 2 - ;; - -d | --deployer_tfstate_key) - deployer_tfstate_key="$2" - shift 2 - ;; - -l | --landscape_tfstate_key) - landscape_tfstate_key="$2" - shift 2 - ;; - -i | --auto-approve) - approve="--auto-approve" - shift - ;; - -a | --ado) - called_from_ado=1 - shift - ;; - -h | --help) - showhelp - exit 3 - ;; - --) - shift - break - ;; - esac + case "$1" in + -p | --parameterfile) + parameterfile="$2" + shift 2 + ;; + -o | --storageaccountname) + REMOTE_STATE_SA="$2" + shift 2 + ;; + -s | --state_subscription) + STATE_SUBSCRIPTION="$2" + shift 2 + ;; + -t | --type) + deployment_system="$2" + shift 2 + ;; + -d | --deployer_tfstate_key) + deployer_tfstate_key="$2" + shift 2 + ;; + -l | --landscape_tfstate_key) + landscape_tfstate_key="$2" + shift 2 + ;; + -i | --auto-approve) + approve="--auto-approve" + shift + ;; + -a | --ado) + called_from_ado=1 + shift + ;; + -h | --help) + showhelp + exit 3 + ;; + --) + shift + break + ;; + esac done #variables @@ -136,71 +141,78 @@ parameterfile_path=$(realpath "${parameterfile}") parameterfile_name=$(basename "${parameterfile_path}") parameterfile_dirname=$(dirname "${parameterfile_path}") +#Provide a way to limit the number of parallel tasks for Terraform +if [[ -n "$TF_PARALLELLISM" ]]; then + parallelism="$TF_PARALLELLISM" +else + parallelism=3 +fi + if [ "${parameterfile_dirname}" != "${working_directory}" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Please run this command from the folder containing the parameter file $reset_formatting #" - echo "# #" - echo "#########################################################################################" - exit 3 + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Please run this command from the folder containing the parameter file $reset_formatting #" + echo "# #" + echo "#########################################################################################" + exit 3 fi if [ ! -f "${parameterfile}" ]; then - printf -v val %-35.35s "$parameterfile" - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Parameter file does not exist: ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - exit 2 #No such file or directory + printf -v val %-35.35s "$parameterfile" + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Parameter file does not exist: ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + exit 2 #No such file or directory fi if [ -z "${deployment_system}" ]; then - printf -v val %-40.40s "$deployment_system" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Incorrect system deployment type specified: ${val} $reset_formatting #" - echo "# #" - echo "# Valid options are: #" - echo "# sap_deployer #" - echo "# sap_library #" - echo "# sap_landscape #" - echo "# sap_system #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 64 #script usage wrong + printf -v val %-40.40s "$deployment_system" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Incorrect system deployment type specified: ${val} $reset_formatting #" + echo "# #" + echo "# Valid options are: #" + echo "# sap_deployer #" + echo "# sap_library #" + echo "# sap_landscape #" + echo "# sap_system #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 64 #script usage wrong fi # Check that the exports ARM_SUBSCRIPTION_ID and SAP_AUTOMATION_REPO_PATH are defined validate_exports return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi # Check that Terraform and Azure CLI is installed validate_dependencies return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi # Check that parameter files have environment and location defined validate_key_parameters "$parameterfile_name" return_code=$? if [ 0 != $return_code ]; then - exit $return_code + exit $return_code fi if valid_region_name "${region}"; then - # Convert the region to the correct code - get_region_code "${region}" + # Convert the region to the correct code + get_region_code "${region}" else - echo "Invalid region: $region" - exit 2 + echo "Invalid region: $region" + exit 2 fi this_ip=$(curl -s ipinfo.io/ip) >/dev/null 2>&1 @@ -215,29 +227,36 @@ generic_config_information="${automation_config_directory}"/config system_config_information="${automation_config_directory}/${environment}${region_code}" if [ "${deployment_system}" == sap_landscape ]; then - load_config_vars "$parameterfile_name" "network_logical_name" - network_logical_name=$(echo "${network_logical_name}" | tr "[:lower:]" "[:upper:]" | tr -d ' \r\n') + load_config_vars "$parameterfile_name" "network_logical_name" + network_logical_name=$(echo "${network_logical_name}" | tr "[:lower:]" "[:upper:]" | tr -d ' \r\n') - system_config_information="${automation_config_directory}/${environment}${region_code}${network_logical_name}" + system_config_information="${automation_config_directory}/${environment}${region_code}${network_logical_name}" fi if [ "${deployment_system}" == sap_system ]; then - load_config_vars "$parameterfile_name" "network_logical_name" - network_logical_name=$(echo "${network_logical_name}" | tr "[:lower:]" "[:upper:]" | tr -d ' \r\n') + load_config_vars "$parameterfile_name" "network_logical_name" + network_logical_name=$(echo "${network_logical_name}" | tr "[:lower:]" "[:upper:]" | tr -d ' \r\n') - system_config_information="${automation_config_directory}/${environment}${region_code}${network_logical_name}" + system_config_information="${automation_config_directory}/${environment}${region_code}${network_logical_name}" fi +load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" + +load_config_vars "${system_config_information}" "keyvault" +TF_VAR_deployer_kv_user_arm_id=$(az resource list --name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --resource-type Microsoft.KeyVault/vaults --query "[].id | [0]" -o tsv) +export TF_VAR_spn_keyvault_id="${TF_VAR_deployer_kv_user_arm_id}" + echo "Configuration file: $system_config_information" echo "Deployment region: $region" echo "Deployment region code: $region_code" +echo "Working_directory: $working_directory" key=$(echo "${parameterfile_name}" | cut -d. -f1) if [ -f terraform.tfvars ]; then - extra_vars="-var-file=${param_dirname}/terraform.tfvars" + extra_vars="-var-file=${param_dirname}/terraform.tfvars" else - unset extra_vars + unset extra_vars fi echo "" @@ -251,31 +270,33 @@ echo "Target subscription: ${ARM_SUBSCRIPTION_ID}" echo "Deployer State file: ${deployer_tfstate_key}" echo "Landscape State file: ${landscape_tfstate_key}" + +export TF_VAR_subscription_id="${ARM_SUBSCRIPTION_ID}" # Terraform Plugins if checkIfCloudShell; then - mkdir -p "${HOME}/.terraform.d/plugin-cache" - export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" + mkdir -p "${HOME}/.terraform.d/plugin-cache" + export TF_PLUGIN_CACHE_DIR="${HOME}/.terraform.d/plugin-cache" else - if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then - mkdir -p /opt/terraform/.terraform.d/plugin-cache - sudo chown -R "$USER" /opt/terraform - fi - export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache + if [ ! -d /opt/terraform/.terraform.d/plugin-cache ]; then + sudo mkdir -p /opt/terraform/.terraform.d/plugin-cache + sudo chown -R "$USER" /opt/terraform + fi + export TF_PLUGIN_CACHE_DIR=/opt/terraform/.terraform.d/plugin-cache fi init "${automation_config_directory}" "${generic_config_information}" "${system_config_information}" var_file="${parameterfile_dirname}"/"${parameterfile}" if [ -z "$REMOTE_STATE_SA" ]; then - load_config_vars "${system_config_information}" "REMOTE_STATE_SA" - load_config_vars "${system_config_information}" "REMOTE_STATE_RG" - load_config_vars "${system_config_information}" "tfstate_resource_id" - load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${system_config_information}" "REMOTE_STATE_SA" + load_config_vars "${system_config_information}" "REMOTE_STATE_RG" + load_config_vars "${system_config_information}" "tfstate_resource_id" + load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" else - save_config_vars "${system_config_information}" REMOTE_STATE_SA - getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" - load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" - load_config_vars "${system_config_information}" "REMOTE_STATE_RG" - load_config_vars "${system_config_information}" "tfstate_resource_id" + save_config_vars "${system_config_information}" REMOTE_STATE_SA + getAndStoreTerraformStateStorageAccountDetails "${REMOTE_STATE_SA}" "${system_config_information}" + load_config_vars "${system_config_information}" "STATE_SUBSCRIPTION" + load_config_vars "${system_config_information}" "REMOTE_STATE_RG" + load_config_vars "${system_config_information}" "tfstate_resource_id" fi load_config_vars "${system_config_information}" "deployer_tfstate_key" @@ -284,12 +305,12 @@ load_config_vars "${system_config_information}" "ARM_SUBSCRIPTION_ID" deployer_tfstate_key_parameter='' if [ "${deployment_system}" != sap_deployer ]; then - deployer_tfstate_key_parameter=" -var deployer_tfstate_key=${deployer_tfstate_key} " + deployer_tfstate_key_parameter=" -var deployer_tfstate_key=${deployer_tfstate_key} " fi landscape_tfstate_key_parameter='' if [ "${deployment_system}" == sap_system ]; then - landscape_tfstate_key_parameter=" -var landscape_tfstate_key=${landscape_tfstate_key} " + landscape_tfstate_key_parameter=" -var landscape_tfstate_key=${landscape_tfstate_key} " fi tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id} " @@ -298,7 +319,7 @@ tfstate_parameter=" -var tfstate_resource_id=${tfstate_resource_id} " set_executing_user_environment_variables "none" if [ -n "${STATE_SUBSCRIPTION}" ]; then - az account set --sub "${STATE_SUBSCRIPTION}" + az account set --sub "${STATE_SUBSCRIPTION}" fi export TF_DATA_DIR="${parameterfile_dirname}"/.terraform @@ -306,40 +327,43 @@ export TF_DATA_DIR="${parameterfile_dirname}"/.terraform terraform_module_directory="${SAP_AUTOMATION_REPO_PATH}"/deploy/terraform/run/"${deployment_system}"/ if [ ! -d "${terraform_module_directory}" ]; then - printf -v val %-40.40s "$deployment_system" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Incorrect system deployment type specified: ${val} $reset_formatting#" - echo "# #" - echo "# Valid options are: #" - echo "# sap_deployer #" - echo "# sap_library #" - echo "# sap_landscape #" - echo "# sap_system #" - echo "# #" - echo "#########################################################################################" - echo "" - exit 66 #cannot open input file/folder + printf -v val %-40.40s "$deployment_system" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Incorrect system deployment type specified: ${val} $reset_formatting#" + echo "# #" + echo "# Valid options are: #" + echo "# sap_deployer #" + echo "# sap_library #" + echo "# sap_landscape #" + echo "# sap_system #" + echo "# #" + echo "#########################################################################################" + echo "" + exit 66 #cannot open input file/folder fi #ok_to_proceed=false #new_deployment=false if [ -f backend.tf ]; then - rm backend.tf + rm backend.tf fi -useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --query allowSharedKeyAccess --subscription "${STATE_SUBSCRIPTION}" --out tsv) - -if [ "$useSAS" = "true" ]; then - echo "Storage Account Authentication: Key" - export ARM_USE_AZUREAD=false -else - echo "Storage Account Authentication: Entra ID" +if [ -n "${REMOTE_STATE_SA}" ]; then + useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --query allowSharedKeyAccess --subscription "${STATE_SUBSCRIPTION}" --out tsv) - export ARM_USE_AZUREAD=true + if [ "$useSAS" = "true" ]; then + echo "Storage Account Authentication: Key" + export ARM_USE_AZUREAD=false + else + echo "Storage Account Authentication: Entra ID" + export ARM_USE_AZUREAD=true + fi fi +cd "${param_dirname}" || exit +pwd echo "" echo "#########################################################################################" echo "# #" @@ -348,15 +372,54 @@ echo "# echo "#########################################################################################" echo "" -terraform -chdir="${terraform_module_directory}" init -reconfigure \ - --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ - --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ - --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ - --backend-config "container_name=tfstate" \ - --backend-config "key=${key}.terraform.tfstate" || { - echo "Terraform init failed" - exit 1 -} +if [ -f .terraform/terraform.tfstate ]; then + + azure_backend=$(grep "\"type\": \"azurerm\"" .terraform/terraform.tfstate || true) + if [ -n "${azure_backend}" ]; then + if terraform -chdir="${terraform_module_directory}" init -upgrade=true; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + exit 1 + fi + else + if terraform -chdir="${terraform_module_directory}" init -reconfigure \ + --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ + --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ + --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + exit 1 + fi + fi +else + if terraform -chdir="${terraform_module_directory}" init -reconfigure \ + --backend-config "subscription_id=${STATE_SUBSCRIPTION}" \ + --backend-config "resource_group_name=${REMOTE_STATE_RG}" \ + --backend-config "storage_account_name=${REMOTE_STATE_SA}" \ + --backend-config "container_name=tfstate" \ + --backend-config "key=${key}.terraform.tfstate"; then + echo "" + echo -e "${cyan}Terraform init: succeeded$reset_formatting" + echo "" + else + echo "" + echo -e "${bold_red}Terraform init: failed$reset_formatting" + echo "" + exit 1 + fi +fi tfstate_resource_id=$(az storage account show --name "${REMOTE_STATE_SA}" --query id --subscription "${STATE_SUBSCRIPTION}" --out tsv) export TF_VAR_tfstate_resource_id="${tfstate_resource_id}" @@ -367,130 +430,215 @@ created_resource_group_subscription_id=$(terraform -chdir="${terraform_module_di created_resource_group_subscription_id_length="${#created_resource_group_subscription_id}" if [ "${created_resource_group_id_length}" -eq 0 ] && [ "${created_resource_group_subscription_id_length}" -eq 0 ]; then - resource_group_exist=$(az group exists --name "${created_resource_group_id}" --subscription "${created_resource_group_subscription_id}") + resource_group_exist=$(az group exists --name "${created_resource_group_id}" --subscription "${created_resource_group_subscription_id}") else - resource_group_exist=true + resource_group_exist=true fi if [ "$resource_group_exist" ]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $cyan Running Terraform destroy$reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - - if [ "$deployment_system" == "sap_deployer" ]; then - terraform -chdir="${terraform_bootstrap_directory}" refresh -var-file="${var_file}" \ - "$deployer_tfstate_key_parameter" - - echo -e "#$cyan processing $deployment_system removal as defined in $parameterfile_name $reset_formatting" - terraform -chdir="${terraform_module_directory}" destroy -var-file="${var_file}" \ - "$deployer_tfstate_key_parameter" - - elif [ "$deployment_system" == "sap_library" ]; then - echo -e "#$cyan processing $deployment_system removal as defined in $parameterfile_name $reset_formatting" - - terraform_bootstrap_directory="${SAP_AUTOMATION_REPO_PATH}/deploy/terraform/bootstrap/${deployment_system}/" - if [ ! -d "${terraform_bootstrap_directory}" ]; then - printf -v val %-40.40s "$terraform_bootstrap_directory" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Unable to find bootstrap directory: ${val}$reset_formatting#" - echo "# #" - echo "#########################################################################################" - echo "" - exit 66 #cannot open input file/folder - fi - terraform -chdir="${terraform_bootstrap_directory}" init -upgrade=true -force-copy - - terraform -chdir="${terraform_bootstrap_directory}" refresh -var-file="${var_file}" \ - "$landscape_tfstate_key_parameter" \ - "$deployer_tfstate_key_parameter" - - terraform -chdir="${terraform_bootstrap_directory}" destroy -var-file="${var_file}" "${approve}" \ - "$landscape_tfstate_key_parameter" \ - "$deployer_tfstate_key_parameter" - else - - echo -e "#$cyan processing $deployment_system removal as defined in $parameterfile_name $reset_formatting" - echo "Calling destroy with: -var-file=${var_file} $approve $tfstate_parameter $landscape_tfstate_key_parameter $deployer_tfstate_key_parameter" - - allParameters=$(printf " -var-file=%s %s %s %s %s " "${var_file}" "${extra_vars}" "${tfstate_parameter}" "${landscape_tfstate_key_parameter}" "${deployer_tfstate_key_parameter}") - - if [ -n "${approve}" ]; then - # shellcheck disable=SC2086 - terraform -chdir="${terraform_module_directory}" destroy $allParameters "$approve" -no-color -json | tee -a destroy_output.json - else - # shellcheck disable=SC2086 - terraform -chdir="${terraform_module_directory}" destroy $allParameters - - fi - - return_value=$? - - if [ -f destroy_output.json ]; then - errors_occurred=$(jq 'select(."@level" == "error") | length' destroy_output.json) - - if [[ -n $errors_occurred ]]; then - echo "" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red_underscore!Errors during the destroy phase!$reset_formatting #" - - return_value=2 - all_errors=$(jq 'select(."@level" == "error") | {summary: .diagnostic.summary, detail: .diagnostic.detail}' destroy_output.json) - if [[ -n ${all_errors} ]]; then - readarray -t errors_strings < <(echo ${all_errors} | jq -c '.') - for errors_string in "${errors_strings[@]}"; do - string_to_report=$(jq -c -r '.detail ' <<<"$errors_string") - if [[ -z ${string_to_report} ]]; then - string_to_report=$(jq -c -r '.summary ' <<<"$errors_string") - fi - - report=$(echo $string_to_report | grep -m1 "Message=" "${var_file}" | cut -d'=' -f2- | tr -d ' ' | tr -d '"') - if [[ -n ${report} ]]; then - echo -e "# $bold_red_underscore $report $reset_formatting" - echo "##vso[task.logissue type=error]${report}" - else - echo -e "# $bold_red_underscore $string_to_report $reset_formatting" - echo "##vso[task.logissue type=error]${string_to_report}" - fi - - done - - fi - echo "# #" - echo "#########################################################################################" - echo "" - - fi - - fi - - if [ -f destroy_output.json ]; then - rm destroy_output.json - fi - - fi + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $cyan Running Terraform destroy$reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + if [ "$deployment_system" == "sap_deployer" ]; then + terraform -chdir="${terraform_bootstrap_directory}" refresh -var-file="${var_file}" \ + "$deployer_tfstate_key_parameter" + + echo -e "#$cyan processing $deployment_system removal as defined in $parameterfile_name $reset_formatting" + terraform -chdir="${terraform_module_directory}" destroy -var-file="${var_file}" \ + "$deployer_tfstate_key_parameter" + + elif [ "$deployment_system" == "sap_library" ]; then + echo -e "#$cyan processing $deployment_system removal as defined in $parameterfile_name $reset_formatting" + + terraform_bootstrap_directory="${SAP_AUTOMATION_REPO_PATH}/deploy/terraform/bootstrap/${deployment_system}/" + if [ ! -d "${terraform_bootstrap_directory}" ]; then + printf -v val %-40.40s "$terraform_bootstrap_directory" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red Unable to find bootstrap directory: ${val}$reset_formatting#" + echo "# #" + echo "#########################################################################################" + echo "" + exit 66 #cannot open input file/folder + fi + terraform -chdir="${terraform_bootstrap_directory}" init -upgrade=true -force-copy + + terraform -chdir="${terraform_bootstrap_directory}" refresh -var-file="${var_file}" \ + "$deployer_tfstate_key_parameter" + + terraform -chdir="${terraform_bootstrap_directory}" destroy -var-file="${var_file}" "${approve}" -var use_deployer=false \ + "$deployer_tfstate_key_parameter" + elif [ "$deployment_system" == "sap_landscape" ]; then + + echo -e "#$cyan processing $deployment_system removal as defined in $parameterfile_name $reset_formatting" + echo "Calling destroy with: -var-file=${var_file} $approve $tfstate_parameter deployer_tfstate_key_parameter" + + allParameters=$(printf " -var-file=%s %s %s %s " "${var_file}" "${extra_vars}" "${tfstate_parameter}" "${deployer_tfstate_key_parameter}") + + moduleID="module.sap_landscape.azurerm_key_vault_secret.sid_ppk" + if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then + echo "Secret 'sid_ppk' removed from state" + fi + moduleID="module.sap_landscape.azurerm_key_vault_secret.sid_pk" + if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then + echo "Secret 'sid_pk' removed from state" + fi + moduleID="module.sap_landscape.azurerm_key_vault_secret.sid_username" + if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then + echo "Secret 'sid_username' removed from state" + fi + moduleID="module.sap_landscape.azurerm_key_vault_secret.sid_password" + if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then + echo "Secret 'sid_password' removed from state" + fi + moduleID="module.sap_landscape.azurerm_key_vault_secret.witness_access_key" + if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then + echo "Secret 'witness_access_key' removed from state" + fi + moduleID="module.sap_landscape.azurerm_key_vault_secret.deployer_keyvault_user_name" + if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then + echo "Secret 'deployer_keyvault_user_name' removed from state" + fi + moduleID="module.sap_landscape.azurerm_key_vault_secret.witness_name" + if terraform -chdir="${terraform_module_directory}" state rm "${moduleID}"; then + echo "Secret 'witness_name' removed from state" + fi + + if [ -n "${approve}" ]; then + # shellcheck disable=SC2086 + if terraform -chdir="${terraform_module_directory}" destroy $allParameters "$approve" -no-color -json -parallelism="$parallelism" | tee -a destroy_output.json; then + return_value=$? + echo "" + echo -e "${cyan}Terraform destroy: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform destroy: failed$reset_formatting" + echo "" + exit 1 + fi + else + # shellcheck disable=SC2086 + if terraform -chdir="${terraform_module_directory}" destroy $allParameters -parallelism="$parallelism"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform destroy: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform destroy: failed$reset_formatting" + echo "" + exit 1 + fi + fi + else + + echo -e "#$cyan processing $deployment_system removal as defined in $parameterfile_name $reset_formatting" + echo "Calling destroy with: -var-file=${var_file} $approve $tfstate_parameter $landscape_tfstate_key_parameter $deployer_tfstate_key_parameter" + + allParameters=$(printf " -var-file=%s %s %s %s %s " "${var_file}" "${extra_vars}" "${tfstate_parameter}" "${landscape_tfstate_key_parameter}" "${deployer_tfstate_key_parameter}") + + if [ -n "${approve}" ]; then + # shellcheck disable=SC2086 + if terraform -chdir="${terraform_module_directory}" destroy $allParameters "$approve" -no-color -json -parallelism="$parallelism" | tee -a destroy_output.json; then + return_value=$? + echo "" + echo -e "${cyan}Terraform destroy: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform destroy: failed$reset_formatting" + echo "" + exit 1 + fi + else + # shellcheck disable=SC2086 + if terraform -chdir="${terraform_module_directory}" destroy $allParameters -parallelism="$parallelism"; then + return_value=$? + echo "" + echo -e "${cyan}Terraform destroy: succeeded$reset_formatting" + echo "" + else + return_value=$? + echo "" + echo -e "${bold_red}Terraform destroy: failed$reset_formatting" + echo "" + exit 1 + fi + + fi + + return_value=$? + + if [ -f destroy_output.json ]; then + errors_occurred=$(jq 'select(."@level" == "error") | length' destroy_output.json) + + if [[ -n $errors_occurred ]]; then + echo "" + echo "#########################################################################################" + echo "# #" + echo -e "# $bold_red_underscore!Errors during the destroy phase!$reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "" + + return_value=2 + all_errors=$(jq 'select(."@level" == "error") | {summary: .diagnostic.summary, detail: .diagnostic.detail}' destroy_output.json) + if [[ -n ${all_errors} ]]; then + readarray -t errors_strings < <(echo ${all_errors} | jq -c '.') + for errors_string in "${errors_strings[@]}"; do + string_to_report=$(jq -c -r '.detail ' <<<"$errors_string") + if [[ -z ${string_to_report} ]]; then + string_to_report=$(jq -c -r '.summary ' <<<"$errors_string") + fi + + report=$(echo $string_to_report | grep -m1 "Message=" "${var_file}" | cut -d'=' -f2- | tr -d ' ' | tr -d '"') + if [[ -n ${report} ]]; then + echo -e "# $bold_red_underscore $report $reset_formatting" + echo "##vso[task.logissue type=error]${report}" + else + echo -e "# $bold_red_underscore $string_to_report $reset_formatting" + echo "##vso[task.logissue type=error]${string_to_report}" + fi + + done + + fi + + fi + + fi + + if [ -f destroy_output.json ]; then + rm destroy_output.json + fi + + fi else - return_value=0 + return_value=0 fi if [ "${deployment_system}" == sap_deployer ]; then - sed -i /deployer_tfstate_key/d "${system_config_information}" + sed -i /deployer_tfstate_key/d "${system_config_information}" fi if [ "${deployment_system}" == sap_landscape ]; then - rm "${system_config_information}" + rm "${system_config_information}" fi if [ "${deployment_system}" == sap_library ]; then - sed -i /REMOTE_STATE_RG/d "${system_config_information}" - sed -i /REMOTE_STATE_SA/d "${system_config_information}" - sed -i /tfstate_resource_id/d "${system_config_information}" + sed -i /REMOTE_STATE_RG/d "${system_config_information}" + sed -i /REMOTE_STATE_SA/d "${system_config_information}" + sed -i /tfstate_resource_id/d "${system_config_information}" fi # if [ "${deployment_system}" == sap_system ]; then diff --git a/deploy/scripts/set_secrets.sh b/deploy/scripts/set_secrets.sh index d78cb39aa5..0f8ddef746 100755 --- a/deploy/scripts/set_secrets.sh +++ b/deploy/scripts/set_secrets.sh @@ -17,36 +17,57 @@ script_directory="$(dirname "${full_script_path}")" # shellcheck disable=SC1091 source "${script_directory}/deploy_utils.sh" +function setSecretValue { + local keyvault=$1 + local subscription=$2 + local secret_name=$3 + local value=$4 + if az keyvault secret set --name "${secret_name}" --vault-name "${keyvault}" --subscription "${subscription}" --value "${value}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --output none; then + return_value=$? + else + return_value=$? + if [ 1 = "${return_value}" ]; then + az keyvault secret recover --name "${secret_name}" --vault-name "${keyvault}" --subscription "${subscription}" + sleep 10 + az keyvault secret set --name "${secret_name}" --vault-name "${keyvault}" --subscription "${subscription}" --value "${value}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --output none + else + echo "Failed to set secret ${secret_name} in keyvault ${keyvault}" + fi + fi + return $return_value + +} + function showhelp { - echo "" - echo "#########################################################################################" - echo "# #" - echo "# #" - echo "# This file contains the logic to add the SPN secrets to the keyvault. #" - echo "# #" - echo "# #" - echo "# Usage: set_secret.sh #" - echo "# -e or --environment environment name #" - echo "# -r or --region region name #" - echo "# -v or --vault Azure keyvault name #" - echo "# -s or --subscription subscription #" - echo "# -c or --spn_id SPN application id #" - echo "# -p or --spn_secret SPN password #" - echo "# -t or --tenant_id SPN Tenant id #" - echo "# -h or --help Show help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/set_secret.sh \ #" - echo "# --environment PROD \ #" - echo "# --region weeu \ #" - echo "# --vault prodweeuusrabc \ #" - echo "# --subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ #" - echo "# --spn_id yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy \ #" - echo "# --spn_secret ************************ \ #" - echo "# --tenant_id zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz \ #" - echo "# #" - echo "#########################################################################################" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# #" + echo "# This file contains the logic to add the SPN secrets to the keyvault. #" + echo "# #" + echo "# #" + echo "# Usage: set_secret.sh #" + echo "# -e or --environment environment name #" + echo "# -r or --region region name #" + echo "# -v or --vault Azure keyvault name #" + echo "# -s or --subscription subscription #" + echo "# -c or --spn_id SPN application id #" + echo "# -p or --spn_secret SPN password #" + echo "# -t or --tenant_id SPN Tenant id #" + echo "# -h or --help Show help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/set_secret.sh \ #" + echo "# --environment PROD \ #" + echo "# --region weeu \ #" + echo "# --vault prodweeuusrabc \ #" + echo "# --subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ #" + echo "# --spn_id yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy \ #" + echo "# --spn_secret ************************ \ #" + echo "# --tenant_id zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz \ #" + echo "# #" + echo "#########################################################################################" } deploy_using_msi_only=0 @@ -55,79 +76,79 @@ INPUT_ARGUMENTS=$(getopt -n set_secrets -o e:r:v:s:c:p:t:b:hwm --longoptions env VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp + showhelp fi eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -e | --environment) - environment="$2" - shift 2 - ;; - -r | --region) - region_code="$2" - shift 2 - ;; - -v | --vault) - keyvault="$2" - shift 2 - ;; - -s | --subscription) - subscription="$2" - shift 2 - ;; - -c | --spn_id) - client_id="$2" - shift 2 - ;; - -p | --spn_secret) - client_secret="$2" - shift 2 - ;; - -t | --tenant_id) - tenant_id="$2" - shift 2 - ;; - -b | --keyvault_subscription) - STATE_SUBSCRIPTION="$2" - shift 2 - ;; - -w | --workload) - workload=1 - shift - ;; - -m | --msi) - deploy_using_msi_only=1 - shift - ;; - -h | --help) - showhelp - exit 3 - - ;; - --) - shift - break - ;; - esac + case "$1" in + -e | --environment) + environment="$2" + shift 2 + ;; + -r | --region) + region_code="$2" + shift 2 + ;; + -v | --vault) + keyvault="$2" + shift 2 + ;; + -s | --subscription) + subscription="$2" + shift 2 + ;; + -c | --spn_id) + client_id="$2" + shift 2 + ;; + -p | --spn_secret) + client_secret="$2" + shift 2 + ;; + -t | --tenant_id) + tenant_id="$2" + shift 2 + ;; + -b | --keyvault_subscription) + STATE_SUBSCRIPTION="$2" + shift 2 + ;; + -w | --workload) + workload=1 + shift + ;; + -m | --msi) + deploy_using_msi_only=1 + shift + ;; + -h | --help) + showhelp + exit 3 + + ;; + --) + shift + break + ;; + esac done if [ "$DEBUG" = True ]; then - set -x + set -x fi while [ -z "${environment}" ]; do - read -r -p "Environment name: " environment + read -r -p "Environment name: " environment done while [ -z "${region_code}" ]; do - read -r -p "Region name: " region + read -r -p "Region name: " region done if [ -z "${region_code}" ]; then - # Convert the region to the correct code - get_region_code "$region" + # Convert the region to the correct code + get_region_code "$region" fi # if ! valid_environment "${environment}"; then @@ -147,146 +168,146 @@ environment_config_information="${automation_config_directory}/${environment}${r return_code=0 if [ -f secret.err ]; then - rm secret.err + rm secret.err fi if [ ! -d "${automation_config_directory}" ]; then - # No configuration directory exists - mkdir "${automation_config_directory}" + # No configuration directory exists + mkdir "${automation_config_directory}" else - touch "${environment_config_information}" + touch "${environment_config_information}" fi if [ -z "$subscription" ]; then - load_config_vars "${environment_config_information}" "subscription" + load_config_vars "${environment_config_information}" "subscription" fi if [ "$workload" != 1 ]; then - load_config_vars "${environment_config_information}" "STATE_SUBSCRIPTION" - if [ "$STATE_SUBSCRIPTION" ]; then - subscription=${STATE_SUBSCRIPTION} - fi + load_config_vars "${environment_config_information}" "STATE_SUBSCRIPTION" + if [ "$STATE_SUBSCRIPTION" ]; then + subscription=${STATE_SUBSCRIPTION} + fi fi if [ -z "$keyvault" ]; then - load_config_vars "${environment_config_information}" "keyvault" - if [ -z "$keyvault" ]; then - read -r -p "Keyvault name: " keyvault - fi - if valid_kv_name "$keyvault"; then - echo "Valid keyvault name format specified" - else - printf -v val %-40.40s "$keyvault" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided keyvault is not valid:$bold_red ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "The provided keyvault is not valid " "${val}" >secret.err - return_code=65 - exit $return_code - fi + load_config_vars "${environment_config_information}" "keyvault" + if [ -z "$keyvault" ]; then + read -r -p "Keyvault name: " keyvault + fi + if valid_kv_name "$keyvault"; then + echo "Valid keyvault name format specified" + else + printf -v val %-40.40s "$keyvault" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided keyvault is not valid:$bold_red ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + echo "The provided keyvault is not valid " "${val}" >secret.err + return_code=65 + exit $return_code + fi fi if [ -z "${keyvault}" ]; then - echo "Missing keyvault" - echo "No keyvault specified" >secret.err - showhelp - return_code=65 #/* data format error */ - echo $return_code - exit $return_code + echo "Missing keyvault" + echo "No keyvault specified" >secret.err + showhelp + return_code=65 #/* data format error */ + echo $return_code + exit $return_code fi if [ 0 = "${deploy_using_msi_only:-}" ]; then - if [ -z "${client_id}" ]; then - load_config_vars "${environment_config_information}" "client_id" - if [ -z "$client_id" ]; then - read -r -p "SPN App ID: " client_id - fi - else - if is_valid_guid "${client_id}"; then - echo "" - else - printf -v val %-40.40s "$client_id" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided client_id is not valid:$bold_red ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - return_code=65 - echo "The provided client_id is not valid " "${val}" >secret.err - exit $return_code - fi - fi - - if [ -z "$client_secret" ]; then - #do not output the secret to screen - read -rs -p " -> Kindly provide SPN Password: " client_secret - echo "********" - fi - - if [ -z "${tenant_id}" ]; then - load_config_vars "${environment_config_information}" "tenant_id" - if [ -z "${tenant_id}" ]; then - read -r -p "SPN Tenant ID: " tenant_id - fi - else - if is_valid_guid "${tenant_id}"; then - echo "" - else - printf -v val %-40.40s "$tenant_id" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided tenant_id is not valid:$bold_red ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - return_code=65 - echo "The provided tenant_id is not valid " "${val}" >secret.err - exit $return_code - fi - fi - if [ -z "${client_id}" ]; then - echo "Missing client_id" - echo "No client_id specified" >secret.err - showhelp - return_code=65 #/* data format error */ - echo $return_code - exit $return_code - fi - - if [ -z "$client_secret" ]; then - echo "Missing client_secret" - echo "No client_secret specified" >secret.err - showhelp - return_code=65 #/* data format error */ - echo $return_code - exit $return_code - fi - - if [ -z "${tenant_id}" ]; then - echo "Missing tenant_id" - echo "No tenant_id specified" >secret.err - showhelp - return_code=65 #/* data format error */ - echo $return_code - exit $return_code - fi + if [ -z "${client_id}" ]; then + load_config_vars "${environment_config_information}" "client_id" + if [ -z "$client_id" ]; then + read -r -p "SPN App ID: " client_id + fi + else + if is_valid_guid "${client_id}"; then + echo "" + else + printf -v val %-40.40s "$client_id" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided client_id is not valid:$bold_red ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + return_code=65 + echo "The provided client_id is not valid " "${val}" >secret.err + exit $return_code + fi + fi + + if [ -z "$client_secret" ]; then + #do not output the secret to screen + read -rs -p " -> Kindly provide SPN Password: " client_secret + echo "********" + fi + + if [ -z "${tenant_id}" ]; then + load_config_vars "${environment_config_information}" "tenant_id" + if [ -z "${tenant_id}" ]; then + read -r -p "SPN Tenant ID: " tenant_id + fi + else + if is_valid_guid "${tenant_id}"; then + echo "" + else + printf -v val %-40.40s "$tenant_id" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided tenant_id is not valid:$bold_red ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + return_code=65 + echo "The provided tenant_id is not valid " "${val}" >secret.err + exit $return_code + fi + fi + if [ -z "${client_id}" ]; then + echo "Missing client_id" + echo "No client_id specified" >secret.err + showhelp + return_code=65 #/* data format error */ + echo $return_code + exit $return_code + fi + + if [ -z "$client_secret" ]; then + echo "Missing client_secret" + echo "No client_secret specified" >secret.err + showhelp + return_code=65 #/* data format error */ + echo $return_code + exit $return_code + fi + + if [ -z "${tenant_id}" ]; then + echo "Missing tenant_id" + echo "No tenant_id specified" >secret.err + showhelp + return_code=65 #/* data format error */ + echo $return_code + exit $return_code + fi fi if [ -z "${subscription}" ]; then - read -r -p "SPN Subscription: " subscription + read -r -p "SPN Subscription: " subscription else - if is_valid_guid "${subscription}"; then - echo "" - else - printf -v val %-40.40s "${subscription}" - echo "#########################################################################################" - echo "# #" - echo -e "# The provided subscription is not valid:$bold_red ${val} $reset_formatting #" - echo "# #" - echo "#########################################################################################" - return_code=65 #/* data format error */ - echo "The provided subscription is not valid " "${val}" >secret.err - exit $return_code - fi + if is_valid_guid "${subscription}"; then + echo "" + else + printf -v val %-40.40s "${subscription}" + echo "#########################################################################################" + echo "# #" + echo -e "# The provided subscription is not valid:$bold_red ${val} $reset_formatting #" + echo "# #" + echo "#########################################################################################" + return_code=65 #/* data format error */ + echo "The provided subscription is not valid " "${val}" >secret.err + exit $return_code + fi fi echo "#########################################################################################" @@ -300,136 +321,53 @@ echo "Key vault: ${keyvault}" echo "Subscription: ${STATE_SUBSCRIPTION}" save_config_vars "${environment_config_information}" \ - keyvault \ - environment \ - subscription \ - client_id \ - tenant_id \ - STATE_SUBSCRIPTION + keyvault \ + environment \ + subscription \ + client_id \ + tenant_id \ + STATE_SUBSCRIPTION -secretname="${environment}"-subscription-id +secret_name="${environment}"-subscription-id -# az keyvault secret show --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" >stdout.az 2>&1 +# az keyvault secret show --name "${secret_name}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" >stdout.az 2>&1 # result=$(grep "ERROR: The user, group or application" stdout.az) # if [ -n "${result}" ]; then # upn=$(az account show | grep name | grep @ | cut -d: -f2 | cut -d, -f1 -o tsv | xargs) # az keyvault set-policy -n "${keyvault}" --secret-permissions get list recover restore set --upn "${upn}" # fi - -deleted=$(az keyvault secret list-deleted --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" -o tsv) -if [ "${deleted}" == "${secretname}" ]; then - echo -e "\t $cyan Recovering secret ${secretname} in keyvault ${keyvault} $reset_formatting \n" - az keyvault secret recover --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" - sleep 10 - v=$(az keyvault secret list --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query [].name | tee grep "${secretname}") - - if [ "${v}" != "${subscription}" ]; then - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value "${subscription}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --only-show-errors --output none - fi +if setSecretValue "${keyvault}" "${STATE_SUBSCRIPTION}" "${secret_name}" "${STATE_SUBSCRIPTION}"; then + echo "Secret ${secret_name} set in keyvault ${keyvault}" else - exists=$(az keyvault secret list --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" -o tsv) - if [ "${exists}" == "${secretname}" ]; then - v=$(az keyvault secret show --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query value -o tsv) - if [ "${v}" != "${subscription}" ]; then - echo -e "\t $cyan Setting secret ${secretname} in keyvault ${keyvault} $reset_formatting \n" - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value "${subscription}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" >stdout.az 2>&1 - fi - else - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value "${subscription}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" >stdout.az 2>&1 - fi + echo "Failed to set secret ${secret_name} in keyvault ${keyvault}" + exit 20 fi -if [ -f stdout.az ]; then - result=$(grep "ERROR: The user, group or application" stdout.az) - - if [ -n "${result}" ]; then - printf -v val "%-20.20s" "$keyvault" - echo "#########################################################################################" - echo "# #" - echo -e "# No access to add the secrets in the$bold_red" "${val}" "$reset_formatting keyvault #" - echo "# Please add an access policy for the account you use #" - echo "# #" - echo "#########################################################################################" - echo "" - rm stdout.az - echo "No access to add the secrets in the " "${val}" "keyvault" >secret.err - return_code=77 - exit $return_code - fi - - result=$(grep "The Vault may not exist" stdout.az) - if [ -n "${result}" ]; then - printf -v val "%-20.20s could not be found!" "$keyvault" - echo "#########################################################################################" - echo "# #" - echo -e "# $bold_red Keyvault" "${val}" "$reset_formatting #" - echo "# #" - echo "#########################################################################################" - echo "" - rm stdout.az - return_code=65 #/* name unknown */ - echo "Keyvault" "${val}" >secret.err - exit $return_code - - fi -fi if [ 0 = "${deploy_using_msi_only:-}" ]; then - #turn off output, we do not want to show the details being uploaded to keyvault - secretname="${environment}"-client-id - deleted=$(az keyvault secret list-deleted --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" -o tsv) - if [ "${deleted}" == "${secretname}" ]; then - echo -e "\t $cyan Recovering secret ${secretname} in keyvault ${keyvault} $reset_formatting \n" - az keyvault secret recover --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" - sleep 10 - fi - - v="" - secret=$(az keyvault secret list --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" -o tsv) - if [ "${secret}" == "${secretname}" ]; then - v=$(az keyvault secret show --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query value -o tsv) - if [ "${v}" != "${client_id}" ]; then - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value "${client_id}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --only-show-errors --output none - fi - else - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value "${client_id}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --only-show-errors --output none - fi - - secretname="${environment}"-tenant-id - deleted=$(az keyvault secret list-deleted --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" -o tsv) - if [ "${deleted}" == "${secretname}" ]; then - echo -e "\t $cyan Recovering secret ${secretname} in keyvault ${keyvault} $reset_formatting \n" - az keyvault secret recover --name "${secretname}" --vault-name "${keyvault}" --subscription "$STATE_SUBSCRIPTION" - sleep 10 - fi - v="" - secret=$(az keyvault secret list --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" -o tsv) - if [ "${secret}" == "${secretname}" ]; then - v=$(az keyvault secret show --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query value -o tsv) - if [ "${v}" != "${tenant_id}" ]; then - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value "${tenant_id}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --only-show-errors --output none - fi - else - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value "${tenant_id}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --only-show-errors --output none - fi - - secretname="${environment}"-client-secret - deleted=$(az keyvault secret list-deleted --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" -o tsv) - if [ "${deleted}" == "${secretname}" ]; then - echo -e "\t $cyan Recovering secret ${secretname} in keyvault ${keyvault} $reset_formatting \n" - az keyvault secret recover --name "${secretname}" --vault-name "${keyvault}" --subscription "$STATE_SUBSCRIPTION" - sleep 10 - fi - - v="" - secret=$(az keyvault secret list --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query "[].{Name:name} | [? contains(Name,'${secretname}')] | [0]" -o tsv) - if [ "${secret}" == "${secretname}" ]; then - v=$(az keyvault secret show --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --query value -o tsv) - if [ "${v}" != "${client_secret}" ]; then - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value="${client_secret}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --only-show-errors --output none - fi - else - az keyvault secret set --name "${secretname}" --vault-name "${keyvault}" --subscription "${STATE_SUBSCRIPTION}" --value="${client_secret}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --only-show-errors --output none - fi + + #turn off output, we do not want to show the details being uploaded to keyvault + secret_name="${environment}"-client-id + if setSecretValue "${keyvault}" "${STATE_SUBSCRIPTION}" "${secret_name}" "${client_id}"; then + echo "Secret ${secret_name} set in keyvault ${keyvault}" + else + echo "Failed to set secret ${secret_name} in keyvault ${keyvault}" + exit 20 + fi + + secret_name="${environment}"-tenant-id + if setSecretValue "${keyvault}" "${STATE_SUBSCRIPTION}" "${secret_name}" "${tenant_id}"; then + echo "Secret ${secret_name} set in keyvault ${keyvault}" + else + echo "Failed to set secret ${secret_name} in keyvault ${keyvault}" + exit 20 + fi + secret_name="${environment}"-client-secret + if setSecretValue "${keyvault}" "${STATE_SUBSCRIPTION}" "${secret_name}" "${client_secret}"; then + echo "Secret ${secret_name} set in keyvault ${keyvault}" + else + echo "Failed to set secret ${secret_name} in keyvault ${keyvault}" + exit 20 + fi fi exit $return_code diff --git a/deploy/scripts/setup_devops.ps1 b/deploy/scripts/setup_devops.ps1 index 24dca5349a..476d0ff402 100644 --- a/deploy/scripts/setup_devops.ps1 +++ b/deploy/scripts/setup_devops.ps1 @@ -482,7 +482,7 @@ Write-Host "Creating the variable group SDAF-General" -ForegroundColor Green $general_group_id = (az pipelines variable-group list --query "[?name=='SDAF-General'].id | [0]" --only-show-errors) if ($general_group_id.Length -eq 0) { - az pipelines variable-group create --name SDAF-General --variables ANSIBLE_HOST_KEY_CHECKING=false Deployment_Configuration_Path=WORKSPACES Branch=main tf_version="1.7.0" ansible_core_version="2.15" S-Username=$SUserName S-Password=$SPassword --output yaml --authorize true --output none + az pipelines variable-group create --name SDAF-General --variables ANSIBLE_HOST_KEY_CHECKING=false Deployment_Configuration_Path=WORKSPACES Branch=main tf_version="1.10.1" ansible_core_version="2.16" S-Username=$SUserName S-Password=$SPassword --output yaml --authorize true --output none $general_group_id = (az pipelines variable-group list --query "[?name=='SDAF-General'].id | [0]" --only-show-errors) az pipelines variable-group variable update --group-id $general_group_id --name "S-Password" --value $SPassword --secret true --output none --only-show-errors diff --git a/deploy/scripts/sync_deployer.sh b/deploy/scripts/sync_deployer.sh index 4b7b4fd248..43a7292ec0 100755 --- a/deploy/scripts/sync_deployer.sh +++ b/deploy/scripts/sync_deployer.sh @@ -17,72 +17,71 @@ script_directory="$(dirname "${full_script_path}")" source "${script_directory}/deploy_utils.sh" function showhelp { - echo "" - echo "#########################################################################################" - echo "# #" - echo "# #" - echo "# Usage: sync_deployer.sh #" - echo "# -o or --storageaccountname Storage account name for state file #" - echo "# -s or --state_subscription Subscription for tfstate storage account #" - echo "# -h or --help Show help #" - echo "# #" - echo "# Example: #" - echo "# #" - echo "# [REPO-ROOT]deploy/scripts/sync_deployer.sh \ #" - echo "# --storageaccountname mgmtweeutfstate### \ #" - echo "# --state_subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx #" - echo "# #" - echo "#########################################################################################" + echo "" + echo "#########################################################################################" + echo "# #" + echo "# #" + echo "# Usage: sync_deployer.sh #" + echo "# -o or --storageaccountname Storage account name for state file #" + echo "# -s or --state_subscription Subscription for tfstate storage account #" + echo "# -h or --help Show help #" + echo "# #" + echo "# Example: #" + echo "# #" + echo "# [REPO-ROOT]deploy/scripts/sync_deployer.sh \ #" + echo "# --storageaccountname mgmtweeutfstate### \ #" + echo "# --state_subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx #" + echo "# #" + echo "#########################################################################################" } INPUT_ARGUMENTS=$(getopt -n sync_deployer -o o:s:h --longoptions storageaccountname:,state_subscription:,help -- "$@") VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then - showhelp + showhelp fi eval set -- "$INPUT_ARGUMENTS" while :; do - case "$1" in - -k | --state_subscription) - STATE_SUBSCRIPTION="$2" - shift 2 - ;; - -o | --storageaccountname) - REMOTE_STATE_SA="$2" - shift 2 - ;; - -h | --help) - showhelp - exit 3 - shift - ;; - --) - shift - break - ;; - esac + case "$1" in + -k | --state_subscription) + STATE_SUBSCRIPTION="$2" + shift 2 + ;; + -o | --storageaccountname) + REMOTE_STATE_SA="$2" + shift 2 + ;; + -h | --help) + showhelp + exit 3 + shift + ;; + --) + shift + break + ;; + esac done -useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --query allowSharedKeyAccess --out tsv) +useSAS=$(az storage account show --name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --query allowSharedKeyAccess --out tsv) -if [ $useSAS = "true" ] ; then - files=$(az storage blob list --container-name tfvars --account-name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --query "[].name" -o tsv --only-show-errors --output tsv) +if [ $useSAS = "true" ]; then + files=$(az storage blob list --container-name tfvars --account-name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --query "[].name" -o tsv --only-show-errors --output tsv) else - files=$(az storage blob list --container-name tfvars --account-name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --auth-mode login --query "[].name" -o tsv --only-show-errors --output tsv) + files=$(az storage blob list --container-name tfvars --account-name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --auth-mode login --query "[].name" -o tsv --only-show-errors --output tsv) fi -for name in $files; -do - if [ -n "$name" ] ; then - echo "Downloading file: " "$name" - dirName=$(dirname "$name") - mkdir -p "$dirName" - if [ $useSAS = "true" ] ; then - az storage blob download --container-name tfvars --account-name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --file "${name}" --name "${name}" --only-show-errors --output none --no-progress - else - az storage blob download --container-name tfvars --account-name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --auth-mode login --file "${name}" --name "${name}" --only-show-errors --output none --no-progress - fi - fi +for name in $files; do + if [ -n "$name" ]; then + echo "Downloading file: " "$name" + dirName=$(dirname "$name") + mkdir -p "$dirName" + if [ $useSAS = "true" ]; then + az storage blob download --container-name tfvars --account-name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --file "${name}" --name "${name}" --only-show-errors --output none --no-progress + else + az storage blob download --container-name tfvars --account-name "${REMOTE_STATE_SA}" --subscription "${STATE_SUBSCRIPTION}" --auth-mode login --file "${name}" --name "${name}" --only-show-errors --output none --no-progress + fi + fi done diff --git a/deploy/terraform/bootstrap/sap_deployer/module.tf b/deploy/terraform/bootstrap/sap_deployer/module.tf index 32d9848a6b..98d561d9b7 100644 --- a/deploy/terraform/bootstrap/sap_deployer/module.tf +++ b/deploy/terraform/bootstrap/sap_deployer/module.tf @@ -18,6 +18,7 @@ module "sap_deployer" { Agent_IP = var.add_Agent_IP ? var.Agent_IP : "" agent_pat = var.agent_pat agent_pool = var.agent_pool + agent_network_id = var.agent_network_id ansible_core_version = var.ansible_core_version app_registration_app_id = var.use_webapp ? var.app_registration_app_id : "" app_service = local.app_service @@ -38,7 +39,7 @@ module "sap_deployer" { key_vault = local.key_vault options = local.options place_delete_lock_on_resources = var.place_delete_lock_on_resources - public_network_access_enabled = var.public_network_access_enabled + public_network_access_enabled = true # This can only be set once we have private DNS in place var.public_network_access_enabled sa_connection_string = var.sa_connection_string soft_delete_retention_days = var.soft_delete_retention_days set_secret_expiry = var.set_secret_expiry diff --git a/deploy/terraform/bootstrap/sap_deployer/tfvar_variables.tf b/deploy/terraform/bootstrap/sap_deployer/tfvar_variables.tf index 9af7763d7d..a5884b3039 100644 --- a/deploy/terraform/bootstrap/sap_deployer/tfvar_variables.tf +++ b/deploy/terraform/bootstrap/sap_deployer/tfvar_variables.tf @@ -79,6 +79,17 @@ variable "management_network_address_space" { default = "" } +variable "network_flow_timeout_in_minutes" { + description = "The flow timeout in minutes of the virtual network" + type = number + nullable = true + default = null + validation { + condition = var.network_flow_timeout_in_minutes == null ? true : (var.network_flow_timeout_in_minutes >= 4 && var.network_flow_timeout_in_minutes <= 30) + error_message = "The flow timeout in minutes must be between 4 and 30 if set." + } + } + #######################################4#######################################8 # # # Management Subnet variables # @@ -134,11 +145,10 @@ variable "firewall_allowed_ipaddresses" { } variable "firewall_public_ip_tags" { - description = "Tags for the public_ip resource" - type = map(string) - default = null - } - + description = "Tags for the public_ip resource attached to firewall" + type = map(string) + default = null + } #######################################4#######################################8 # # @@ -167,6 +177,11 @@ variable "bastion_sku" { default = "Basic" } +variable "bastion_public_ip_tags" { + description = "Tags for the public_ip resource attached to bastion" + type = map(string) + default = null + } #######################################4#######################################8 # # # App Service Subnet variables # @@ -212,6 +227,11 @@ variable "deployer_enable_public_ip" { type = bool } +variable "deployer_public_ip_tags" { + description = "Tags for the public_ip resource attached to deployer" + type = map(string) + default = null + } ############################################################################### # # # Deployer Information # @@ -361,7 +381,7 @@ variable "set_secret_expiry" { #######################################4#######################################8 # # -# Miscallaneous settings # +# Miscellaneous settings # # # #######################################4#######################################8 @@ -426,6 +446,12 @@ variable "tags" { description = "If provided, tags for all resources" default = {} } + +variable "agent_network_id" { + description = "Agent Network resource ID" + default = "" + } + ######################################################################################### # # # DNS settings # diff --git a/deploy/terraform/bootstrap/sap_deployer/transform.tf b/deploy/terraform/bootstrap/sap_deployer/transform.tf index 4e5c563a8c..e8ad384aaf 100644 --- a/deploy/terraform/bootstrap/sap_deployer/transform.tf +++ b/deploy/terraform/bootstrap/sap_deployer/transform.tf @@ -53,6 +53,7 @@ locals { ), "" ) + flow_timeout_in_minutes=var.network_flow_timeout_in_minutes subnet_mgmt = { name = try( @@ -130,6 +131,7 @@ locals { deploy_defender_extension = var.deploy_defender_extension custom_random_id = var.custom_random_id + bastion_public_ip_tags = try(var.bastion_public_ip_tags, {}) } @@ -190,6 +192,8 @@ locals { user_assigned_identity_id = var.user_assigned_identity_id shared_access_key_enabled = var.shared_access_key_enabled devops_authentication_type = var.app_service_devops_authentication_type + deployer_public_ip_tags = try(var.deployer_public_ip_tags, {}) + } @@ -218,7 +222,7 @@ locals { deployment = var.firewall_deployment rule_subnets = var.firewall_rule_subnets allowed_ipaddresses = var.firewall_allowed_ipaddresses - ip_tags = var.firewall_public_ip_tags + ip_tags = try(var.firewall_public_ip_tags, {}) } assign_subscription_permissions = try(var.deployer_assign_subscription_permissions, false) diff --git a/deploy/terraform/bootstrap/sap_library/tfvar_variables.tf b/deploy/terraform/bootstrap/sap_library/tfvar_variables.tf index 8aeac98c74..b933e9b3e6 100644 --- a/deploy/terraform/bootstrap/sap_library/tfvar_variables.tf +++ b/deploy/terraform/bootstrap/sap_library/tfvar_variables.tf @@ -335,3 +335,14 @@ variable "enable_firewall_for_keyvaults_and_storage" { default = true type = bool } + +variable "create_privatelink_dns_zones" { + description = "Boolean value indicating if PrivateLink DNS Zones should be created" + default = true + type = bool + } + +variable "agent_network_id" { + description = "Agent Network resource ID" + default = "" + } diff --git a/deploy/terraform/bootstrap/sap_library/transform.tf b/deploy/terraform/bootstrap/sap_library/transform.tf index 1b6ab732cc..0acf20fbd0 100644 --- a/deploy/terraform/bootstrap/sap_library/transform.tf +++ b/deploy/terraform/bootstrap/sap_library/transform.tf @@ -65,18 +65,22 @@ locals { dns_settings = { - use_custom_dns_a_registration = var.use_custom_dns_a_registration - dns_label = var.dns_label - dns_zone_names = var.dns_zone_names + use_custom_dns_a_registration = var.use_custom_dns_a_registration + dns_label = var.dns_label + dns_zone_names = var.dns_zone_names - management_dns_resourcegroup_name = trimspace(var.management_dns_resourcegroup_name) - management_dns_subscription_id = var.management_dns_subscription_id + management_dns_resourcegroup_name = trimspace(var.management_dns_resourcegroup_name) + management_dns_subscription_id = var.management_dns_subscription_id - privatelink_dns_subscription_id = var.privatelink_dns_subscription_id != var.management_dns_subscription_id ? var.privatelink_dns_subscription_id : var.management_dns_subscription_id - privatelink_dns_resourcegroup_name = var.management_dns_resourcegroup_name != var.privatelink_dns_resourcegroup_name ? var.privatelink_dns_resourcegroup_name : var.management_dns_resourcegroup_name + privatelink_dns_subscription_id = var.privatelink_dns_subscription_id != var.management_dns_subscription_id ? var.privatelink_dns_subscription_id : var.management_dns_subscription_id + privatelink_dns_resourcegroup_name = var.management_dns_resourcegroup_name != var.privatelink_dns_resourcegroup_name ? var.privatelink_dns_resourcegroup_name : var.management_dns_resourcegroup_name register_storage_accounts_keyvaults_with_dns = var.register_storage_accounts_keyvaults_with_dns - register_endpoints_with_dns = var.register_endpoints_with_dns + register_endpoints_with_dns = var.register_endpoints_with_dns + + create_privatelink_dns_zones = var.create_privatelink_dns_zones + + agent_network_id = var.agent_network_id } diff --git a/deploy/terraform/run/sap_deployer/module.tf b/deploy/terraform/run/sap_deployer/module.tf index 09b461a4e3..fb51ff59a5 100644 --- a/deploy/terraform/run/sap_deployer/module.tf +++ b/deploy/terraform/run/sap_deployer/module.tf @@ -18,6 +18,7 @@ module "sap_deployer" { Agent_IP = var.add_Agent_IP ? var.Agent_IP : "" agent_pat = var.agent_pat agent_pool = var.agent_pool + agent_network_id = var.agent_network_id ansible_core_version = var.ansible_core_version app_registration_app_id = var.use_webapp ? var.app_registration_app_id : "" app_service = local.app_service diff --git a/deploy/terraform/run/sap_deployer/providers.tf b/deploy/terraform/run/sap_deployer/providers.tf index 174f751ce2..8ba54492db 100644 --- a/deploy/terraform/run/sap_deployer/providers.tf +++ b/deploy/terraform/run/sap_deployer/providers.tf @@ -54,9 +54,6 @@ provider "azurerm" { partner_id = "f94f50f2-2539-42f8-9c8e-c65b28c681f7" subscription_id = var.subscription_id - client_id = var.use_spn ? local.spn.client_id : null - client_secret = var.use_spn ? local.spn.client_secret: null - tenant_id = var.use_spn ? local.spn.tenant_id: null use_msi = var.use_spn ? false : true alias = "main" storage_use_azuread = var.data_plane_available diff --git a/deploy/terraform/run/sap_deployer/tfvar_variables.tf b/deploy/terraform/run/sap_deployer/tfvar_variables.tf index 12259e6ada..3c2f8cbceb 100644 --- a/deploy/terraform/run/sap_deployer/tfvar_variables.tf +++ b/deploy/terraform/run/sap_deployer/tfvar_variables.tf @@ -152,10 +152,10 @@ variable "firewall_allowed_ipaddresses" { } variable "firewall_public_ip_tags" { - description = "Tags for the public_ip resource" - type = map(string) - default = null - } + description = "Tags for the public_ip resource attached to firewall" + type = map(string) + default = null + } #######################################4#######################################8 # # @@ -184,6 +184,12 @@ variable "bastion_sku" { default = "Basic" } +variable "bastion_public_ip_tags" { + description = "Tags for the public_ip resource attached to bastion" + type = map(string) + default = null + } + #######################################4#######################################8 # # # App Service Subnet variables # @@ -197,7 +203,7 @@ variable "webapp_subnet_arm_id" { } variable "webapp_subnet_address_prefix" { - description = "Subnet adress range for the Web App subnet" + description = "Subnet address range for the Web App subnet" default = "" } @@ -229,6 +235,11 @@ variable "deployer_enable_public_ip" { type = bool } +variable "deployer_public_ip_tags" { + description = "Tags for the public_ip resource attached to deployer" + type = map(string) + default = null + } ############################################################################### # # # Deployer Information # @@ -366,7 +377,7 @@ variable "soft_delete_retention_days" { #######################################4#######################################8 # # -# Miscallaneous settings # +# Miscellaneous settings # # # #######################################4#######################################8 @@ -437,6 +448,12 @@ variable "tags" { description = "If provided, tags for all resources" default = {} } + +variable "agent_network_id" { + description = "Agent Network resource ID" + default = "" + } + ######################################################################################### # # # DNS settings # @@ -497,7 +514,7 @@ variable "agent_pool" { } variable "agent_pat" { - description = "If provided, contains the Personal Access Token to be used" + description = "If provided, contains the Personal Access Token to be used" default = "" } @@ -508,7 +525,7 @@ variable "agent_ado_url" { variable "ansible_core_version" { description = "If provided, the version of ansible core to be installed" - default = "2.15" + default = "2.16" } ######################################################################################### diff --git a/deploy/terraform/run/sap_deployer/transform.tf b/deploy/terraform/run/sap_deployer/transform.tf index 2dbec7716d..187a706b0f 100644 --- a/deploy/terraform/run/sap_deployer/transform.tf +++ b/deploy/terraform/run/sap_deployer/transform.tf @@ -131,9 +131,10 @@ locals { } } } - deploy_monitoring_extension = var.deploy_monitoring_extension - deploy_defender_extension = var.deploy_defender_extension - custom_random_id = var.custom_random_id + deploy_monitoring_extension = var.deploy_monitoring_extension + deploy_defender_extension = var.deploy_defender_extension + custom_random_id = var.custom_random_id + bastion_public_ip_tags = try(var.bastion_public_ip_tags, {}) } deployer = { @@ -193,6 +194,7 @@ locals { user_assigned_identity_id = var.user_assigned_identity_id shared_access_key_enabled = var.shared_access_key_enabled devops_authentication_type = var.app_service_devops_authentication_type + deployer_public_ip_tags = try(var.deployer_public_ip_tags, {}) } authentication = { diff --git a/deploy/terraform/run/sap_landscape/imports.tf b/deploy/terraform/run/sap_landscape/imports.tf index 4d9ecfda1e..5628f06f17 100644 --- a/deploy/terraform/run/sap_landscape/imports.tf +++ b/deploy/terraform/run/sap_landscape/imports.tf @@ -21,50 +21,74 @@ data "terraform_remote_state" "deployer" { } data "azurerm_key_vault_secret" "subscription_id" { + count = length(var.subscription_id) > 0 ? 0 : (var.use_spn ? 1 : 0) name = format("%s-subscription-id", local.environment) key_vault_id = local.spn_key_vault_arm_id + timeouts { + read = "1m" + } } data "azurerm_key_vault_secret" "client_id" { count = var.use_spn ? 1 : 0 name = format("%s-client-id", local.environment) key_vault_id = local.spn_key_vault_arm_id + timeouts { + read = "1m" + } } data "azurerm_key_vault_secret" "client_secret" { count = var.use_spn ? 1 : 0 name = format("%s-client-secret", local.environment) key_vault_id = local.spn_key_vault_arm_id + timeouts { + read = "1m" + } } data "azurerm_key_vault_secret" "tenant_id" { count = var.use_spn ? 1 : 0 name = format("%s-tenant-id", local.environment) key_vault_id = local.spn_key_vault_arm_id + timeouts { + read = "1m" + } } data "azurerm_key_vault_secret" "cp_subscription_id" { - count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (var.use_spn ? 1 : 0) : 0 name = format("%s-subscription-id", data.terraform_remote_state.deployer[0].outputs.environment) key_vault_id = local.spn_key_vault_arm_id + timeouts { + read = "1m" + } } data "azurerm_key_vault_secret" "cp_client_id" { - count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (var.use_spn ? 1 : 0) : 0 + count = var.use_spn ? 1 : 0 name = format("%s-client-id", data.terraform_remote_state.deployer[0].outputs.environment) key_vault_id = local.spn_key_vault_arm_id + timeouts { + read = "1m" + } } data "azurerm_key_vault_secret" "cp_client_secret" { - count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (var.use_spn ? 1 : 0) : 0 + count = var.use_spn ? 1 : 0 name = format("%s-client-secret", data.terraform_remote_state.deployer[0].outputs.environment) key_vault_id = local.spn_key_vault_arm_id + timeouts { + read = "1m" + } } data "azurerm_key_vault_secret" "cp_tenant_id" { - count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (var.use_spn ? 1 : 0) : 0 + count = var.use_spn ? 1 : 0 name = format("%s-tenant-id", data.terraform_remote_state.deployer[0].outputs.environment) key_vault_id = local.spn_key_vault_arm_id + timeouts { + read = "1m" + } } // Import current service principal diff --git a/deploy/terraform/run/sap_landscape/module.tf b/deploy/terraform/run/sap_landscape/module.tf index bc8a9d235e..acd116a75b 100644 --- a/deploy/terraform/run/sap_landscape/module.tf +++ b/deploy/terraform/run/sap_landscape/module.tf @@ -16,6 +16,7 @@ module "sap_landscape" { additional_users_to_add_to_keyvault_policies = var.additional_users_to_add_to_keyvault_policies Agent_IP = var.add_Agent_IP ? var.Agent_IP : "" + agent_network_id = var.agent_network_id ANF_settings = local.ANF_settings authentication = local.authentication create_transport_storage = var.create_transport_storage diff --git a/deploy/terraform/run/sap_landscape/output.tf b/deploy/terraform/run/sap_landscape/output.tf index c14c099c3c..93aa2ff328 100644 --- a/deploy/terraform/run/sap_landscape/output.tf +++ b/deploy/terraform/run/sap_landscape/output.tf @@ -250,13 +250,13 @@ output "storageaccount_rg_name" { } output "transport_storage_account_id" { - description = "Transport storage account resource group name" + description = "Transport storage account name" value = module.sap_landscape.transport_storage_account_id } //Witness output "witness_storage_account" { - description = "Transport storage account resource group name" + description = "Witness storage account name" value = module.sap_landscape.witness_storage_account } diff --git a/deploy/terraform/run/sap_landscape/providers.tf b/deploy/terraform/run/sap_landscape/providers.tf index e32039b17d..72da7a1455 100644 --- a/deploy/terraform/run/sap_landscape/providers.tf +++ b/deploy/terraform/run/sap_landscape/providers.tf @@ -14,7 +14,7 @@ provider "azurerm" { features {} - subscription_id = coalesce(var.management_subscription,var.subscription, local.deployer_subscription_id) + subscription_id = coalesce(var.management_subscription,var.subscription_id, local.deployer_subscription_id) use_msi = var.use_spn ? false : true storage_use_azuread = true @@ -36,7 +36,7 @@ provider "azurerm" { } } - subscription_id = coalesce(var.subscription, data.azurerm_key_vault_secret.subscription_id.value) + subscription_id = length(var.subscription_id) > 0 ? var.subscription_id : data.azurerm_key_vault_secret.subscription_id[0].value client_id = var.use_spn ? local.spn.client_id : null client_secret = var.use_spn ? local.spn.client_secret : null tenant_id = var.use_spn ? local.spn.tenant_id : null diff --git a/deploy/terraform/run/sap_landscape/tfvar_variables.tf b/deploy/terraform/run/sap_landscape/tfvar_variables.tf index 4d7ec15cd1..9ea84c2df8 100644 --- a/deploy/terraform/run/sap_landscape/tfvar_variables.tf +++ b/deploy/terraform/run/sap_landscape/tfvar_variables.tf @@ -46,7 +46,7 @@ variable "Description" { } -variable "subscription" { +variable "subscription_id" { description = "This is the target subscription for the deployment" type = string default = "" @@ -730,7 +730,7 @@ variable "use_AFS_for_shared_storage" { ######################################################################################### # # -# iSCSI definitioms # +# iSCSI definitions # # # ######################################################################################### @@ -1007,3 +1007,8 @@ variable "custom_random_id" { description = "If provided, the value of the custom random id" default = "" } + +variable "agent_network_id" { + description = "Agent Network resource ID" + default = "" + } diff --git a/deploy/terraform/run/sap_landscape/transform.tf b/deploy/terraform/run/sap_landscape/transform.tf index 074d0b09cd..d60ce6ced4 100644 --- a/deploy/terraform/run/sap_landscape/transform.tf +++ b/deploy/terraform/run/sap_landscape/transform.tf @@ -211,12 +211,9 @@ locals { user_keyvault = var.user_keyvault_id - spn_keyvault_specified = ( - length(var.spn_keyvault_id) + - length(try(var.key_vault.kv_spn_id, "")) - ) > 0 + spn_keyvault_specified = length(var.spn_keyvault_id) > 0 - spn_kv = local.spn_keyvault_specified ? ( + keyvault_containing_the_spns = local.spn_keyvault_specified ? ( var.spn_keyvault_id ) : ( "" @@ -225,12 +222,12 @@ locals { key_vault = merge(local.key_vault_temp, ( local.user_keyvault_specified ? ( { - kv_user_id = local.user_keyvault + keyvault_id_for_system_credentials = local.user_keyvault } ) : null), ( local.spn_keyvault_specified ? ( { - kv_spn_id = local.spn_kv + keyvault_id_for_deployment_credentials = local.keyvault_containing_the_spns } ) : null ) diff --git a/deploy/terraform/run/sap_landscape/variables_local.tf b/deploy/terraform/run/sap_landscape/variables_local.tf index af4562b762..47706fd920 100644 --- a/deploy/terraform/run/sap_landscape/variables_local.tf +++ b/deploy/terraform/run/sap_landscape/variables_local.tf @@ -31,14 +31,14 @@ locals { ) spn = { - subscription_id = data.azurerm_key_vault_secret.subscription_id.value, + subscription_id = length(var.subscription_id) > 0 ? var.subscription_id : data.azurerm_key_vault_secret.subscription_id[0].value, client_id = var.use_spn ? data.azurerm_key_vault_secret.client_id[0].value : null, client_secret = var.use_spn ? data.azurerm_key_vault_secret.client_secret[0].value : null, tenant_id = var.use_spn ? data.azurerm_key_vault_secret.tenant_id[0].value : null } cp_spn = { - subscription_id = try(data.azurerm_key_vault_secret.cp_subscription_id[0].value, null) + subscription_id = try(data.azurerm_key_vault_secret.cp_subscription_id.value, null) client_id = var.use_spn ? data.azurerm_key_vault_secret.cp_client_id[0].value : null, client_secret = var.use_spn ? data.azurerm_key_vault_secret.cp_client_secret[0].value : null, tenant_id = var.use_spn ? data.azurerm_key_vault_secret.cp_tenant_id[0].value : null @@ -47,13 +47,17 @@ locals { service_principal = { subscription_id = local.spn.subscription_id, tenant_id = local.spn.tenant_id, - object_id = var.use_spn ? data.azuread_service_principal.sp[0].object_id : null + object_id = var.use_spn ? data.azuread_service_principal.sp[0].object_id : null, + client_id = var.use_spn ? data.azuread_service_principal.sp[0].client_id : null, + exists = var.use_spn } account = { - subscription_id = data.azurerm_key_vault_secret.subscription_id.value, + subscription_id = length(var.subscription_id) > 0 ? var.subscription_id : data.azurerm_key_vault_secret.subscription_id[0].value, tenant_id = data.azurerm_client_config.current.tenant_id, - object_id = data.azurerm_client_config.current.object_id + object_id = data.azurerm_client_config.current.object_id, + client_id = data.azurerm_client_config.current.client_id , + exists = false } custom_names = length(var.name_override_file) > 0 ? ( @@ -63,7 +67,7 @@ locals { ) is_DNS_info_different = ( - var.management_dns_subscription_id != data.azurerm_key_vault_secret.subscription_id.value + var.management_dns_subscription_id != ((length(var.subscription_id) > 0) ? var.subscription_id : data.azurerm_key_vault_secret.subscription_id[0].value) ) || ( var.management_dns_resourcegroup_name != (local.saplib_resource_group_name) ) diff --git a/deploy/terraform/run/sap_library/tfvar_variables.tf b/deploy/terraform/run/sap_library/tfvar_variables.tf index 6b92440f12..e4e2e20cdd 100644 --- a/deploy/terraform/run/sap_library/tfvar_variables.tf +++ b/deploy/terraform/run/sap_library/tfvar_variables.tf @@ -348,6 +348,19 @@ variable "privatelink_dns_resourcegroup_name" { type = string } +variable "create_privatelink_dns_zones" { + description = "Boolean value indicating if PrivateLink DNS Zones should be created" + default = true + type = bool + } + + +variable "agent_network_id" { + description = "Agent Network resource ID" + default = "" + } + + variable "dns_label" { description = "DNS label" default = "" diff --git a/deploy/terraform/run/sap_library/transform.tf b/deploy/terraform/run/sap_library/transform.tf index 5a5bee587f..6bc0faefe7 100644 --- a/deploy/terraform/run/sap_library/transform.tf +++ b/deploy/terraform/run/sap_library/transform.tf @@ -64,17 +64,21 @@ locals { } dns_settings = { - use_custom_dns_a_registration = var.use_custom_dns_a_registration - dns_label = var.dns_label - dns_zone_names = var.dns_zone_names + use_custom_dns_a_registration = var.use_custom_dns_a_registration + dns_label = var.dns_label + dns_zone_names = var.dns_zone_names - management_dns_resourcegroup_name = trimspace(var.management_dns_resourcegroup_name) - management_dns_subscription_id = var.management_dns_subscription_id + management_dns_resourcegroup_name = trimspace(var.management_dns_resourcegroup_name) + management_dns_subscription_id = var.management_dns_subscription_id - privatelink_dns_subscription_id = var.privatelink_dns_subscription_id != var.management_dns_subscription_id ? var.privatelink_dns_subscription_id : var.management_dns_subscription_id - privatelink_dns_resourcegroup_name = var.management_dns_resourcegroup_name != var.privatelink_dns_resourcegroup_name ? var.privatelink_dns_resourcegroup_name : var.management_dns_resourcegroup_name + privatelink_dns_subscription_id = var.privatelink_dns_subscription_id != var.management_dns_subscription_id ? var.privatelink_dns_subscription_id : var.management_dns_subscription_id + privatelink_dns_resourcegroup_name = var.management_dns_resourcegroup_name != var.privatelink_dns_resourcegroup_name ? var.privatelink_dns_resourcegroup_name : var.management_dns_resourcegroup_name register_storage_accounts_keyvaults_with_dns = var.register_storage_accounts_keyvaults_with_dns - register_endpoints_with_dns = var.register_endpoints_with_dns + register_endpoints_with_dns = var.register_endpoints_with_dns + + create_privatelink_dns_zones = var.create_privatelink_dns_zones + + agent_network_id = var.agent_network_id } } diff --git a/deploy/terraform/run/sap_system/imports.tf b/deploy/terraform/run/sap_system/imports.tf index 0171babd7e..546134195c 100644 --- a/deploy/terraform/run/sap_system/imports.tf +++ b/deploy/terraform/run/sap_system/imports.tf @@ -16,8 +16,6 @@ data "terraform_remote_state" "deployer" { container_name = local.tfstate_container_name key = var.deployer_tfstate_key subscription_id = local.saplib_subscription_id - use_msi = var.use_spn ? false : true - use_azuread_auth = true } } @@ -29,54 +27,53 @@ data "terraform_remote_state" "landscape" { container_name = "tfstate" key = var.landscape_tfstate_key subscription_id = local.saplib_subscription_id - use_msi = var.use_spn ? false : true - use_azuread_auth = true } } data "azurerm_key_vault_secret" "subscription_id" { + count = length(var.subscription_id) > 0 ? 0 : (var.use_spn ? 1 : 0) name = format("%s-subscription-id", local.environment) key_vault_id = local.spn_key_vault_arm_id } data "azurerm_key_vault_secret" "client_id" { - count = try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? 1 : 0 + count = var.use_spn ? 1 : 0 name = format("%s-client-id", local.environment) key_vault_id = local.spn_key_vault_arm_id } data "azurerm_key_vault_secret" "client_secret" { - count = try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? 1 : 0 + count = var.use_spn ? 1 : 0 name = format("%s-client-secret", local.environment) key_vault_id = local.spn_key_vault_arm_id } data "azurerm_key_vault_secret" "tenant_id" { - count = try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? 1 : 0 + count = var.use_spn ? 1 : 0 name = format("%s-tenant-id", local.environment) key_vault_id = local.spn_key_vault_arm_id } data "azurerm_key_vault_secret" "cp_subscription_id" { - count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? 1 : 0) : 0 + count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (var.use_spn ? 1 : 0) : 0 name = format("%s-subscription-id", data.terraform_remote_state.deployer[0].outputs.environment) key_vault_id = local.spn_key_vault_arm_id } data "azurerm_key_vault_secret" "cp_client_id" { - count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? 1 : 0) : 0 + count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (var.use_spn ? 1 : 0) : 0 name = format("%s-client-id", data.terraform_remote_state.deployer[0].outputs.environment) key_vault_id = local.spn_key_vault_arm_id } data "azurerm_key_vault_secret" "cp_client_secret" { - count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? 1 : 0) : 0 + count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (var.use_spn ? 1 : 0) : 0 name = format("%s-client-secret", data.terraform_remote_state.deployer[0].outputs.environment) key_vault_id = local.spn_key_vault_arm_id } data "azurerm_key_vault_secret" "cp_tenant_id" { - count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? 1 : 0) : 0 + count = length(try(data.terraform_remote_state.deployer[0].outputs.environment, "")) > 0 ? (var.use_spn ? 1 : 0) : 0 name = format("%s-tenant-id", data.terraform_remote_state.deployer[0].outputs.environment) key_vault_id = local.spn_key_vault_arm_id } diff --git a/deploy/terraform/run/sap_system/module.tf b/deploy/terraform/run/sap_system/module.tf index f7fe9dc2f2..0ab990621c 100644 --- a/deploy/terraform/run/sap_system/module.tf +++ b/deploy/terraform/run/sap_system/module.tf @@ -51,7 +51,6 @@ module "sap_namegenerator" { module "common_infrastructure" { source = "../../terraform-units/modules/sap_system/common_infrastructure" providers = { - azurerm.deployer = azurerm azurerm.main = azurerm.system azurerm.dnsmanagement = azurerm.dnsmanagement azurerm.privatelinkdnsmanagement = azurerm.privatelinkdnsmanagement @@ -127,6 +126,7 @@ module "hdb_node" { 0 ) database_use_premium_v2_storage = var.database_use_premium_v2_storage + database_active_active = var.database_active_active database_vm_admin_nic_ips = var.database_vm_admin_nic_ips database_vm_db_nic_ips = var.database_vm_db_nic_ips database_vm_db_nic_secondary_ips = var.database_vm_db_nic_secondary_ips @@ -332,6 +332,8 @@ module "output_files" { database_cluster_type = var.database_cluster_type database_cluster_ip = module.anydb_node.database_cluster_ip database_high_availability = local.database.high_availability + database_active_active = var.database_active_active + database_active_active_loadbalancer_ip = try(module.hdb_node.database_loadbalancer_ip[1], "") database_loadbalancer_ip = upper(try(local.database.platform, "HANA")) == "HANA" ? ( module.hdb_node.database_loadbalancer_ip[0]) : ( module.anydb_node.database_loadbalancer_ip[0] diff --git a/deploy/terraform/run/sap_system/providers.tf b/deploy/terraform/run/sap_system/providers.tf index f01aaaa29e..a56a8f45c9 100644 --- a/deploy/terraform/run/sap_system/providers.tf +++ b/deploy/terraform/run/sap_system/providers.tf @@ -16,6 +16,7 @@ provider "azurerm" { features {} subscription_id = length(local.deployer_subscription_id) > 0 ? local.deployer_subscription_id : null storage_use_azuread = true + use_msi = true } provider "azurerm" { @@ -37,6 +38,8 @@ provider "azurerm" { client_secret = try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? local.spn.client_secret : null tenant_id = try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? local.spn.tenant_id : null use_msi = try(data.terraform_remote_state.landscape.outputs.use_spn, true) && var.use_spn ? false : true + subscription_id = length(var.subscription_id) > 0 ? var.subscription_id : data.azurerm_key_vault_secret.subscription_id[0].value + partner_id = "3179cd51-f54b-4c73-ac10-8e99417efce7" storage_use_azuread = true diff --git a/deploy/terraform/run/sap_system/tfvar_variables.tf b/deploy/terraform/run/sap_system/tfvar_variables.tf index 393f8b47cd..4b58a8af3f 100644 --- a/deploy/terraform/run/sap_system/tfvar_variables.tf +++ b/deploy/terraform/run/sap_system/tfvar_variables.tf @@ -620,6 +620,11 @@ variable "database_use_premium_v2_storage" { default = false } +variable "database_active_active" { + description = "If true, database will deployed with Active/Active (read enabled) configuration, only supported for HANA" + default = false + } + ######################################################################################### # # # Observer variables # @@ -1403,7 +1408,7 @@ variable "anchor_vm_accelerated_networking" { default = true } -variable "subscription" { +variable "subscription_id" { description = "Target subscription" default = "" } diff --git a/deploy/terraform/run/sap_system/variables_local.tf b/deploy/terraform/run/sap_system/variables_local.tf index 4bb0b5f4bf..47d6a9dc37 100644 --- a/deploy/terraform/run/sap_system/variables_local.tf +++ b/deploy/terraform/run/sap_system/variables_local.tf @@ -35,18 +35,18 @@ locals { deployer_subscription_id = length(local.spn_key_vault_arm_id) > 0 ? split("/", local.spn_key_vault_arm_id)[2] : "" spn = { - subscription_id = data.azurerm_key_vault_secret.subscription_id.value, + subscription_id = length(var.subscription_id) > 0 ? var.subscription_id : data.azurerm_key_vault_secret.subscription_id[0].value, client_id = var.use_spn ? data.azurerm_key_vault_secret.client_id[0].value : null, client_secret = var.use_spn ? data.azurerm_key_vault_secret.client_secret[0].value : null, tenant_id = var.use_spn ? data.azurerm_key_vault_secret.tenant_id[0].value : null } cp_spn = { - subscription_id = local.deployer_subscription_id - client_id = var.use_spn ? try(coalesce(data.azurerm_key_vault_secret.cp_client_id[0].value, data.azurerm_key_vault_secret.client_id[0].value), null) : null, - client_secret = var.use_spn ? try(coalesce(data.azurerm_key_vault_secret.cp_client_secret[0].value, data.azurerm_key_vault_secret.client_secret[0].value), null) : null, - tenant_id = var.use_spn ? try(coalesce(data.azurerm_key_vault_secret.cp_tenant_id[0].value, data.azurerm_key_vault_secret.tenant_id[0].value), null) : null - } + subscription_id = local.deployer_subscription_id + client_id = var.use_spn ? try(coalesce(data.azurerm_key_vault_secret.cp_client_id[0].value, data.azurerm_key_vault_secret.client_id[0].value), null) : null, + client_secret = var.use_spn ? try(coalesce(data.azurerm_key_vault_secret.cp_client_secret[0].value, data.azurerm_key_vault_secret.client_secret[0].value), null) : null, + tenant_id = var.use_spn ? try(coalesce(data.azurerm_key_vault_secret.cp_tenant_id[0].value, data.azurerm_key_vault_secret.tenant_id[0].value), null) : null + } service_principal = { subscription_id = local.spn.subscription_id, @@ -55,7 +55,7 @@ locals { } account = { - subscription_id = data.azurerm_key_vault_secret.subscription_id.value, + subscription_id = length(var.subscription_id) > 0 ? var.subscription_id : data.azurerm_key_vault_secret.subscription_id[0].value, tenant_id = var.use_spn ? data.azurerm_client_config.current.tenant_id : null, object_id = var.use_spn ? data.azurerm_client_config.current.object_id : null } diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/app_service.tf b/deploy/terraform/terraform-units/modules/sap_deployer/app_service.tf index 81136504a7..61e047beea 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/app_service.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/app_service.tf @@ -11,11 +11,11 @@ resource "azurerm_subnet" "webapp" { count = var.use_webapp ? local.webapp_subnet_exists ? 0 : 1 : 0 name = local.webapp_subnet_name - resource_group_name = local.vnet_mgmt_exists ? ( + resource_group_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].resource_group_name) : ( azurerm_virtual_network.vnet_mgmt[0].resource_group_name ) - virtual_network_name = local.vnet_mgmt_exists ? ( + virtual_network_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].name) : ( azurerm_virtual_network.vnet_mgmt[0].name ) @@ -102,12 +102,15 @@ resource "azurerm_windows_web_app" "webapp" { app_settings = { "CollectionUri" = var.agent_ado_url "IS_PIPELINE_DEPLOYMENT" = false - "OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID" = length(var.deployer.user_assigned_identity_id) > 0 ? data.azurerm_user_assigned_identity.deployer[0].client_id : azurerm_user_assigned_identity.deployer[0].client_id + "OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID" = length(var.deployer.user_assigned_identity_id) > 0 ? data.azurerm_user_assigned_identity.deployer[0].client_id : null "WEBSITE_AUTH_CUSTOM_AUTHORIZATION" = true "WHICH_ENV" = length(var.deployer.user_assigned_identity_id) > 0 ? "DATA" : "LOCAL" "AZURE_TENANT_ID" = data.azurerm_client_config.deployer.tenant_id "AUTHENTICATION_TYPE" = var.deployer.devops_authentication_type - "PAT" = var.use_private_endpoint ? format("@Microsoft.KeyVault(SecretUri=https://%s.privatelink.vaultcore.azure.net/secrets/PAT/)", local.keyvault_names.user_access) : format("@Microsoft.KeyVault(SecretUri=https://%s.vault.azure.net/secrets/PAT/)", local.keyvault_names.user_access) + "PAT" = var.use_private_endpoint ? ( + format("@Microsoft.KeyVault(SecretUri=https://%s.privatelink.vaultcore.azure.net/secrets/PAT/)", local.keyvault_names.user_access)): ( + format("@Microsoft.KeyVault(SecretUri=https://%s.vault.azure.net/secrets/PAT/)", local.keyvault_names.user_access) + ) } sticky_settings { @@ -165,7 +168,10 @@ resource "azurerm_windows_web_app" "webapp" { connection_string { name = "tfstate" type = "Custom" - value = var.use_private_endpoint ? format("@Microsoft.KeyVault(SecretUri=https://%s.privatelink.vaultcore.azure.net/secrets/tfstate/)", local.user_keyvault_name) : format("@Microsoft.KeyVault(SecretUri=https://%s.vault.azure.net/secrets/tfstate/)", local.user_keyvault_name) + value = var.use_private_endpoint ? ( + format("@Microsoft.KeyVault(SecretUri=https://%s.privatelink.vaultcore.azure.net/secrets/tfstate/)", local.user_keyvault_name)) : ( + format("@Microsoft.KeyVault(SecretUri=https://%s.vault.azure.net/secrets/tfstate/)", local.user_keyvault_name) + ) } lifecycle { diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/bastion.tf b/deploy/terraform/terraform-units/modules/sap_deployer/bastion.tf index f5ee149b3c..de5399af39 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/bastion.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/bastion.tf @@ -13,11 +13,11 @@ resource "azurerm_subnet" "bastion" { 0 ) name = "AzureBastionSubnet" - resource_group_name = local.vnet_mgmt_exists ? ( + resource_group_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].resource_group_name) : ( azurerm_virtual_network.vnet_mgmt[0].resource_group_name ) - virtual_network_name = local.vnet_mgmt_exists ? ( + virtual_network_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].name) : ( azurerm_virtual_network.vnet_mgmt[0].name ) @@ -55,18 +55,22 @@ resource "azurerm_public_ip" "bastion" { ) allocation_method = "Static" sku = "Standard" - location = local.vnet_mgmt_exists ? ( + location = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].location) : ( azurerm_virtual_network.vnet_mgmt[0].location ) - resource_group_name = local.vnet_mgmt_exists ? ( + resource_group_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].resource_group_name) : ( azurerm_virtual_network.vnet_mgmt[0].resource_group_name ) - - lifecycle { + # zones = [1,2,3] - optional property. + ip_tags = var.infrastructure.bastion_public_ip_tags + lifecycle { + ignore_changes = [ + ip_tags + ] create_before_destroy = true - } + } } # Create the Bastion Host @@ -79,11 +83,11 @@ resource "azurerm_bastion_host" "bastion" { var.naming.resource_suffixes.bastion_host ) sku = var.bastion_sku - location = local.vnet_mgmt_exists ? ( + location = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].location) : ( azurerm_virtual_network.vnet_mgmt[0].location ) - resource_group_name = local.vnet_mgmt_exists ? ( + resource_group_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].resource_group_name) : ( azurerm_virtual_network.vnet_mgmt[0].resource_group_name ) diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/firewall.tf b/deploy/terraform/terraform-units/modules/sap_deployer/firewall.tf index 3e1b5c5f8b..fe556ddd73 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/firewall.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/firewall.tf @@ -7,11 +7,11 @@ resource "azurerm_subnet" "firewall" { count = var.firewall.deployment && !local.firewall_subnet_exists ? 1 : 0 name = local.firewall_subnet_name address_prefixes = [local.firewall_subnet_prefix] - resource_group_name = local.vnet_mgmt_exists ? ( + resource_group_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].resource_group_name) : ( azurerm_virtual_network.vnet_mgmt[0].resource_group_name ) - virtual_network_name = local.vnet_mgmt_exists ? ( + virtual_network_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].name) : ( azurerm_virtual_network.vnet_mgmt[0].name ) @@ -36,21 +36,25 @@ resource "azurerm_public_ip" "firewall" { allocation_method = "Static" sku = "Standard" - location = local.vnet_mgmt_exists ? ( + location = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].location) : ( azurerm_virtual_network.vnet_mgmt[0].location ) - resource_group_name = local.vnet_mgmt_exists ? ( + resource_group_name = local.management_virtual_network_exists ? ( data.azurerm_virtual_network.vnet_mgmt[0].resource_group_name) : ( azurerm_virtual_network.vnet_mgmt[0].resource_group_name ) + # zones = [1,2,3] - optional property. + ip_tags = var.firewall.ip_tags + lifecycle { + ignore_changes = [ + ip_tags + ] + create_before_destroy = true + } - lifecycle { - create_before_destroy = true - } - ip_tags = local.firewall_service_tags } diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/infrastructure.tf b/deploy/terraform/terraform-units/modules/sap_deployer/infrastructure.tf index 8b0d8fb725..9ef62cbf6b 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/infrastructure.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/infrastructure.tf @@ -37,15 +37,16 @@ data "azurerm_resource_group" "deployer" { // Create/Import management vnet resource "azurerm_virtual_network" "vnet_mgmt" { - count = (!local.vnet_mgmt_exists) ? 1 : 0 + count = (!local.management_virtual_network_exists) ? 1 : 0 name = local.vnet_mgmt_name resource_group_name = local.resource_group_exists ? data.azurerm_resource_group.deployer[0].name : azurerm_resource_group.deployer[0].name location = local.resource_group_exists ? data.azurerm_resource_group.deployer[0].location : azurerm_resource_group.deployer[0].location address_space = [local.vnet_mgmt_addr] + flow_timeout_in_minutes = var.infrastructure.vnets.management.flow_timeout_in_minutes } data "azurerm_virtual_network" "vnet_mgmt" { - count = (local.vnet_mgmt_exists) ? 1 : 0 + count = (local.management_virtual_network_exists) ? 1 : 0 name = split("/", local.vnet_mgmt_arm_id)[8] resource_group_name = split("/", local.vnet_mgmt_arm_id)[4] } @@ -54,8 +55,8 @@ data "azurerm_virtual_network" "vnet_mgmt" { resource "azurerm_subnet" "subnet_mgmt" { count = (!local.management_subnet_exists) ? 1 : 0 name = local.management_subnet_name - resource_group_name = local.vnet_mgmt_exists ? data.azurerm_virtual_network.vnet_mgmt[0].resource_group_name : azurerm_virtual_network.vnet_mgmt[0].resource_group_name - virtual_network_name = local.vnet_mgmt_exists ? data.azurerm_virtual_network.vnet_mgmt[0].name : azurerm_virtual_network.vnet_mgmt[0].name + resource_group_name = local.management_virtual_network_exists ? data.azurerm_virtual_network.vnet_mgmt[0].resource_group_name : azurerm_virtual_network.vnet_mgmt[0].resource_group_name + virtual_network_name = local.management_virtual_network_exists ? data.azurerm_virtual_network.vnet_mgmt[0].name : azurerm_virtual_network.vnet_mgmt[0].name address_prefixes = [local.management_subnet_prefix] private_endpoint_network_policies = !var.use_private_endpoint ? "Enabled" : "Disabled" @@ -67,7 +68,6 @@ resource "azurerm_subnet" "subnet_mgmt" { )) : ( null) - flow_timeout_in_minutes = var.infrastructure.vnets.management.flow_timeout_in_minutes } @@ -133,5 +133,66 @@ resource "azurerm_role_assignment" "resource_group_contributor_contributor_msi" principal_id = length(var.deployer.user_assigned_identity_id) == 0 ? azurerm_user_assigned_identity.deployer[0].principal_id : data.azurerm_user_assigned_identity.deployer[0].principal_id } +resource "azurerm_virtual_network_peering" "peering_management_agent" { + provider = azurerm.main + count = length(var.agent_network_id) > 0 ? 1 : 0 + name = substr( + format("%s_to_%s", + split("/", var.agent_network_id)[8], + local.management_virtual_network_exists ? ( + data.azurerm_virtual_network.vnet_mgmt[0].name) : ( + azurerm_virtual_network.vnet_mgmt[0].name + ) + ), + 0, + 80 + ) + resource_group_name = local.resource_group_exists ? ( + data.azurerm_resource_group.deployer[0].name) : ( + azurerm_resource_group.deployer[0].name + ) + + remote_virtual_network_id = data.azurerm_virtual_network.agent_virtual_network[0].id + + virtual_network_name = local.management_virtual_network_exists ? ( + data.azurerm_virtual_network.vnet_mgmt[0].name) : ( + azurerm_virtual_network.vnet_mgmt[0].name + ) + + allow_virtual_network_access = true +} + +resource "azurerm_virtual_network_peering" "peering_agent_management" { + provider = azurerm.main + count = length(var.agent_network_id) > 0 ? 1:0 + + name = substr( + format("%s_to_%s", + local.management_virtual_network_exists ? ( + data.azurerm_virtual_network.vnet_mgmt[0].name) : ( + azurerm_virtual_network.vnet_mgmt[0].name + ), + split("/", var.agent_network_id)[8] + ), + 0, + 80 + ) + resource_group_name = split("/", var.agent_network_id)[4] + virtual_network_name = split("/", var.agent_network_id)[8] + remote_virtual_network_id = local.management_virtual_network_exists ? ( + data.azurerm_virtual_network.vnet_mgmt[0].id) : ( + azurerm_virtual_network.vnet_mgmt[0].id + ) + allow_virtual_network_access = true + allow_forwarded_traffic = true +} + + +data "azurerm_virtual_network" "agent_virtual_network" { + count = length(var.agent_network_id) > 0 ? 1:0 + name = split("/", var.agent_network_id)[8] + resource_group_name = split("/", var.agent_network_id)[4] +} + diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/key_vault.tf b/deploy/terraform/terraform-units/modules/sap_deployer/key_vault.tf index 17dd651258..96caf299d8 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/key_vault.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/key_vault.tf @@ -30,7 +30,7 @@ resource "azurerm_key_vault" "kv_user" { dynamic "network_acls" { - for_each = range(!var.public_network_access_enabled ? 1 : 0) + for_each = range(var.public_network_access_enabled ? 1 : 0) content { bypass = "AzureServices" @@ -46,11 +46,11 @@ resource "azurerm_key_vault" "kv_user" { ) virtual_network_subnet_ids = compact(local.management_subnet_exists ? (var.use_webapp ? ( - flatten([data.azurerm_subnet.subnet_mgmt[0].id, data.azurerm_subnet.webapp[0].id, var.subnets_to_add])) : ( - flatten([data.azurerm_subnet.subnet_mgmt[0].id, var.subnets_to_add])) + flatten([data.azurerm_subnet.subnet_mgmt[0].id, data.azurerm_subnet.webapp[0].id, var.subnets_to_add, var.agent_network_id])) : ( + flatten([data.azurerm_subnet.subnet_mgmt[0].id, var.subnets_to_add, var.agent_network_id])) ) : (var.use_webapp ? ( - compact(flatten([azurerm_subnet.subnet_mgmt[0].id, try(azurerm_subnet.webapp[0].id, null), var.subnets_to_add]))) : ( - flatten([azurerm_subnet.subnet_mgmt[0].id, var.subnets_to_add]) + compact(flatten([azurerm_subnet.subnet_mgmt[0].id, try(azurerm_subnet.webapp[0].id, null), var.subnets_to_add, var.agent_network_id]))) : ( + flatten([azurerm_subnet.subnet_mgmt[0].id, var.subnets_to_add, var.agent_network_id]) ) )) } @@ -423,3 +423,69 @@ resource "azurerm_key_vault_secret" "subscription" { null ) } + +ephemeral "azurerm_key_vault_secret" "test" { + count = !var.key_vault.kv_exists ? (1) : (0) + + depends_on = [ + azurerm_key_vault_access_policy.kv_user_pre_deployer[0], + azurerm_key_vault_access_policy.kv_user_msi, + azurerm_key_vault_access_policy.kv_user_systemidentity + ] + + name = format("%s-subscription-id-tester", upper(var.infrastructure.environment)) + value = data.azurerm_client_config.deployer.subscription_id + key_vault_id = var.key_vault.kv_exists ? ( + var.key_vault.kv_user_id) : ( + azurerm_key_vault.kv_user[0].id + ) + + expiration_date = var.set_secret_expiry ? ( + time_offset.secret_expiry_date.rfc3339) : ( + null + ) +} +# resource "azurerm_key_vault_secret" "tenant" { +# count = !var.key_vault.kv_exists ? (1) : (0) + +# depends_on = [ +# azurerm_key_vault_access_policy.kv_user_pre_deployer[0], +# azurerm_key_vault_access_policy.kv_user_msi, +# azurerm_key_vault_access_policy.kv_user_systemidentity +# ] + +# name = format("%s-tenant-id", upper(var.infrastructure.environment)) +# value = data.azurerm_client_config.deployer.tenant_id +# key_vault_id = var.key_vault.kv_exists ? ( +# var.key_vault.kv_user_id) : ( +# azurerm_key_vault.kv_user[0].id +# ) + +# expiration_date = var.set_secret_expiry ? ( +# time_offset.secret_expiry_date.rfc3339) : ( +# null +# ) +# } + + +# resource "azurerm_key_vault_secret" "spn" { +# count = !var.key_vault.kv_exists && length(var.spn_id) > 0 ? (1) : (0) + +# depends_on = [ +# azurerm_key_vault_access_policy.kv_user_pre_deployer[0], +# azurerm_key_vault_access_policy.kv_user_msi, +# azurerm_key_vault_access_policy.kv_user_systemidentity +# ] + +# name = format("%s-client-id", upper(var.infrastructure.environment)) +# value = var.spn_id +# key_vault_id = var.key_vault.kv_exists ? ( +# var.key_vault.kv_user_id) : ( +# azurerm_key_vault.kv_user[0].id +# ) + +# expiration_date = var.set_secret_expiry ? ( +# time_offset.secret_expiry_date.rfc3339) : ( +# null +# ) +# } diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/output.tf b/deploy/terraform/terraform-units/modules/sap_deployer/output.tf index 08d7447d12..a203a69b95 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/output.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/output.tf @@ -90,7 +90,7 @@ output "deployer_user_assigned_identity" { // Details of management vnet that is deployed/imported output "vnet_mgmt_id" { description = "Management VNet ID" - value = local.vnet_mgmt_exists ? data.azurerm_virtual_network.vnet_mgmt[0].id : azurerm_virtual_network.vnet_mgmt[0].id + value = local.management_virtual_network_exists ? data.azurerm_virtual_network.vnet_mgmt[0].id : azurerm_virtual_network.vnet_mgmt[0].id } // Details of management subnet that is deployed/imported diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/templates/configure_deployer.sh.tmpl b/deploy/terraform/terraform-units/modules/sap_deployer/templates/configure_deployer.sh.tmpl index 14b5724107..147476f785 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/templates/configure_deployer.sh.tmpl +++ b/deploy/terraform/terraform-units/modules/sap_deployer/templates/configure_deployer.sh.tmpl @@ -71,7 +71,7 @@ AGENTNAME=$(hostname) # # Ansible Version settings # -ansible_version="$${ansible_version:-2.13}" +ansible_version="$${ansible_version:-2.16}" ansible_major="$${ansible_version%%.*}" ansible_minor=$(echo "$${ansible_version}." | cut -d . -f 2) @@ -315,7 +315,7 @@ else echo "we are inside ubuntu block" rel=$(lsb_release -a | grep Release | cut -d':' -f2 | xargs) if [ "$rel" == "22.04" ]; then - ansible_version="$${ansible_version:-2.15}" + ansible_version="$${ansible_version:-2.16}" ansible_major="$${ansible_version%%.*}" ansible_minor=$(echo "$${ansible_version}." | cut -d . -f 2) fi @@ -414,6 +414,7 @@ else esac # Install required packages as determined above + sleep 10 set +o errexit pkg_mgr_install "$${required_pkgs[@]}" @@ -426,7 +427,6 @@ else pkg_mgr_refresh - # Prepare Azure SAP Automated Deployment folder structure mkdir -p \ "$${asad_ws}/LOCAL/${rg_name}" \ diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/variables_global.tf b/deploy/terraform/terraform-units/modules/sap_deployer/variables_global.tf index 6ecaa95419..8567dc3204 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/variables_global.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/variables_global.tf @@ -108,4 +108,16 @@ variable "ansible_core_version" { description = "If provided, the version variable "Agent_IP" { description = "If provided, contains the IP address of the agent" } variable "spn_id" { description = "SPN ID to be used for the deployment" } + +#######################################4#######################################8 +# # +# Miscellaneous settings # +# # +#######################################4#######################################8 + variable "app_service" { description = "Details of the Application Service" } + +variable "agent_network_id" { + description = "Agent Network resource ID" + default = "" + } diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/variables_local.tf b/deploy/terraform/terraform-units/modules/sap_deployer/variables_local.tf index 63dffd5b5e..7f1bde99a5 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/variables_local.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/variables_local.tf @@ -41,10 +41,10 @@ locals { // Management vnet vnet_mgmt_arm_id = try(var.infrastructure.vnets.management.arm_id, "") - vnet_mgmt_exists = length(local.vnet_mgmt_arm_id) > 0 + management_virtual_network_exists = length(local.vnet_mgmt_arm_id) > 0 // If resource ID is specified extract the vnet name from it otherwise read it either from input of create using the naming convention - vnet_mgmt_name = local.vnet_mgmt_exists ? ( + vnet_mgmt_name = local.management_virtual_network_exists ? ( split("/", local.vnet_mgmt_arm_id)[8]) : ( length(var.infrastructure.vnets.management.name) > 0 ? ( var.infrastructure.vnets.management.name) : ( @@ -59,7 +59,7 @@ locals { ) ) - vnet_mgmt_addr = local.vnet_mgmt_exists ? "" : try(var.infrastructure.vnets.management.address_space, "") + vnet_mgmt_addr = local.management_virtual_network_exists ? "" : try(var.infrastructure.vnets.management.address_space, "") // Management subnet management_subnet_arm_id = try(var.infrastructure.vnets.management.subnet_mgmt.arm_id, "") diff --git a/deploy/terraform/terraform-units/modules/sap_deployer/vm-deployer.tf b/deploy/terraform/terraform-units/modules/sap_deployer/vm-deployer.tf index b99a2749b0..236e5e45e7 100644 --- a/deploy/terraform/terraform-units/modules/sap_deployer/vm-deployer.tf +++ b/deploy/terraform/terraform-units/modules/sap_deployer/vm-deployer.tf @@ -36,6 +36,14 @@ resource "azurerm_public_ip" "deployer" { data.azurerm_resource_group.deployer[0].location) : ( azurerm_resource_group.deployer[0].location ) + # zones = [1,2,3] - optional property. + ip_tags = var.deployer.deployer_public_ip_tags + lifecycle { + ignore_changes = [ + ip_tags + ] + create_before_destroy = true + } } resource "azurerm_network_interface" "deployer" { @@ -94,16 +102,6 @@ data "azurerm_user_assigned_identity" "deployer" { resource_group_name = split("/", var.deployer.user_assigned_identity_id)[4] } - -# // Add role to be able to deploy resources -resource "azurerm_role_assignment" "sub_contributor" { - provider = azurerm.main - count = var.assign_subscription_permissions && length(var.deployer.user_assigned_identity_id) == 0 ? 1 : 0 - scope = data.azurerm_subscription.primary.id - role_definition_name = "Reader" - principal_id = length(var.deployer.user_assigned_identity_id) == 0 ? azurerm_user_assigned_identity.deployer[0].principal_id : data.azurerm_user_assigned_identity.deployer[0].principal_id -} - // Linux Virtual Machine for Deployer resource "azurerm_linux_virtual_machine" "deployer" { count = var.deployer_vm_count diff --git a/deploy/terraform/terraform-units/modules/sap_landscape/dns.tf b/deploy/terraform/terraform-units/modules/sap_landscape/dns.tf new file mode 100644 index 0000000000..4c388445b9 --- /dev/null +++ b/deploy/terraform/terraform-units/modules/sap_landscape/dns.tf @@ -0,0 +1,245 @@ + +#######################################4#######################################8 +# # +# Network links # +# # +#######################################4#######################################8 + + +resource "azurerm_private_dns_zone_virtual_network_link" "vnet_sap" { + provider = azurerm.dnsmanagement + count = local.use_Azure_native_DNS && var.use_private_endpoint && var.dns_settings.register_virtual_network_to_dns ? 1 : 0 + depends_on = [ + azurerm_virtual_network.vnet_sap, + azurerm_subnet.app, + azurerm_key_vault.kv_user + ] + name = format("%s%s%s%s", + var.naming.resource_prefixes.dns_link, + local.prefix, + var.naming.separator, + var.naming.resource_suffixes.dns_link + ) + + resource_group_name = var.dns_settings.management_dns_resourcegroup_name + + private_dns_zone_name = var.dns_settings.dns_label + virtual_network_id = azurerm_virtual_network.vnet_sap[0].id + registration_enabled = true +} + +resource "azurerm_private_dns_zone_virtual_network_link" "vnet_sap_file" { + provider = azurerm.privatelinkdnsmanagement + count = local.use_Azure_native_DNS && var.use_private_endpoint ? 1 : 0 + depends_on = [ + azurerm_virtual_network.vnet_sap, + azurerm_subnet.app, + azurerm_key_vault.kv_user + ] + name = format("%s%s%s%s-file", + var.naming.resource_prefixes.dns_link, + local.prefix, + var.naming.separator, + var.naming.resource_suffixes.dns_link + ) + + resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name + + private_dns_zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name + virtual_network_id = azurerm_virtual_network.vnet_sap[0].id + registration_enabled = false +} + +resource "azurerm_private_dns_zone_virtual_network_link" "storage" { + provider = azurerm.privatelinkdnsmanagement + count = local.use_Azure_native_DNS && var.use_private_endpoint ? 1 : 0 + depends_on = [ + azurerm_virtual_network.vnet_sap, + azurerm_storage_account.witness_storage, + azurerm_key_vault.kv_user + ] + name = format("%s%s%s%s-blob", + var.naming.resource_prefixes.dns_link, + local.prefix, + var.naming.separator, + var.naming.resource_suffixes.dns_link + ) + + resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name + private_dns_zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name + virtual_network_id = azurerm_virtual_network.vnet_sap[0].id +} + +resource "azurerm_private_dns_zone_virtual_network_link" "vault" { + provider = azurerm.privatelinkdnsmanagement + count = local.use_Azure_native_DNS && var.use_private_endpoint ? 1 : 0 + depends_on = [ + azurerm_virtual_network.vnet_sap, + azurerm_key_vault.kv_user + ] + name = format("%s%s%s%s", + var.naming.resource_prefixes.dns_link, + local.prefix, + var.naming.separator, + "vault" + ) + resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name + private_dns_zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name + virtual_network_id = azurerm_virtual_network.vnet_sap[0].id + registration_enabled = false +} + + +# resource "azurerm_private_dns_a_record" "transport" { +# provider = azurerm.privatelinkdnsmanagement +# count = var.use_private_endpoint && var.create_transport_storage && local.use_Azure_native_DNS && local.use_AFS_for_shared && length(var.transport_private_endpoint_id) == 0 ? 1 : 0 +# name = replace( +# lower( +# format("%s", local.landscape_shared_transport_storage_account_name) +# ), +# "/[^a-z0-9]/", +# "" +# ) +# zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name +# resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +# ttl = 10 +# records = [ +# length(var.transport_private_endpoint_id) > 0 ? ( +# data.azurerm_private_endpoint_connection.transport[0].private_service_connection[0].private_ip_address) : ( +# azurerm_private_endpoint.transport[0].private_service_connection[0].private_ip_address ) +# ] +# tags = var.tags +# } + +# resource "azurerm_private_dns_a_record" "install" { +# provider = azurerm.privatelinkdnsmanagement +# count = var.use_private_endpoint && local.use_Azure_native_DNS && local.use_AFS_for_shared && length(var.install_private_endpoint_id) == 0 ? 1 : 0 +# name = replace( +# lower( +# format("%s", local.landscape_shared_install_storage_account_name) +# ), +# "/[^a-z0-9]/", +# "" +# ) +# zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name +# resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +# ttl = 10 +# records = [ +# length(var.install_private_endpoint_id) > 0 ? ( +# data.azurerm_private_endpoint_connection.install[0].private_service_connection[0].private_ip_address) : ( +# azurerm_private_endpoint.install[0].private_service_connection[0].private_ip_address) +# ] + +# lifecycle { +# ignore_changes = [tags] +# } +# } + + +#######################################4#######################################8 +# # +# DNS records # +# # +#######################################4#######################################8 + +# resource "azurerm_private_dns_a_record" "witness_storage" { +# provider = azurerm.privatelinkdnsmanagement +# count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 0 : 0 +# name = lower(local.witness_storageaccount_name) +# zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name +# resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +# ttl = 3600 +# records = [azurerm_private_endpoint.witness_storage[count.index].private_service_connection[0].private_ip_address] + +# tags = var.tags +# } + + +# resource "azurerm_private_dns_a_record" "storage_bootdiag" { +# provider = azurerm.privatelinkdnsmanagement +# count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 0 : 0 +# name = lower(local.storageaccount_name) + +# zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name +# resource_group_name = local.resource_group_exists ? ( +# data.azurerm_resource_group.resource_group[0].name) : ( +# azurerm_resource_group.resource_group[0].name +# ) +# ttl = 3600 +# records = [azurerm_private_endpoint.storage_bootdiag[count.index].private_service_connection[0].private_ip_address] +# tags = var.tags +# } + +data "azurerm_private_dns_a_record" "install" { + provider = azurerm.privatelinkdnsmanagement + count = var.use_private_endpoint && length(var.install_private_endpoint_id) > 0 ? 1 : 0 + name = replace( + lower( + format("%s", local.landscape_shared_install_storage_account_name) + ), + "/[^a-z0-9]/", + "" + ) + zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name + resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +} + +data "azurerm_private_dns_a_record" "transport" { + provider = azurerm.privatelinkdnsmanagement + count = var.create_transport_storage && var.use_private_endpoint && length(var.transport_private_endpoint_id) > 0 ? 1 : 0 + name = replace( + lower( + format("%s", local.landscape_shared_transport_storage_account_name) + ), + "/[^a-z0-9]/", + "" + ) + zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name + resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +} + +# Duplicate code, the private endpoint deployment performs the DNS registration +# resource "azurerm_private_dns_a_record" "keyvault" { +# provider = azurerm.privatelinkdnsmanagement +# count = local.use_Azure_native_DNS && var.use_private_endpoint ? 0 : 0 +# name = lower( +# format("%s", local.user_keyvault_name) +# ) +# zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name +# resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +# ttl = 10 +# records = [ +# length(var.keyvault_private_endpoint_id) > 0 ? ( +# data.azurerm_private_endpoint_connection.kv_user[0].private_service_connection[0].private_ip_address) : ( +# azurerm_private_endpoint.kv_user[0].private_service_connection[0].private_ip_address +# ) +# ] +# tags = var.tags + +# } + +#######################################4#######################################8 +# # +# DNS zones # +# # +#######################################4####################################### +data "azurerm_private_dns_zone" "file" { + provider = azurerm.privatelinkdnsmanagement + count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0 + name = var.dns_settings.dns_zone_names.file_dns_zone_name + resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +} + +data "azurerm_private_dns_zone" "storage" { + provider = azurerm.privatelinkdnsmanagement + count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0 + name = var.dns_settings.dns_zone_names.blob_dns_zone_name + resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +} + +data "azurerm_private_dns_zone" "keyvault" { + provider = azurerm.privatelinkdnsmanagement + count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0 + name = var.dns_settings.dns_zone_names.vault_dns_zone_name + resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name +} diff --git a/deploy/terraform/terraform-units/modules/sap_landscape/infrastructure.tf b/deploy/terraform/terraform-units/modules/sap_landscape/infrastructure.tf index 03696c6f19..9847e6a837 100644 --- a/deploy/terraform/terraform-units/modules/sap_landscape/infrastructure.tf +++ b/deploy/terraform/terraform-units/modules/sap_landscape/infrastructure.tf @@ -51,25 +51,13 @@ data "azurerm_virtual_network" "vnet_sap" { resource "azurerm_virtual_network_dns_servers" "vnet_sap_dns_servers" { provider = azurerm.main count = local.SAP_virtualnetwork_exists && length(var.dns_settings.dns_server_list) > 0 ? 1 : 0 - virtual_network_id = local.SAP_virtualnetwork_exists ? ( - data.azurerm_virtual_network.vnet_sap[0].id) : ( - azurerm_virtual_network.vnet_sap[0].id - ) + virtual_network_id = azurerm_virtual_network.vnet_sap[0].id dns_servers = var.dns_settings.dns_server_list } # // Peers management VNET to SAP VNET resource "azurerm_virtual_network_peering" "peering_management_sap" { provider = azurerm.peering - depends_on = [ - azurerm_subnet.app, - azurerm_subnet.db, - azurerm_subnet.web, - azurerm_subnet.admin, - azurerm_subnet.ams - - ] - count = var.peer_with_control_plane_vnet ? ( local.SAP_virtualnetwork_exists || !var.use_deployer ? 0 : 1) : ( 0 @@ -87,10 +75,7 @@ resource "azurerm_virtual_network_peering" "peering_management_sap" { ) virtual_network_name = split("/", local.deployer_virtualnetwork_id)[8] resource_group_name = split("/", local.deployer_virtualnetwork_id)[4] - remote_virtual_network_id = local.SAP_virtualnetwork_exists ? ( - data.azurerm_virtual_network.vnet_sap[0].id) : ( - azurerm_virtual_network.vnet_sap[0].id - ) + remote_virtual_network_id = azurerm_virtual_network.vnet_sap[0].id allow_virtual_network_access = true } @@ -102,14 +87,6 @@ resource "azurerm_virtual_network_peering" "peering_sap_management" { local.SAP_virtualnetwork_exists || !var.use_deployer ? 0 : 1) : ( 0 ) - depends_on = [ - azurerm_subnet.app, - azurerm_subnet.db, - azurerm_subnet.web, - azurerm_subnet.admin, - azurerm_subnet.ams - - ] name = substr( format("%s_to_%s", @@ -125,15 +102,89 @@ resource "azurerm_virtual_network_peering" "peering_sap_management" { data.azurerm_virtual_network.vnet_sap[0].resource_group_name) : ( azurerm_virtual_network.vnet_sap[0].resource_group_name ) - virtual_network_name = local.SAP_virtualnetwork_exists ? ( - data.azurerm_virtual_network.vnet_sap[0].name) : ( - azurerm_virtual_network.vnet_sap[0].name - ) + virtual_network_name = azurerm_virtual_network.vnet_sap[0].name + remote_virtual_network_id = local.deployer_virtualnetwork_id allow_virtual_network_access = true allow_forwarded_traffic = true } + +resource "azurerm_private_endpoint" "kv_user" { + provider = azurerm.main + count = (length(var.keyvault_private_endpoint_id) == 0 && + local.create_application_subnet && + var.use_private_endpoint && + local.create_workloadzone_keyvault + ) ? 1 : 0 + depends_on = [ + azurerm_private_dns_zone_virtual_network_link.vault, + azurerm_virtual_network_peering.peering_sap_management, + azurerm_virtual_network_peering.peering_management_sap + ] + + name = format("%s%s%s", + var.naming.resource_prefixes.keyvault_private_link, + length(local.prefix) > 0 ? ( + local.prefix) : ( + var.infrastructure.environment + ), + local.resource_suffixes.keyvault_private_link + ) + resource_group_name = local.resource_group_exists ? ( + data.azurerm_resource_group.resource_group[0].name) : ( + azurerm_resource_group.resource_group[0].name + ) + location = local.resource_group_exists ? ( + data.azurerm_resource_group.resource_group[0].location) : ( + azurerm_resource_group.resource_group[0].location + ) + + subnet_id = local.application_subnet_existing ? ( + var.infrastructure.vnets.sap.subnet_app.arm_id) : ( + azurerm_subnet.app[0].id + ) + + custom_network_interface_name = format("%s%s%s%s", + var.naming.resource_prefixes.keyvault_private_link, + length(local.prefix) > 0 ? ( + local.prefix) : ( + var.infrastructure.environment + ), + var.naming.resource_suffixes.keyvault_private_link, + var.naming.resource_suffixes.nic + ) + + private_service_connection { + name = format("%s%s%s", + var.naming.resource_prefixes.keyvault_private_svc, + length(local.prefix) > 0 ? ( + local.prefix) : ( + var.infrastructure.environment + ), + local.resource_suffixes.keyvault_private_svc + ) + is_manual_connection = false + private_connection_resource_id = local.user_keyvault_exist ? ( + data.azurerm_key_vault.kv_user[0].id + ) : ( + azurerm_key_vault.kv_user[0].id + ) + subresource_names = [ + "Vault" + ] + } + + dynamic "private_dns_zone_group" { + for_each = range(var.dns_settings.register_endpoints_with_dns ? 1 : 0) + content { + name = var.dns_settings.dns_zone_names.vault_dns_zone_name + private_dns_zone_ids = [data.azurerm_private_dns_zone.keyvault[0].id] + } + } +} + + //Route table resource "azurerm_route_table" "rt" { provider = azurerm.main @@ -148,14 +199,9 @@ resource "azurerm_route_table" "rt" { local.resource_suffixes.routetable ) bgp_route_propagation_enabled = local.network_enable_route_propagation - resource_group_name = local.SAP_virtualnetwork_exists ? ( - data.azurerm_virtual_network.vnet_sap[0].resource_group_name) : ( - azurerm_virtual_network.vnet_sap[0].resource_group_name - ) - location = local.SAP_virtualnetwork_exists ? ( - data.azurerm_virtual_network.vnet_sap[0].location) : ( - azurerm_virtual_network.vnet_sap[0].location - ) + resource_group_name = azurerm_virtual_network.vnet_sap[0].resource_group_name + location = azurerm_virtual_network.vnet_sap[0].location + tags = var.tags } @@ -182,78 +228,6 @@ resource "azurerm_route" "admin" { } -resource "azurerm_private_dns_zone_virtual_network_link" "vnet_sap" { - provider = azurerm.dnsmanagement - count = local.use_Azure_native_DNS && var.use_private_endpoint && var.dns_settings.register_virtual_network_to_dns ? 1 : 0 - depends_on = [ - azurerm_virtual_network.vnet_sap - ] - name = format("%s%s%s%s", - var.naming.resource_prefixes.dns_link, - local.prefix, - var.naming.separator, - var.naming.resource_suffixes.dns_link - ) - - resource_group_name = var.dns_settings.management_dns_resourcegroup_name - - private_dns_zone_name = var.dns_settings.dns_label - virtual_network_id = azurerm_virtual_network.vnet_sap[0].id - registration_enabled = true -} - -resource "azurerm_private_dns_zone_virtual_network_link" "vnet_sap_file" { - provider = azurerm.privatelinkdnsmanagement - count = local.use_Azure_native_DNS && var.use_private_endpoint ? 1 : 0 - depends_on = [ - azurerm_virtual_network.vnet_sap - ] - name = format("%s%s%s%s-file", - var.naming.resource_prefixes.dns_link, - local.prefix, - var.naming.separator, - var.naming.resource_suffixes.dns_link - ) - - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name - - private_dns_zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name - virtual_network_id = azurerm_virtual_network.vnet_sap[0].id - registration_enabled = false -} - -data "azurerm_private_dns_zone" "file" { - provider = azurerm.privatelinkdnsmanagement - count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0 - name = var.dns_settings.dns_zone_names.file_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name -} - -resource "azurerm_private_dns_zone_virtual_network_link" "storage" { - provider = azurerm.privatelinkdnsmanagement - count = local.use_Azure_native_DNS && var.use_private_endpoint ? 1 : 0 - depends_on = [ - azurerm_virtual_network.vnet_sap - ] - name = format("%s%s%s%s-blob", - var.naming.resource_prefixes.dns_link, - local.prefix, - var.naming.separator, - var.naming.resource_suffixes.dns_link - ) - - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name - private_dns_zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name - virtual_network_id = azurerm_virtual_network.vnet_sap[0].id -} - -data "azurerm_private_dns_zone" "storage" { - provider = azurerm.privatelinkdnsmanagement - count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0 - name = var.dns_settings.dns_zone_names.blob_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name -} - resource "azurerm_management_lock" "vnet_sap" { provider = azurerm.main count = (local.SAP_virtualnetwork_exists) ? 0 : var.place_delete_lock_on_resources ? 1 : 0 @@ -266,3 +240,54 @@ resource "azurerm_management_lock" "vnet_sap" { } } +# // Peers management VNET to SAP VNET +resource "azurerm_virtual_network_peering" "peering_agent_sap" { + provider = azurerm.peering + count = length(var.agent_network_id) > 0 ? 1:0 + name = substr( + format("%s_to_%s", + split("/", var.agent_network_id)[8], + local.SAP_virtualnetwork_exists ? ( + data.azurerm_virtual_network.vnet_sap[0].name) : ( + azurerm_virtual_network.vnet_sap[0].name + ) + ), + 0, + 80 + ) + virtual_network_name = split("/", var.agent_network_id)[8] + resource_group_name = split("/", var.agent_network_id)[4] + remote_virtual_network_id = local.SAP_virtualnetwork_exists ? ( + data.azurerm_virtual_network.vnet_sap[0].id) : ( + azurerm_virtual_network.vnet_sap[0].id + ) + + allow_virtual_network_access = true +} + +// Peers SAP VNET to management VNET +resource "azurerm_virtual_network_peering" "peering_sap_agent" { + provider = azurerm.main + count = length(var.agent_network_id) > 0 ? 1:0 + name = substr( + format("%s_to_%s", + local.SAP_virtualnetwork_exists ? ( + data.azurerm_virtual_network.vnet_sap[0].name) : ( + azurerm_virtual_network.vnet_sap[0].name + ), split("/", var.agent_network_id)[8] + ), + 0, + 80 + ) + resource_group_name = local.SAP_virtualnetwork_exists ? ( + data.azurerm_virtual_network.vnet_sap[0].resource_group_name) : ( + azurerm_virtual_network.vnet_sap[0].resource_group_name + ) + virtual_network_name = local.SAP_virtualnetwork_exists ? ( + data.azurerm_virtual_network.vnet_sap[0].name) : ( + azurerm_virtual_network.vnet_sap[0].name + ) + remote_virtual_network_id = var.agent_network_id + allow_virtual_network_access = true + allow_forwarded_traffic = true +} diff --git a/deploy/terraform/terraform-units/modules/sap_landscape/iscsi.tf b/deploy/terraform/terraform-units/modules/sap_landscape/iscsi.tf index 4d1786032b..0427838b88 100644 --- a/deploy/terraform/terraform-units/modules/sap_landscape/iscsi.tf +++ b/deploy/terraform/terraform-units/modules/sap_landscape/iscsi.tf @@ -253,12 +253,13 @@ data "template_cloudinit_config" "config_growpart" { resource "azurerm_key_vault_secret" "iscsi_ppk" { provider = azurerm.main - count = (local.enable_landscape_kv && local.enable_iscsi_auth_key && !local.iscsi_key_exist) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi_auth_key && !local.iscsi_key_exist) ? 1 : 0 depends_on = [ azurerm_key_vault_access_policy.kv_user, azurerm_role_assignment.role_assignment_spn, azurerm_role_assignment.role_assignment_msi, - azurerm_key_vault_access_policy.kv_user_msi + azurerm_key_vault_access_policy.kv_user_msi, + azurerm_private_endpoint.kv_user ] content_type = "" name = local.iscsi_ppk_name @@ -273,12 +274,13 @@ resource "azurerm_key_vault_secret" "iscsi_ppk" { resource "azurerm_key_vault_secret" "iscsi_pk" { provider = azurerm.main - count = (local.enable_landscape_kv && local.enable_iscsi_auth_key && !local.iscsi_key_exist) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi_auth_key && !local.iscsi_key_exist) ? 1 : 0 depends_on = [ azurerm_key_vault_access_policy.kv_user, azurerm_role_assignment.role_assignment_spn, azurerm_role_assignment.role_assignment_msi, - azurerm_key_vault_access_policy.kv_user_msi + azurerm_key_vault_access_policy.kv_user_msi, + azurerm_private_endpoint.kv_user ] content_type = "" name = local.iscsi_pk_name @@ -292,12 +294,13 @@ resource "azurerm_key_vault_secret" "iscsi_pk" { resource "azurerm_key_vault_secret" "iscsi_username" { provider = azurerm.main - count = (local.enable_landscape_kv && local.enable_iscsi && !local.iscsi_username_exist) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi && !local.iscsi_username_exist) ? 1 : 0 depends_on = [ azurerm_key_vault_access_policy.kv_user, azurerm_role_assignment.role_assignment_spn, azurerm_role_assignment.role_assignment_msi, - azurerm_key_vault_access_policy.kv_user_msi + azurerm_key_vault_access_policy.kv_user_msi, + azurerm_private_endpoint.kv_user ] content_type = "" name = local.iscsi_username_name @@ -311,12 +314,13 @@ resource "azurerm_key_vault_secret" "iscsi_username" { resource "azurerm_key_vault_secret" "iscsi_password" { provider = azurerm.main - count = (local.enable_landscape_kv && local.enable_iscsi_auth_password && !local.iscsi_pwd_exist) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi_auth_password && !local.iscsi_pwd_exist) ? 1 : 0 depends_on = [ azurerm_key_vault_access_policy.kv_user, azurerm_role_assignment.role_assignment_spn, azurerm_role_assignment.role_assignment_msi, - azurerm_key_vault_access_policy.kv_user_msi + azurerm_key_vault_access_policy.kv_user_msi, + azurerm_private_endpoint.kv_user ] content_type = "" name = local.iscsi_pwd_name @@ -330,7 +334,7 @@ resource "azurerm_key_vault_secret" "iscsi_password" { // Generate random password if password is set as authentication type and user doesn't specify a password, and save in KV resource "random_password" "iscsi_password" { - count = (local.enable_landscape_kv && local.enable_iscsi_auth_password && !local.iscsi_pwd_exist && try(var.authentication.password, null) == null) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi_auth_password && !local.iscsi_pwd_exist && try(var.authentication.password, null) == null) ? 1 : 0 length = 32 min_upper = 2 min_lower = 2 @@ -342,28 +346,28 @@ resource "random_password" "iscsi_password" { // Import secrets about iSCSI data "azurerm_key_vault_secret" "iscsi_pk" { provider = azurerm.main - count = (local.enable_landscape_kv && local.enable_iscsi_auth_key && local.iscsi_key_exist) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi_auth_key && local.iscsi_key_exist) ? 1 : 0 name = local.iscsi_pk_name key_vault_id = local.user_key_vault_id } data "azurerm_key_vault_secret" "iscsi_ppk" { provider = azurerm.main - count = (local.enable_landscape_kv && local.enable_iscsi_auth_key && local.iscsi_key_exist) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi_auth_key && local.iscsi_key_exist) ? 1 : 0 name = local.iscsi_ppk_name key_vault_id = local.user_key_vault_id } data "azurerm_key_vault_secret" "iscsi_password" { provider = azurerm.main - count = (local.enable_landscape_kv && local.enable_iscsi_auth_password && local.iscsi_pwd_exist) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi_auth_password && local.iscsi_pwd_exist) ? 1 : 0 name = local.iscsi_pwd_name key_vault_id = local.user_key_vault_id } data "azurerm_key_vault_secret" "iscsi_username" { provider = azurerm.main - count = (local.enable_landscape_kv && local.enable_iscsi && local.iscsi_username_exist) ? 1 : 0 + count = (local.create_workloadzone_keyvault && local.enable_iscsi && local.iscsi_username_exist) ? 1 : 0 name = local.iscsi_username_name key_vault_id = local.user_key_vault_id } @@ -371,7 +375,7 @@ data "azurerm_key_vault_secret" "iscsi_username" { // Using TF tls to generate SSH key pair for iscsi devices and store in user KV resource "tls_private_key" "iscsi" { count = ( - local.enable_landscape_kv + local.create_workloadzone_keyvault && local.enable_iscsi_auth_key && !local.iscsi_key_exist && try(file(var.authentication.path_to_public_key), null) == null diff --git a/deploy/terraform/terraform-units/modules/sap_landscape/key_vault_sap_landscape.tf b/deploy/terraform/terraform-units/modules/sap_landscape/key_vault_sap_landscape.tf index 7fe898cfaf..048f169f23 100644 --- a/deploy/terraform/terraform-units/modules/sap_landscape/key_vault_sap_landscape.tf +++ b/deploy/terraform/terraform-units/modules/sap_landscape/key_vault_sap_landscape.tf @@ -13,7 +13,9 @@ resource "azurerm_key_vault" "kv_user" { count = (var.key_vault.exists) ? 0 : 1 depends_on = [ azurerm_virtual_network_peering.peering_management_sap, - azurerm_virtual_network_peering.peering_sap_management + azurerm_virtual_network_peering.peering_sap_management, + azurerm_virtual_network_peering.peering_agent_sap, + azurerm_virtual_network_peering.peering_sap_agent, ] name = local.user_keyvault_name location = local.region @@ -31,7 +33,7 @@ resource "azurerm_key_vault" "kv_user" { tags = var.tags dynamic "network_acls" { - for_each = range(var.enable_firewall_for_keyvaults_and_storage ? 1 : 0) + for_each = range(var.enable_firewall_for_keyvaults_and_storage ? 1 : 0) content { bypass = "AzureServices" @@ -53,7 +55,8 @@ resource "azurerm_key_vault" "kv_user" { local.application_subnet_existing ? var.infrastructure.vnets.sap.subnet_app.arm_id : azurerm_subnet.app[0].id) : ( "" ), - local.deployer_subnet_management_id + local.deployer_subnet_management_id, + var.agent_network_id ] ) } @@ -75,6 +78,27 @@ data "azurerm_key_vault" "kv_user" { resource_group_name = local.user_keyvault_resourcegroup_name } + +resource "azurerm_management_lock" "keyvault" { + provider = azurerm.main + count = var.key_vault.exists ? 0 : var.place_delete_lock_on_resources ? 1 : 0 + name = format("%s-lock", local.user_keyvault_name) + scope = azurerm_key_vault.kv_user[0].id + lock_level = "CanNotDelete" + notes = "Locked because it's needed by the Workload zone" + + lifecycle { + prevent_destroy = false + } +} + +#######################################4#######################################8 +# # +# Workload zone key vault role assignments # +# # +#######################################4#######################################8 + + resource "azurerm_role_assignment" "role_assignment_msi" { provider = azurerm.main count = var.enable_rbac_authorization_for_keyvault ? 1 : 0 @@ -117,10 +141,10 @@ resource "azurerm_key_vault_access_policy" "kv_user" { resource "azurerm_key_vault_access_policy" "kv_user_spn" { provider = azurerm.main - count = var.options.use_spn ? 1 : 0 - key_vault_id = local.user_keyvault_exist ? local.user_key_vault_id : azurerm_key_vault.kv_user[0].id - tenant_id = data.azuread_client_config.current.tenant_id - object_id = data.azuread_client_config.current.object_id + count = var.service_principal.exists ? 1 : 0 + key_vault_id = local.user_keyvault_exist ? data.azurerm_key_vault.kv_user[0].id : azurerm_key_vault.kv_user[0].id + tenant_id = var.service_principal.tenant_id + object_id = var.service_principal.object_id secret_permissions = [ "Get", @@ -134,6 +158,37 @@ resource "azurerm_key_vault_access_policy" "kv_user_spn" { } +resource "azurerm_key_vault_access_policy" "kv_user_msi" { + provider = azurerm.main + count = local.user_keyvault_exist && var.enable_rbac_authorization_for_keyvault ? ( + 0) : ( + length(var.deployer_tfstate) > 0 ? ( + length(var.deployer_tfstate.deployer_uai) == 2 ? ( + 1) : ( + 0 + )) : ( + 0 + ) + ) + key_vault_id = local.user_keyvault_exist ? ( + local.user_key_vault_id) : ( + azurerm_key_vault.kv_user[0].id + ) + + tenant_id = var.deployer_tfstate.deployer_uai.tenant_id + object_id = var.deployer_tfstate.deployer_uai.principal_id + + secret_permissions = [ + "Get", + "List", + "Set", + "Delete", + "Recover", + "Restore", + "Purge" + ] +} + ############################################################################### # # # Secrets # @@ -162,18 +217,19 @@ resource "time_offset" "secret_expiry_date" { // Key pair/password will be stored in the existing KV if specified, otherwise will be stored in a newly provisioned KV resource "azurerm_key_vault_secret" "sid_ppk" { provider = azurerm.main - count = !local.sid_key_exist ? 1 : 0 depends_on = [ - azurerm_key_vault_access_policy.kv_user, - azurerm_role_assignment.role_assignment_spn, - azurerm_role_assignment.role_assignment_msi, + azurerm_key_vault_access_policy.kv_user_spn, azurerm_key_vault_access_policy.kv_user_msi, - azurerm_key_vault_access_policy.kv_user_spn + azurerm_private_endpoint.kv_user ] + count = !local.sid_key_exist ? 1 : 0 content_type = "" name = local.sid_ppk_name value = local.sid_private_key - key_vault_id = local.user_keyvault_exist ? local.user_key_vault_id : azurerm_key_vault.kv_user[0].id + key_vault_id = local.user_keyvault_exist ? ( + data.azurerm_key_vault.kv_user[0].id) : ( + azurerm_key_vault.kv_user[0].id + ) expiration_date = var.key_vault.set_secret_expiry ? ( time_offset.secret_expiry_date.rfc3339) : ( null @@ -189,19 +245,17 @@ data "azurerm_key_vault_secret" "sid_ppk" { resource "azurerm_key_vault_secret" "sid_pk" { provider = azurerm.main - count = !local.sid_key_exist ? 1 : 0 depends_on = [ - azurerm_key_vault_access_policy.kv_user, - azurerm_role_assignment.role_assignment_spn, - azurerm_role_assignment.role_assignment_msi, + azurerm_key_vault_access_policy.kv_user_spn, azurerm_key_vault_access_policy.kv_user_msi, - azurerm_key_vault_access_policy.kv_user_spn + azurerm_private_endpoint.kv_user ] + count = !local.sid_key_exist ? 1 : 0 content_type = "" name = local.sid_pk_name value = local.sid_public_key key_vault_id = local.user_keyvault_exist ? ( - local.user_key_vault_id) : ( + data.azurerm_key_vault.kv_user[0].id) : ( azurerm_key_vault.kv_user[0].id ) expiration_date = var.key_vault.set_secret_expiry ? ( @@ -212,6 +266,11 @@ resource "azurerm_key_vault_secret" "sid_pk" { data "azurerm_key_vault_secret" "sid_pk" { provider = azurerm.main + depends_on = [ + azurerm_key_vault_access_policy.kv_user_spn, + azurerm_key_vault_access_policy.kv_user_msi, + azurerm_private_endpoint.kv_user + ] count = (local.sid_key_exist) ? 1 : 0 name = local.sid_pk_name key_vault_id = local.user_key_vault_id @@ -221,19 +280,17 @@ data "azurerm_key_vault_secret" "sid_pk" { // Credentials will be stored in the existing KV if specified, otherwise will be stored in a newly provisioned KV resource "azurerm_key_vault_secret" "sid_username" { provider = azurerm.main - count = (!local.sid_credentials_secret_exist) ? 1 : 0 depends_on = [ - azurerm_key_vault_access_policy.kv_user, - azurerm_role_assignment.role_assignment_spn, - azurerm_role_assignment.role_assignment_msi, + azurerm_key_vault_access_policy.kv_user_spn, azurerm_key_vault_access_policy.kv_user_msi, - azurerm_key_vault_access_policy.kv_user_spn - ] + azurerm_private_endpoint.kv_user + ] + count = (!local.sid_credentials_secret_exist) ? 1 : 0 content_type = "" name = local.sid_username_secret_name value = local.input_sid_username key_vault_id = local.user_keyvault_exist ? ( - local.user_key_vault_id) : ( + data.azurerm_key_vault.kv_user[0].id) : ( azurerm_key_vault.kv_user[0].id ) expiration_date = var.key_vault.set_secret_expiry ? ( @@ -244,6 +301,11 @@ resource "azurerm_key_vault_secret" "sid_username" { data "azurerm_key_vault_secret" "sid_username" { provider = azurerm.main + depends_on = [ + azurerm_key_vault_access_policy.kv_user_spn, + azurerm_key_vault_access_policy.kv_user_msi, + azurerm_private_endpoint.kv_user + ] count = (local.sid_credentials_secret_exist) ? 1 : 0 name = local.sid_username_secret_name key_vault_id = local.user_key_vault_id @@ -251,19 +313,17 @@ data "azurerm_key_vault_secret" "sid_username" { resource "azurerm_key_vault_secret" "sid_password" { provider = azurerm.main - count = (!local.sid_credentials_secret_exist) ? 1 : 0 depends_on = [ - azurerm_key_vault_access_policy.kv_user, - azurerm_role_assignment.role_assignment_spn, - azurerm_role_assignment.role_assignment_msi, + azurerm_key_vault_access_policy.kv_user_spn, azurerm_key_vault_access_policy.kv_user_msi, - azurerm_key_vault_access_policy.kv_user_spn + azurerm_private_endpoint.kv_user ] + count = (!local.sid_credentials_secret_exist) ? 1 : 0 name = local.sid_password_secret_name content_type = "" value = local.input_sid_password key_vault_id = local.user_keyvault_exist ? ( - local.user_key_vault_id) : ( + data.azurerm_key_vault.kv_user[0].id) : ( azurerm_key_vault.kv_user[0].id ) expiration_date = var.key_vault.set_secret_expiry ? ( @@ -274,6 +334,11 @@ resource "azurerm_key_vault_secret" "sid_password" { data "azurerm_key_vault_secret" "sid_password" { provider = azurerm.main + depends_on = [ + azurerm_key_vault_access_policy.kv_user_spn, + azurerm_key_vault_access_policy.kv_user_msi, + azurerm_private_endpoint.kv_user + ] count = (local.sid_credentials_secret_exist) ? 1 : 0 name = local.sid_password_secret_name key_vault_id = local.user_key_vault_id @@ -283,14 +348,12 @@ data "azurerm_key_vault_secret" "sid_password" { //Witness access key resource "azurerm_key_vault_secret" "witness_access_key" { provider = azurerm.main - count = 1 depends_on = [ - azurerm_key_vault_access_policy.kv_user, - azurerm_role_assignment.role_assignment_spn, - azurerm_role_assignment.role_assignment_msi, + azurerm_key_vault_access_policy.kv_user_spn, azurerm_key_vault_access_policy.kv_user_msi, - azurerm_key_vault_access_policy.kv_user_spn + azurerm_private_endpoint.kv_user ] + count = 1 content_type = "" name = replace( format("%s%s%s", @@ -309,7 +372,7 @@ resource "azurerm_key_vault_secret" "witness_access_key" { azurerm_storage_account.witness_storage[0].primary_access_key ) key_vault_id = local.user_keyvault_exist ? ( - local.user_key_vault_id) : ( + data.azurerm_key_vault.kv_user[0].id) : ( azurerm_key_vault.kv_user[0].id ) expiration_date = var.key_vault.set_secret_expiry ? ( @@ -321,14 +384,12 @@ resource "azurerm_key_vault_secret" "witness_access_key" { //Witness access key resource "azurerm_key_vault_secret" "witness_name" { provider = azurerm.main - count = 1 depends_on = [ - azurerm_key_vault_access_policy.kv_user, - azurerm_role_assignment.role_assignment_spn, - azurerm_role_assignment.role_assignment_msi, + azurerm_key_vault_access_policy.kv_user_spn, azurerm_key_vault_access_policy.kv_user_msi, - azurerm_key_vault_access_policy.kv_user_spn + azurerm_private_endpoint.kv_user ] + count = 1 content_type = "" name = replace( format("%s%s%s", @@ -347,7 +408,7 @@ resource "azurerm_key_vault_secret" "witness_name" { azurerm_storage_account.witness_storage[0].name ) key_vault_id = local.user_keyvault_exist ? ( - local.user_key_vault_id) : ( + data.azurerm_key_vault.kv_user[0].id) : ( azurerm_key_vault.kv_user[0].id ) expiration_date = var.key_vault.set_secret_expiry ? ( @@ -356,52 +417,19 @@ resource "azurerm_key_vault_secret" "witness_name" { ) } -resource "azurerm_key_vault_access_policy" "kv_user_msi" { - provider = azurerm.main - count = local.user_keyvault_exist && var.enable_rbac_authorization_for_keyvault ? ( - 0) : ( - length(var.deployer_tfstate) > 0 ? ( - length(var.deployer_tfstate.deployer_uai) == 2 ? ( - 1) : ( - 0 - )) : ( - 0 - ) - ) - key_vault_id = local.user_keyvault_exist ? ( - local.user_key_vault_id) : ( - azurerm_key_vault.kv_user[0].id - ) - - tenant_id = var.deployer_tfstate.deployer_uai.tenant_id - object_id = var.deployer_tfstate.deployer_uai.principal_id - - secret_permissions = [ - "Get", - "List", - "Set", - "Delete", - "Recover", - "Restore", - "Purge" - ] -} - //Witness access key resource "azurerm_key_vault_secret" "deployer_keyvault_user_name" { provider = azurerm.main depends_on = [ - azurerm_key_vault_access_policy.kv_user, - azurerm_role_assignment.role_assignment_spn, - azurerm_role_assignment.role_assignment_msi, + azurerm_key_vault_access_policy.kv_user_spn, azurerm_key_vault_access_policy.kv_user_msi, - azurerm_key_vault_access_policy.kv_user_spn + azurerm_private_endpoint.kv_user ] content_type = "" name = "deployer-kv-name" value = local.deployer_keyvault_user_name key_vault_id = local.user_keyvault_exist ? ( - local.user_key_vault_id) : ( + data.azurerm_key_vault.kv_user[0].id) : ( azurerm_key_vault.kv_user[0].id ) expiration_date = var.key_vault.set_secret_expiry ? ( @@ -421,137 +449,6 @@ data "azurerm_private_endpoint_connection" "kv_user" { resource_group_name = split("/", var.keyvault_private_endpoint_id)[4] } - -resource "azurerm_private_endpoint" "kv_user" { - provider = azurerm.main - count = (length(var.keyvault_private_endpoint_id) == 0 && - local.application_subnet_defined && - var.use_private_endpoint && - local.enable_landscape_kv && - !local.user_keyvault_exist - ) ? 1 : 0 - depends_on = [ - azurerm_key_vault_access_policy.kv_user_msi, - azurerm_key_vault_access_policy.kv_user, - azurerm_private_dns_zone_virtual_network_link.vault, - azurerm_key_vault_secret.sid_ppk, - azurerm_key_vault_secret.sid_pk, - azurerm_key_vault_secret.sid_username, - azurerm_key_vault_secret.deployer_keyvault_user_name, - azurerm_key_vault_secret.witness_name, - azurerm_key_vault_secret.witness_access_key, - azurerm_key_vault_secret.sid_password, - azurerm_key_vault_secret.sid_username - ] - - name = format("%s%s%s", - var.naming.resource_prefixes.keyvault_private_link, - length(local.prefix) > 0 ? ( - local.prefix) : ( - var.infrastructure.environment - ), - local.resource_suffixes.keyvault_private_link - ) - resource_group_name = local.resource_group_exists ? ( - data.azurerm_resource_group.resource_group[0].name) : ( - azurerm_resource_group.resource_group[0].name - ) - location = local.resource_group_exists ? ( - data.azurerm_resource_group.resource_group[0].location) : ( - azurerm_resource_group.resource_group[0].location - ) - - subnet_id = local.application_subnet_existing ? ( - var.infrastructure.vnets.sap.subnet_app.arm_id) : ( - azurerm_subnet.app[0].id - ) - - custom_network_interface_name = format("%s%s%s%s", - var.naming.resource_prefixes.keyvault_private_link, - length(local.prefix) > 0 ? ( - local.prefix) : ( - var.infrastructure.environment - ), - var.naming.resource_suffixes.keyvault_private_link, - var.naming.resource_suffixes.nic - ) - - private_service_connection { - name = format("%s%s%s", - var.naming.resource_prefixes.keyvault_private_svc, - length(local.prefix) > 0 ? ( - local.prefix) : ( - var.infrastructure.environment - ), - local.resource_suffixes.keyvault_private_svc - ) - is_manual_connection = false - private_connection_resource_id = local.user_keyvault_exist ? ( - data.azurerm_key_vault.kv_user[0].id - ) : ( - azurerm_key_vault.kv_user[0].id - ) - subresource_names = [ - "Vault" - ] - } - - dynamic "private_dns_zone_group" { - for_each = range(var.dns_settings.register_endpoints_with_dns ? 1 : 0) - content { - name = var.dns_settings.dns_zone_names.vault_dns_zone_name - private_dns_zone_ids = [data.azurerm_private_dns_zone.keyvault[0].id] - } - } -} - - -data "azurerm_private_dns_zone" "keyvault" { - provider = azurerm.privatelinkdnsmanagement - count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0 - name = var.dns_settings.dns_zone_names.vault_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name -} - -resource "azurerm_private_dns_a_record" "keyvault" { - provider = azurerm.privatelinkdnsmanagement - count = local.use_Azure_native_DNS && var.use_private_endpoint ? 1 : 0 - name = lower( - format("%s", local.user_keyvault_name) - ) - zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name - ttl = 10 - records = [ - length(var.keyvault_private_endpoint_id) > 0 ? ( - data.azurerm_private_endpoint_connection.kv_user[0].private_service_connection[0].private_ip_address) : ( - azurerm_private_endpoint.kv_user[0].private_service_connection[0].private_ip_address - ) - ] - tags = var.tags - -} - - -resource "azurerm_private_dns_zone_virtual_network_link" "vault" { - provider = azurerm.privatelinkdnsmanagement - count = local.use_Azure_native_DNS && var.use_private_endpoint ? 1 : 0 - depends_on = [ - azurerm_virtual_network.vnet_sap - ] - name = format("%s%s%s%s", - var.naming.resource_prefixes.dns_link, - local.prefix, - var.naming.separator, - "vault" - ) - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name - private_dns_zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name - virtual_network_id = azurerm_virtual_network.vnet_sap[0].id - registration_enabled = false -} - - ############################################################################### # # # Additional Users # @@ -569,11 +466,10 @@ resource "azurerm_key_vault_access_policy" "kv_user_additional_users" { ) key_vault_id = local.user_keyvault_exist ? ( - local.user_key_vault_id) : ( + data.azurerm_key_vault.kv_user[0].id) : ( azurerm_key_vault.kv_user[0].id ) - tenant_id = local.service_principal.tenant_id object_id = var.additional_users_to_add_to_keyvault_policies[count.index] secret_permissions = [ @@ -599,16 +495,3 @@ resource "azurerm_role_assignment" "kv_user_additional_users" { role_definition_name = "Key Vault Secrets Officer" principal_id = var.additional_users_to_add_to_keyvault_policies[count.index] } - -resource "azurerm_management_lock" "keyvault" { - provider = azurerm.main - count = var.key_vault.exists ? 0 : var.place_delete_lock_on_resources ? 1 : 0 - name = format("%s-lock", local.user_keyvault_name) - scope = azurerm_key_vault.kv_user[0].id - lock_level = "CanNotDelete" - notes = "Locked because it's needed by the Control Plane" - - lifecycle { - prevent_destroy = false - } -} diff --git a/deploy/terraform/terraform-units/modules/sap_landscape/storage_accounts.tf b/deploy/terraform/terraform-units/modules/sap_landscape/storage_accounts.tf index 87f2ee6a07..ece951cb26 100644 --- a/deploy/terraform/terraform-units/modules/sap_landscape/storage_accounts.tf +++ b/deploy/terraform/terraform-units/modules/sap_landscape/storage_accounts.tf @@ -25,7 +25,8 @@ resource "azurerm_storage_account" "storage_bootdiag" { account_replication_type = "LRS" account_tier = "Standard" - https_traffic_only_enabled = true + https_traffic_only_enabled = true + min_tls_version = "TLS1_2" allow_nested_items_to_be_public = false cross_tenant_replication_enabled = false @@ -34,21 +35,6 @@ resource "azurerm_storage_account" "storage_bootdiag" { } -resource "azurerm_private_dns_a_record" "storage_bootdiag" { - provider = azurerm.privatelinkdnsmanagement - count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 0 : 0 - name = lower(local.storageaccount_name) - - zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name - resource_group_name = local.resource_group_exists ? ( - data.azurerm_resource_group.resource_group[0].name) : ( - azurerm_resource_group.resource_group[0].name - ) - ttl = 3600 - records = [azurerm_private_endpoint.storage_bootdiag[count.index].private_service_connection[0].private_ip_address] - tags = var.tags -} - data "azurerm_storage_account" "storage_bootdiag" { provider = azurerm.main count = length(var.diagnostics_storage_account.arm_id) > 0 ? 1 : 0 @@ -153,7 +139,7 @@ resource "azurerm_storage_account" "witness_storage" { tags = var.tags network_rules { default_action = var.enable_firewall_for_keyvaults_and_storage ? "Deny" : "Allow" - virtual_network_subnet_ids = compact([ + virtual_network_subnet_ids = var.public_network_access_enabled ? compact([ local.database_subnet_defined ? ( local.database_subnet_existing ? var.infrastructure.vnets.sap.subnet_db.arm_id : azurerm_subnet.db[0].id) : ( null @@ -161,32 +147,19 @@ resource "azurerm_storage_account" "witness_storage" { local.application_subnet_existing ? var.infrastructure.vnets.sap.subnet_app.arm_id : azurerm_subnet.app[0].id) : ( null ), - length(local.deployer_subnet_management_id) > 0 ? local.deployer_subnet_management_id : null + length(local.deployer_subnet_management_id) > 0 ? local.deployer_subnet_management_id : null, + length(var.agent_network_id) > 0 ? var.agent_network_id : null ] - ) - ip_rules = compact([ + ) : null + ip_rules = var.public_network_access_enabled ? compact([ length(local.deployer_public_ip_address) > 0 ? local.deployer_public_ip_address : "", length(var.Agent_IP) > 0 ? var.Agent_IP : "" - ]) + ]) : null } } - -resource "azurerm_private_dns_a_record" "witness_storage" { - provider = azurerm.privatelinkdnsmanagement - count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 0 : 0 - name = lower(local.witness_storageaccount_name) - zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name - ttl = 3600 - records = [azurerm_private_endpoint.witness_storage[count.index].private_service_connection[0].private_ip_address] - - tags = var.tags - -} - data "azurerm_storage_account" "witness_storage" { provider = azurerm.main count = length(var.witness_storage_account.arm_id) > 0 ? 1 : 0 @@ -303,7 +276,7 @@ resource "azurerm_storage_account" "transport" { network_rules { default_action = var.enable_firewall_for_keyvaults_and_storage ? "Deny" : "Allow" - virtual_network_subnet_ids = compact([ + virtual_network_subnet_ids = var.public_network_access_enabled ? compact([ local.database_subnet_defined ? ( local.database_subnet_existing ? var.infrastructure.vnets.sap.subnet_db.arm_id : azurerm_subnet.db[0].id) : ( null @@ -311,55 +284,21 @@ resource "azurerm_storage_account" "transport" { local.application_subnet_existing ? var.infrastructure.vnets.sap.subnet_app.arm_id : azurerm_subnet.app[0].id) : ( null ), - length(local.deployer_subnet_management_id) > 0 ? local.deployer_subnet_management_id : null + length(local.deployer_subnet_management_id) > 0 ? local.deployer_subnet_management_id : null, + length(var.agent_network_id) > 0 ? var.agent_network_id : null ] - ) - ip_rules = compact([ + ) : null + ip_rules = var.public_network_access_enabled ? compact([ length(local.deployer_public_ip_address) > 0 ? local.deployer_public_ip_address : "", length(var.Agent_IP) > 0 ? var.Agent_IP : "" - ]) + ]) : null } - tags = var.tags - -} -resource "azurerm_private_dns_a_record" "transport" { - provider = azurerm.privatelinkdnsmanagement - count = var.use_private_endpoint && var.create_transport_storage && local.use_Azure_native_DNS && local.use_AFS_for_shared && length(var.transport_private_endpoint_id) == 0 ? 1 : 0 - name = replace( - lower( - format("%s", local.landscape_shared_transport_storage_account_name) - ), - "/[^a-z0-9]/", - "" - ) - zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name - ttl = 10 - records = [ - length(var.transport_private_endpoint_id) > 0 ? ( - data.azurerm_private_endpoint_connection.transport[0].private_service_connection[0].private_ip_address) : ( - azurerm_private_endpoint.transport[0].private_service_connection[0].private_ip_address ) - ] tags = var.tags -} -data "azurerm_private_dns_a_record" "transport" { - provider = azurerm.privatelinkdnsmanagement - count = var.create_transport_storage && var.use_private_endpoint && length(var.transport_private_endpoint_id) > 0 ? 1 : 0 - name = replace( - lower( - format("%s", local.landscape_shared_transport_storage_account_name) - ), - "/[^a-z0-9]/", - "" - ) - zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name } - resource "azurerm_storage_share" "transport" { provider = azurerm.main count = var.create_transport_storage && local.use_AFS_for_shared ? ( @@ -371,7 +310,7 @@ resource "azurerm_storage_share" "transport" { ) name = format("%s", local.resource_suffixes.transport_volume) - storage_account_id = var.data_plane_available ? null : length(var.transport_storage_account_id) > 0 ? ( + storage_account_id = length(var.transport_storage_account_id) > 0 ? ( var.transport_storage_account_id ) : ( azurerm_storage_account.transport[0].id @@ -499,7 +438,9 @@ resource "azurerm_storage_account" "install" { depends_on = [ azurerm_subnet.app, azurerm_subnet.db, - azurerm_subnet.web + azurerm_subnet.web, + azurerm_virtual_network_peering.peering_agent_sap, + azurerm_virtual_network_peering.peering_sap_agent ] name = replace( lower( @@ -542,12 +483,12 @@ resource "azurerm_storage_account_network_rules" "install" { storage_account_id = azurerm_storage_account.install[0].id default_action = var.enable_firewall_for_keyvaults_and_storage ? "Deny" : "Allow" - ip_rules = compact([ + ip_rules = var.public_network_access_enabled ? compact([ length(local.deployer_public_ip_address) > 0 ? local.deployer_public_ip_address : "", length(var.Agent_IP) > 0 ? var.Agent_IP : "" - ]) + ]) : null - virtual_network_subnet_ids = compact([ + virtual_network_subnet_ids = var.public_network_access_enabled ? compact([ local.database_subnet_defined ? ( local.database_subnet_existing ? var.infrastructure.vnets.sap.subnet_db.arm_id : azurerm_subnet.db[0].id) : ( null @@ -557,56 +498,12 @@ resource "azurerm_storage_account_network_rules" "install" { ), length(local.deployer_subnet_management_id) > 0 ? local.deployer_subnet_management_id : null ] - ) + ) : null lifecycle { ignore_changes = [virtual_network_subnet_ids] } } - - - -resource "azurerm_private_dns_a_record" "install" { - provider = azurerm.privatelinkdnsmanagement - count = var.use_private_endpoint && local.use_Azure_native_DNS && local.use_AFS_for_shared && length(var.install_private_endpoint_id) == 0 ? 1 : 0 - name = replace( - lower( - format("%s", local.landscape_shared_install_storage_account_name) - ), - "/[^a-z0-9]/", - "" - ) - zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name - ttl = 10 - records = [ - length(var.install_private_endpoint_id) > 0 ? ( - data.azurerm_private_endpoint_connection.install[0].private_service_connection[0].private_ip_address) : ( - azurerm_private_endpoint.install[0].private_service_connection[0].private_ip_address) - ] - - lifecycle { - ignore_changes = [tags] - } -} - - -data "azurerm_private_dns_a_record" "install" { - provider = azurerm.privatelinkdnsmanagement - count = var.use_private_endpoint && length(var.install_private_endpoint_id) > 0 ? 1 : 0 - name = replace( - lower( - format("%s", local.landscape_shared_install_storage_account_name) - ), - "/[^a-z0-9]/", - "" - ) - zone_name = var.dns_settings.dns_zone_names.file_dns_zone_name - resource_group_name = var.dns_settings.privatelink_dns_resourcegroup_name -} - - - data "azurerm_storage_account" "install" { provider = azurerm.main count = local.use_AFS_for_shared && length(var.install_storage_account_id) > 0 ? 1 : 0 @@ -752,7 +649,7 @@ resource "azurerm_storage_share" "install_smb" { #Private endpoint tend to take a while to be created, so we need to wait for it to be ready before we can use it resource "time_sleep" "wait_for_private_endpoints" { - create_duration = "120s" + create_duration = "60s" depends_on = [ azurerm_private_endpoint.install, diff --git a/deploy/terraform/terraform-units/modules/sap_landscape/subnets.tf b/deploy/terraform/terraform-units/modules/sap_landscape/subnets.tf index 91fd40c415..466ca27b7c 100644 --- a/deploy/terraform/terraform-units/modules/sap_landscape/subnets.tf +++ b/deploy/terraform/terraform-units/modules/sap_landscape/subnets.tf @@ -53,7 +53,7 @@ data "azurerm_subnet" "db" { // Creates app subnet of SAP VNET resource "azurerm_subnet" "app" { provider = azurerm.main - count = local.application_subnet_defined && !local.application_subnet_existing ? 1 : 0 + count = local.create_application_subnet ? 1 : 0 name = local.application_subnet_name resource_group_name = local.SAP_virtualnetwork_exists ? data.azurerm_virtual_network.vnet_sap[0].resource_group_name : azurerm_virtual_network.vnet_sap[0].resource_group_name virtual_network_name = local.SAP_virtualnetwork_exists ? data.azurerm_virtual_network.vnet_sap[0].name : azurerm_virtual_network.vnet_sap[0].name @@ -258,11 +258,3 @@ resource "azurerm_network_security_rule" "nsr_external_db" { destination_address_prefixes = azurerm_subnet.db[0].address_prefixes } - -data "azurerm_resource_group" "mgmt" { - provider = azurerm.deployer - count = length(local.deployer_subnet_management_id) > 0 ? 1 : 0 - name = split("/", local.deployer_subnet_management_id)[4] -} - - diff --git a/deploy/terraform/terraform-units/modules/sap_landscape/variables_global.tf b/deploy/terraform/terraform-units/modules/sap_landscape/variables_global.tf index fc392f10bf..c1deaee125 100644 --- a/deploy/terraform/terraform-units/modules/sap_landscape/variables_global.tf +++ b/deploy/terraform/terraform-units/modules/sap_landscape/variables_global.tf @@ -85,21 +85,21 @@ variable "key_vault" { default = {} validation { condition = ( - contains(keys(var.key_vault), "kv_spn_id") ? ( - length(split("/", var.key_vault.kv_spn_id)) == 9) : ( + contains(keys(var.key_vault), "keyvault_id_for_deployment_credentials") ? ( + length(split("/", var.key_vault.keyvault_id_for_deployment_credentials)) == 9) : ( true ) ) - error_message = "If specified, the kv_spn_id needs to be a correctly formed Azure resource ID." + error_message = "If specified, the spn_keyvault_id needs to be a correctly formed Azure resource ID." } validation { condition = ( - contains(keys(var.key_vault), "kv_user_id") ? ( - length(split("/", var.key_vault.kv_user_id)) == 9) : ( + contains(keys(var.key_vault), "keyvault_id_for_system_credentials") ? ( + length(split("/", var.key_vault.keyvault_id_for_system_credentials)) == 9) : ( true ) ) - error_message = "If specified, the kv_user_id needs to be a correctly formed Azure resource ID." + error_message = "If specified, the user_keyvault_id needs to be a correctly formed Azure resource ID." } validation { @@ -173,7 +173,7 @@ variable "storage_account_replication_type" { #######################################4#######################################8 # # -# Miscallaneous variables # +# Miscellaneous variables # # # #######################################4#######################################8 @@ -218,6 +218,10 @@ variable "ANF_settings" { variable "place_delete_lock_on_resources" { description = "If defined, a delete lock will be placed on the key resources" } +variable "agent_network_id" { + description = "Agent Network resource ID" + default = "" + } ######################################################################################### # # diff --git a/deploy/terraform/terraform-units/modules/sap_landscape/variables_local.tf b/deploy/terraform/terraform-units/modules/sap_landscape/variables_local.tf index bc889fdda7..b4bf0569a4 100644 --- a/deploy/terraform/terraform-units/modules/sap_landscape/variables_local.tf +++ b/deploy/terraform/terraform-units/modules/sap_landscape/variables_local.tf @@ -121,7 +121,7 @@ locals { user_key_vault_id = try(var.key_vault.kv_user_id, "") user_keyvault_exist = length(local.user_key_vault_id) > 0 - enable_landscape_kv = !local.user_keyvault_exist + create_workloadzone_keyvault = !local.user_keyvault_exist // If the user specifies the secret name of key pair/password in input, // the secrets will be imported instead of creating new secrets @@ -369,6 +369,8 @@ locals { "" ) + create_application_subnet = local.application_subnet_defined && !local.application_subnet_existing + ############################################################################################## # # Application subnet NSG - Check if locally provided diff --git a/deploy/terraform/terraform-units/modules/sap_library/infrastructure.tf b/deploy/terraform/terraform-units/modules/sap_library/infrastructure.tf index c6a138b9e7..9b33c38024 100644 --- a/deploy/terraform/terraform-units/modules/sap_library/infrastructure.tf +++ b/deploy/terraform/terraform-units/modules/sap_library/infrastructure.tf @@ -26,24 +26,6 @@ data "azurerm_resource_group" "library" { name = split("/", var.infrastructure.resource_group.arm_id)[4] } -resource "azurerm_role_assignment" "library_sai" { - provider = azurerm.main - count = var.bootstrap ? 0 : try(var.deployer_tfstate.add_system_assigned_identity, false) ? 1 : 0 - scope = local.resource_group_exists ? var.infrastructure.resource_group.arm_id : azurerm_resource_group.library[0].id - role_definition_name = "Storage Blob Data Contributor" - principal_id = var.deployer_tfstate.deployer_system_assigned_identity[count.index] -} - - -resource "azurerm_role_assignment" "library_webapp_system_assigned_identity" { - provider = azurerm.main - count = length(var.deployer_tfstate.webapp_identity) > 0 ? 1 : 0 - scope = local.resource_group_exists ? var.infrastructure.resource_group.arm_id : azurerm_resource_group.library[0].id - role_definition_name = "Storage Blob Data Contributor" - principal_id = var.deployer_tfstate.webapp_identity -} - - // TODO: Add management lock when this issue is addressed https://github.com/terraform-providers/terraform-provider-azurerm/issues/5473 @@ -96,3 +78,80 @@ resource "azurerm_private_dns_zone_virtual_network_link" "vnet_mgmt_blob" { } +resource "azurerm_private_dns_zone_virtual_network_link" "vault" { + provider = azurerm.dnsmanagement + count = var.dns_settings.register_storage_accounts_keyvaults_with_dns && var.use_private_endpoint ? 1 : 0 + depends_on = [ + azurerm_private_dns_zone.vault + ] + + name = format("%s%s%s%s", + var.naming.resource_prefixes.dns_link, + local.prefix, + var.naming.separator, + "vault" + ) + resource_group_name = length(var.dns_settings.privatelink_dns_subscription_id) == 0 ? ( + local.resource_group_exists ? ( + split("/", var.infrastructure.resource_group.arm_id)[4]) : ( + azurerm_resource_group.library[0].name + )) : ( + var.dns_settings.privatelink_dns_resourcegroup_name + ) + private_dns_zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name + virtual_network_id = var.deployer_tfstate.vnet_mgmt_id + registration_enabled = false +} + + +resource "azurerm_private_dns_zone_virtual_network_link" "vault_agent" { + provider = azurerm.dnsmanagement + count = var.dns_settings.register_storage_accounts_keyvaults_with_dns && var.use_private_endpoint && length(var.dns_settings.agent_network_id) > 0 ? 1 : 0 + depends_on = [ + azurerm_private_dns_zone.vault + ] + + name = format("%s%s%s%s", + var.naming.resource_prefixes.dns_link, + local.prefix, + var.naming.separator, + "vault-agent" + ) + resource_group_name = length(var.dns_settings.privatelink_dns_subscription_id) == 0 ? ( + local.resource_group_exists ? ( + split("/", var.infrastructure.resource_group.arm_id)[4]) : ( + azurerm_resource_group.library[0].name + )) : ( + var.dns_settings.privatelink_dns_resourcegroup_name + ) + private_dns_zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name + virtual_network_id = var.dns_settings.agent_network_id + registration_enabled = false +} + + +resource "azurerm_private_dns_zone_virtual_network_link" "blob_agent" { + provider = azurerm.dnsmanagement + count = var.dns_settings.register_storage_accounts_keyvaults_with_dns && var.use_private_endpoint && length(var.dns_settings.agent_network_id) > 0 ? 1 : 0 + depends_on = [ + azurerm_private_dns_zone.vault + ] + + name = format("%s%s%s%s", + var.naming.resource_prefixes.dns_link, + local.prefix, + var.naming.separator, + "vault-agent" + ) + resource_group_name = length(var.dns_settings.privatelink_dns_subscription_id) == 0 ? ( + local.resource_group_exists ? ( + split("/", var.infrastructure.resource_group.arm_id)[4]) : ( + azurerm_resource_group.library[0].name + )) : ( + var.dns_settings.privatelink_dns_resourcegroup_name + ) + private_dns_zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name + virtual_network_id = var.dns_settings.agent_network_id + registration_enabled = false +} + diff --git a/deploy/terraform/terraform-units/modules/sap_library/key_vault.tf b/deploy/terraform/terraform-units/modules/sap_library/key_vault.tf index 6ffc709e9a..81c32938e6 100644 --- a/deploy/terraform/terraform-units/modules/sap_library/key_vault.tf +++ b/deploy/terraform/terraform-units/modules/sap_library/key_vault.tf @@ -13,7 +13,12 @@ resource "time_offset" "secret_expiry_date" { resource "azurerm_key_vault_secret" "saplibrary_access_key" { provider = azurerm.deployer - depends_on = [ azurerm_storage_account.storage_tfstate ] + depends_on = [ + azurerm_storage_account.storage_tfstate, + azurerm_private_dns_zone.vault, + azurerm_private_dns_zone_virtual_network_link.vault, + azurerm_private_dns_zone_virtual_network_link.vault_agent + ] count = var.storage_account_sapbits.shared_access_key_enabled && length(try(var.key_vault.kv_spn_id, "")) > 0 ? 1 : 0 name = "sapbits-access-key" value = local.sa_sapbits_exists ? ( @@ -31,10 +36,16 @@ resource "azurerm_key_vault_secret" "saplibrary_access_key" { resource "azurerm_key_vault_secret" "sapbits_location_base_path" { provider = azurerm.deployer - depends_on = [ azurerm_storage_account.storage_tfstate, azurerm_private_dns_zone.vault ] + depends_on = [ + azurerm_storage_account.storage_tfstate, + azurerm_private_dns_zone.vault, + azurerm_private_dns_zone_virtual_network_link.vault, + azurerm_private_dns_zone_virtual_network_link.vault_agent, + azurerm_private_endpoint.kv_user + ] count = length(try(var.key_vault.kv_spn_id, "")) > 0 ? 1 : 0 name = "sapbits-location-base-path" - value = format("https://%s%s.blob.core.windows.net/%s", (var.dns_settings.register_storage_accounts_keyvaults_with_dns ? ".privatelink" : ""), length(var.storage_account_sapbits.arm_id) > 0 ? + value = format("https://%s%s.blob.core.windows.net/%s", length(var.storage_account_sapbits.arm_id) > 0 ? split("/", var.storage_account_sapbits.arm_id)[8] : replace( lower( format("%s", local.sa_sapbits_name) @@ -42,6 +53,7 @@ resource "azurerm_key_vault_secret" "sapbits_location_base_path" { "/[^a-z0-9]/", "" ), + (var.dns_settings.register_storage_accounts_keyvaults_with_dns ? ".privatelink" : ""), var.storage_account_sapbits.sapbits_blob_container.name ) @@ -56,7 +68,13 @@ resource "azurerm_key_vault_secret" "sapbits_location_base_path" { resource "azurerm_key_vault_secret" "sa_connection_string" { provider = azurerm.deployer - depends_on = [ azurerm_storage_account.storage_tfstate, azurerm_private_dns_zone.vault ] + depends_on = [ + azurerm_storage_account.storage_tfstate, + azurerm_private_dns_zone.vault, + azurerm_private_dns_zone_virtual_network_link.vault, + azurerm_private_dns_zone_virtual_network_link.vault_agent, + azurerm_private_endpoint.kv_user + ] count = length(try(var.key_vault.kv_spn_id, "")) > 0 ? 1 : 0 name = "sa-connection-string" value = local.sa_tfstate_exists ? ( @@ -72,11 +90,17 @@ resource "azurerm_key_vault_secret" "sa_connection_string" { resource "azurerm_key_vault_secret" "tfstate" { provider = azurerm.deployer - depends_on = [ azurerm_storage_account.storage_tfstate, azurerm_private_dns_zone.vault ] + depends_on = [ + azurerm_storage_account.storage_tfstate, + azurerm_private_dns_zone.vault, + azurerm_private_dns_zone_virtual_network_link.vault, + azurerm_private_dns_zone_virtual_network_link.vault_agent, + azurerm_private_endpoint.kv_user + ] count = length(try(var.key_vault.kv_spn_id, "")) > 0 ? 1 : 0 name = "tfstate" value = var.use_private_endpoint ? ( - format("https://privatelink.%s.blob.core.windows.net", local.sa_tfstate_exists ? (data.azurerm_storage_account.storage_tfstate[0].name) : (azurerm_storage_account.storage_tfstate[0].name))) : ( + format("https://%s.privatelink.blob.core.windows.net", local.sa_tfstate_exists ? (data.azurerm_storage_account.storage_tfstate[0].name) : (azurerm_storage_account.storage_tfstate[0].name))) : ( format("https://%s.blob.core.windows.net", local.sa_tfstate_exists ? (data.azurerm_storage_account.storage_tfstate[0].name) : (azurerm_storage_account.storage_tfstate[0].name)) ) key_vault_id = var.key_vault.kv_spn_id @@ -88,21 +112,21 @@ resource "azurerm_key_vault_secret" "tfstate" { -resource "azurerm_private_dns_a_record" "kv_user" { - provider = azurerm.privatelinkdnsmanagement - count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0 - name = lower(split("/", var.key_vault.kv_spn_id)[8]) - zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name - resource_group_name = coalesce( - var.dns_settings.privatelink_dns_resourcegroup_name, - var.dns_settings.management_dns_resourcegroup_name, - local.resource_group_name - ) - ttl = 3600 - records = [azurerm_private_endpoint.kv_user[0].private_service_connection[0].private_ip_address] - - lifecycle { - ignore_changes = [tags] - } -} +# resource "azurerm_private_dns_a_record" "kv_user" { +# provider = azurerm.privatelinkdnsmanagement +# count = var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0 +# name = lower(split("/", var.key_vault.kv_spn_id)[8]) +# zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name +# resource_group_name = coalesce( +# var.dns_settings.privatelink_dns_resourcegroup_name, +# var.dns_settings.management_dns_resourcegroup_name, +# local.resource_group_name +# ) +# ttl = 3600 +# records = [azurerm_private_endpoint.kv_user[0].private_service_connection[0].private_ip_address] + +# lifecycle { +# ignore_changes = [tags] +# } +# } diff --git a/deploy/terraform/terraform-units/modules/sap_library/keyvault_endpoint.tf b/deploy/terraform/terraform-units/modules/sap_library/keyvault_endpoint.tf index da8de606d1..b4d79ae3df 100644 --- a/deploy/terraform/terraform-units/modules/sap_library/keyvault_endpoint.tf +++ b/deploy/terraform/terraform-units/modules/sap_library/keyvault_endpoint.tf @@ -46,28 +46,3 @@ resource "azurerm_private_endpoint" "kv_user" { } } - -resource "azurerm_private_dns_zone_virtual_network_link" "vault" { - provider = azurerm.dnsmanagement - count = var.dns_settings.register_storage_accounts_keyvaults_with_dns && var.use_private_endpoint ? 1 : 0 - depends_on = [ - azurerm_private_dns_zone.vault - ] - - name = format("%s%s%s%s", - var.naming.resource_prefixes.dns_link, - local.prefix, - var.naming.separator, - "vault" - ) - resource_group_name = length(var.dns_settings.privatelink_dns_subscription_id) == 0 ? ( - local.resource_group_exists ? ( - split("/", var.infrastructure.resource_group.arm_id)[4]) : ( - azurerm_resource_group.library[0].name - )) : ( - var.dns_settings.privatelink_dns_resourcegroup_name - ) - private_dns_zone_name = var.dns_settings.dns_zone_names.vault_dns_zone_name - virtual_network_id = var.deployer_tfstate.vnet_mgmt_id - registration_enabled = false -} diff --git a/deploy/terraform/terraform-units/modules/sap_library/storage_accounts.tf b/deploy/terraform/terraform-units/modules/sap_library/storage_accounts.tf index 729836ce21..c4df662d38 100644 --- a/deploy/terraform/terraform-units/modules/sap_library/storage_accounts.tf +++ b/deploy/terraform/terraform-units/modules/sap_library/storage_accounts.tf @@ -88,41 +88,41 @@ resource "azurerm_storage_account_network_rules" "storage_tfstate" { } } -resource "azurerm_private_dns_a_record" "storage_tfstate_pep_a_record_registry" { - provider = azurerm.privatelinkdnsmanagement - count = var.dns_settings.register_storage_accounts_keyvaults_with_dns && var.use_private_endpoint && var.use_custom_dns_a_registration && !local.sa_tfstate_exists ? 1 : 0 - depends_on = [ - azurerm_private_dns_zone.blob - ] - name = lower(azurerm_storage_account.storage_tfstate[0].name) - zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name - resource_group_name = coalesce( - var.dns_settings.privatelink_dns_resourcegroup_name, - var.dns_settings.management_dns_resourcegroup_name, - local.resource_group_exists ? ( - data.azurerm_resource_group.library[0].name - ) : ( - azurerm_resource_group.library[0].name - ) - ) - ttl = 3600 - records = [azurerm_private_endpoint.storage_tfstate[0].private_service_connection[0].private_ip_address] - - lifecycle { - ignore_changes = [tags] - } -} +# resource "azurerm_private_dns_a_record" "storage_tfstate_pep_a_record_registry" { +# provider = azurerm.privatelinkdnsmanagement +# count = var.dns_settings.register_storage_accounts_keyvaults_with_dns && var.use_private_endpoint && var.use_custom_dns_a_registration && !local.sa_tfstate_exists ? 1 : 0 +# depends_on = [ +# azurerm_private_dns_zone.blob +# ] +# name = lower(azurerm_storage_account.storage_tfstate[0].name) +# zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name +# resource_group_name = coalesce( +# var.dns_settings.privatelink_dns_resourcegroup_name, +# var.dns_settings.management_dns_resourcegroup_name, +# local.resource_group_exists ? ( +# data.azurerm_resource_group.library[0].name +# ) : ( +# azurerm_resource_group.library[0].name +# ) +# ) +# ttl = 3600 +# records = [azurerm_private_endpoint.storage_tfstate[0].private_service_connection[0].private_ip_address] + +# lifecycle { +# ignore_changes = [tags] +# } +# } -#Errors can occure when the dns record has not properly been activated, add a wait timer to give +#Errors can occur when the dns record has not properly been activated, add a wait timer to give #it just a little bit more time -resource "time_sleep" "wait_for_dns_refresh" { - create_duration = "120s" +# resource "time_sleep" "wait_for_dns_refresh" { +# create_duration = "120s" - depends_on = [ - azurerm_private_dns_a_record.storage_tfstate_pep_a_record_registry, - azurerm_private_dns_a_record.storage_sapbits_pep_a_record_registry - ] -} +# depends_on = [ +# azurerm_private_dns_a_record.storage_tfstate_pep_a_record_registry, +# azurerm_private_dns_a_record.storage_sapbits_pep_a_record_registry +# ] +# } resource "azurerm_private_endpoint" "storage_tfstate" { @@ -245,9 +245,7 @@ resource "azurerm_storage_container" "storagecontainer_tfstate" { provider = azurerm.main count = var.storage_account_tfstate.tfstate_blob_container.is_existing ? 0 : 1 depends_on = [ - time_sleep.wait_for_dns_refresh, azurerm_private_endpoint.storage_tfstate, - azurerm_private_dns_a_record.storage_tfstate_pep_a_record_registry ] name = var.storage_account_tfstate.tfstate_blob_container.name @@ -339,29 +337,29 @@ resource "azurerm_management_lock" "storage_sapbits" { } -resource "azurerm_private_dns_a_record" "storage_sapbits_pep_a_record_registry" { - provider = azurerm.privatelinkdnsmanagement - count = var.use_private_endpoint && var.use_custom_dns_a_registration && !local.sa_sapbits_exists ? 1 : 0 - depends_on = [ - azurerm_private_dns_zone.blob - ] - - name = lower(azurerm_storage_account.storage_sapbits[0].name) - zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name - resource_group_name = coalesce( - var.dns_settings.privatelink_dns_resourcegroup_name, - var.dns_settings.management_dns_resourcegroup_name, - local.resource_group_exists ? ( - data.azurerm_resource_group.library[0].name) : ( - azurerm_resource_group.library[0].name) - ) - ttl = 3600 - records = [azurerm_private_endpoint.storage_sapbits[0].private_service_connection[0].private_ip_address] - - lifecycle { - ignore_changes = [tags] - } -} +# resource "azurerm_private_dns_a_record" "storage_sapbits_pep_a_record_registry" { +# provider = azurerm.privatelinkdnsmanagement +# count = var.use_private_endpoint && var.use_custom_dns_a_registration && !local.sa_sapbits_exists ? 1 : 0 +# depends_on = [ +# azurerm_private_dns_zone.blob +# ] + +# name = lower(azurerm_storage_account.storage_sapbits[0].name) +# zone_name = var.dns_settings.dns_zone_names.blob_dns_zone_name +# resource_group_name = coalesce( +# var.dns_settings.privatelink_dns_resourcegroup_name, +# var.dns_settings.management_dns_resourcegroup_name, +# local.resource_group_exists ? ( +# data.azurerm_resource_group.library[0].name) : ( +# azurerm_resource_group.library[0].name) +# ) +# ttl = 3600 +# records = [azurerm_private_endpoint.storage_sapbits[0].private_service_connection[0].private_ip_address] + +# lifecycle { +# ignore_changes = [tags] +# } +# } data "azurerm_storage_account" "storage_sapbits" { provider = azurerm.main @@ -416,7 +414,7 @@ resource "azurerm_private_endpoint" "storage_sapbits" { } dynamic "private_dns_zone_group" { - for_each = range(var.use_private_endpoint && !var.use_custom_dns_a_registration ? 1 : 0) + for_each = range(var.dns_settings.register_storage_accounts_keyvaults_with_dns ? 1 : 0) content { name = var.dns_settings.dns_zone_names.blob_dns_zone_name private_dns_zone_ids = [local.use_local_private_dns ? azurerm_private_dns_zone.blob[0].id : data.azurerm_private_dns_zone.storage[0].id] diff --git a/deploy/terraform/terraform-units/modules/sap_library/variables_local.tf b/deploy/terraform/terraform-units/modules/sap_library/variables_local.tf index 015338c91b..06b143dcbd 100644 --- a/deploy/terraform/terraform-units/modules/sap_library/variables_local.tf +++ b/deploy/terraform/terraform-units/modules/sap_library/variables_local.tf @@ -57,7 +57,7 @@ locals { enable_firewall_for_keyvaults_and_storage = try(var.deployer_tfstate.enable_firewall_for_keyvaults_and_storage, false) use_local_private_dns = (length(var.dns_settings.dns_label) > 0 && !var.use_custom_dns_a_registration && length(trimspace(var.dns_settings.management_dns_resourcegroup_name)) == 0) - use_local_privatelink_dns = !var.use_custom_dns_a_registration && length(trimspace(var.dns_settings.privatelink_dns_resourcegroup_name)) == 0 + use_local_privatelink_dns = var.dns_settings.create_privatelink_dns_zones && !var.use_custom_dns_a_registration && length(trimspace(var.dns_settings.privatelink_dns_resourcegroup_name)) == 0 keyvault_id = try(var.deployer_tfstate.deployer_kv_user_arm_id, "") diff --git a/deploy/terraform/terraform-units/modules/sap_namegenerator/variables_global.tf b/deploy/terraform/terraform-units/modules/sap_namegenerator/variables_global.tf index c5cf74d400..909018e19b 100644 --- a/deploy/terraform/terraform-units/modules/sap_namegenerator/variables_global.tf +++ b/deploy/terraform/terraform-units/modules/sap_namegenerator/variables_global.tf @@ -271,6 +271,9 @@ variable "resource_prefixes" { "db_clst_feip" = "" "db_alb_hp" = "" "db_alb_rule" = "" + "db_rlb_feip" = "" + "db_rlb_hp" = "" + "db_rlb_rule" = "" "db_asg" = "" "db_avset" = "" "db_nic" = "" @@ -405,6 +408,9 @@ variable "resource_suffixes" { "db_clst_feip" = "dbClst-feip" "db_alb_hp" = "dbAlb-hp" "db_alb_rule" = "dbAlb-rule" + "db_rlb_feip" = "dbRlb-feip" + "db_rlb_hp" = "dbRlb-hp" + "db_rlb_rule" = "dbRlb-rule" "db_asg" = "db-asg" "db_avset" = "db-avset" "db_nic" = "-db-nic" diff --git a/deploy/terraform/terraform-units/modules/sap_system/app_tier/infrastructure.tf b/deploy/terraform/terraform-units/modules/sap_system/app_tier/infrastructure.tf index 15280f306f..74b3007c6e 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/app_tier/infrastructure.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/app_tier/infrastructure.tf @@ -324,7 +324,7 @@ resource "azurerm_availability_set" "scs" { #######################################4#######################################8 resource "azurerm_availability_set" "app" { provider = azurerm.main - count = local.use_app_avset && var.application_tier.avset_arm_ids_count == 0 ? var.application_tier.app_zone_count : 0 + count = local.use_app_avset && var.application_tier.avset_arm_ids_count == 0 ? max(var.application_tier.app_zone_count, 1) : 0 depends_on = [azurerm_virtual_machine_data_disk_attachment.scs] name = format("%s%s%s", diff --git a/deploy/terraform/terraform-units/modules/sap_system/app_tier/vm-app.tf b/deploy/terraform/terraform-units/modules/sap_system/app_tier/vm-app.tf index d59da2d4ca..47d783662f 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/app_tier/vm-app.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/app_tier/vm-app.tf @@ -134,10 +134,10 @@ resource "azurerm_linux_virtual_machine" "app" { //If more than one servers are deployed into a single zone put them in an availability set and not a zone availability_set_id = var.application_tier.app_use_avset ? ( - length(var.application_tier.avset_arm_ids) > 0 ? ( + try(length(var.application_tier.avset_arm_ids) > 0 ? ( var.application_tier.avset_arm_ids[count.index % max(length(var.application_tier.avset_arm_ids), 1)]) : ( azurerm_availability_set.app[count.index % max(length(var.ppg), 1)].id - )) : ( + ), null)) : ( null ) @@ -286,10 +286,10 @@ resource "azurerm_windows_virtual_machine" "app" { //If more than one servers are deployed into a single zone put them in an availability set and not a zone availability_set_id = var.application_tier.app_use_avset ? ( - length(var.application_tier.avset_arm_ids) > 0 ? ( + try(length(var.application_tier.avset_arm_ids) > 0 ? ( var.application_tier.avset_arm_ids[count.index % max(length(var.application_tier.avset_arm_ids), 1)]) : ( - azurerm_availability_set.app[count.index % max(length(azurerm_availability_set.app), 1)].id - )) : ( + azurerm_availability_set.app[count.index % max(length(var.ppg), 1)].id + ), null)) : ( null ) diff --git a/deploy/terraform/terraform-units/modules/sap_system/common_infrastructure/key_vault_sap_system.tf b/deploy/terraform/terraform-units/modules/sap_system/common_infrastructure/key_vault_sap_system.tf index 4aa763ad93..783bdac4c9 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/common_infrastructure/key_vault_sap_system.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/common_infrastructure/key_vault_sap_system.tf @@ -4,14 +4,12 @@ # # ############################################################################### data "azurerm_key_vault_secret" "sid_pk" { - provider = azurerm.main count = local.use_local_credentials ? 0 : 1 name = var.landscape_tfstate.sid_public_key_secret_name key_vault_id = local.user_key_vault_id } data "azurerm_key_vault_secret" "sid_username" { - provider = azurerm.main count = local.use_local_credentials ? 0 : 1 name = try( var.landscape_tfstate.sid_username_secret_name, @@ -21,7 +19,6 @@ data "azurerm_key_vault_secret" "sid_username" { } data "azurerm_key_vault_secret" "sid_password" { - provider = azurerm.main count = local.use_local_credentials ? 0 : 1 name = try( var.landscape_tfstate.sid_password_secret_name, diff --git a/deploy/terraform/terraform-units/modules/sap_system/common_infrastructure/providers.tf b/deploy/terraform/terraform-units/modules/sap_system/common_infrastructure/providers.tf index 49aaed0d9a..1bca6c973d 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/common_infrastructure/providers.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/common_infrastructure/providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - configuration_aliases = [azurerm.main, azurerm.deployer, azurerm.dnsmanagement, azurerm.privatelinkdnsmanagement] // + configuration_aliases = [azurerm.main, azurerm.dnsmanagement, azurerm.privatelinkdnsmanagement] // } } } diff --git a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/infrastructure.tf b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/infrastructure.tf index e7be0fcd02..2e6e6bb750 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/infrastructure.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/infrastructure.tf @@ -53,28 +53,18 @@ resource "azurerm_lb" "hdb" { sku = "Standard" tags = var.tags - frontend_ip_configuration { - name = format("%s%s%s%s", - var.naming.resource_prefixes.db_alb_feip, - local.prefix, - var.naming.separator, - local.resource_suffixes.db_alb_feip - ) - subnet_id = var.database.scale_out ? var.admin_subnet.id : var.db_subnet.id - private_ip_address = length(try(var.database.loadbalancer.frontend_ips[0], "")) > 0 ? ( - var.database.loadbalancer.frontend_ips[0]) : ( - var.database.use_DHCP ? ( - null) : ( - cidrhost( - var.database.scale_out ? var.admin_subnet.address_prefixes[0] : var.db_subnet.address_prefixes[0], - tonumber(count.index) + local.hdb_ip_offsets.hdb_lb - )) - ) - private_ip_address_allocation = length(try(var.database.loadbalancer.frontend_ips[0], "")) > 0 ? "Static" : "Dynamic" - - zones = ["1", "2", "3"] - } + dynamic "frontend_ip_configuration" { + iterator = pub + for_each = local.frontend_ips + content { + name = pub.value.name + subnet_id = pub.value.subnet_id + private_ip_address = pub.value.private_ip_address + private_ip_address_allocation = pub.value.private_ip_address_allocation + zones = ["1", "2", "3"] + } + } } resource "azurerm_lb_backend_address_pool" "hdb" { @@ -154,3 +144,57 @@ resource "azurerm_private_dns_a_record" "db" { tags = var.tags } +# HANA Active/Active (Read Enabled) System Replication based on database_active_active variable +resource "azurerm_lb_probe" "hdb_active_active" { + provider = azurerm.main + count = local.enable_db_lb_deployment && var.database_active_active ? 1 : 0 + name = format("%s%s%s%s", + var.naming.resource_prefixes.db_rlb_hp, + local.prefix, + var.naming.separator, + local.resource_suffixes.db_rlb_hp + ) + loadbalancer_id = azurerm_lb.hdb[count.index].id + port = "626${var.database.instance.number}" + protocol = "Tcp" + interval_in_seconds = 5 + number_of_probes = 2 + probe_threshold = 2 +} + +resource "azurerm_lb_rule" "hdb_active_active" { + provider = azurerm.main + count = local.enable_db_lb_deployment && var.database_active_active ? 1 : 0 + name = format("%s%s%s%s", + var.naming.resource_prefixes.db_rlb_rule, + local.prefix, + var.naming.separator, + local.resource_suffixes.db_rlb_rule + ) + loadbalancer_id = azurerm_lb.hdb[count.index].id + protocol = "All" + frontend_port = 0 + backend_port = 0 + + frontend_ip_configuration_name = format("%s%s%s%s", + var.naming.resource_prefixes.db_rlb_feip, + local.prefix, + var.naming.separator, + local.resource_suffixes.db_rlb_feip + ) + probe_id = azurerm_lb_probe.hdb_active_active[0].id + backend_address_pool_ids = [azurerm_lb_backend_address_pool.hdb[0].id] + enable_floating_ip = true + idle_timeout_in_minutes = 30 +} + +resource "azurerm_private_dns_a_record" "db_active_active" { + provider = azurerm.dnsmanagement + count = local.enable_db_lb_deployment && var.database_active_active && length(local.dns_label) > 0 && var.dns_settings.register_virtual_network_to_dns ? 1 : 0 + name = lower(format("%s%sdb%sclr", var.sap_sid, local.database_sid, local.database_instance)) + resource_group_name = coalesce(var.dns_settings.management_dns_resourcegroup_name, var.landscape_tfstate.dns_resource_group_name) + zone_name = local.dns_label + ttl = 300 + records = [try(azurerm_lb.hdb[0].frontend_ip_configuration[1].private_ip_address, "")] + tags = var.tags +} diff --git a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/outputs.tf b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/outputs.tf index 8266ddedef..508b6cc434 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/outputs.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/outputs.tf @@ -91,12 +91,18 @@ output "database_disks" { output "database_loadbalancer_ip" { description = "Database loadbalancer IP information" - value = [ - local.enable_db_lb_deployment ? ( - try(azurerm_lb.hdb[0].frontend_ip_configuration[0].private_ip_address, "")) : ( - "" - ) - ] + value = local.enable_db_lb_deployment ? ( + compact( + concat( + [ + try(azurerm_lb.hdb[0].frontend_ip_configuration[0].private_ip_address, "") + ], + [ + try(azurerm_lb.hdb[0].frontend_ip_configuration[1].private_ip_address, "") + ] + ) + ) + ) : [""] } output "database_loadbalancer_id" { diff --git a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/storage_accounts.tf b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/storage_accounts.tf index 3224f41f94..7f4e32885c 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/storage_accounts.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/storage_accounts.tf @@ -55,19 +55,6 @@ resource "azurerm_storage_account" "hanashared" { } - -data "azurerm_storage_account" "hanashared" { - provider = azurerm.main - count = var.NFS_provider == "AFS" && var.database.scale_out ? ( - length(var.hanashared_id) > 0 ? ( - length(var.hanashared_id)) : ( - 0 - )) : ( - 0 - ) - name = split("/", var.hanashared_id[count.index])[8] - resource_group_name = split("/", var.hanashared_id[count.index])[4] -} ######################################################################################### # # # NFS share # @@ -92,7 +79,7 @@ resource "azurerm_storage_share" "hanashared" { name = format("%s-%s-%01d", lower(local.sid),local.resource_suffixes.hanasharedafs, count.index+1) storage_account_id = var.NFS_provider == "AFS" ? ( length(var.hanashared_id) > 0 ? ( - data.azurerm_storage_account.hanashared[count.index].id) : ( + var.hanashared_id[count.index]) : ( azurerm_storage_account.hanashared[count.index].id ) ) : ( diff --git a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/variables_global.tf b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/variables_global.tf index b5da13fbc2..1b864f1fa9 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/variables_global.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/variables_global.tf @@ -23,6 +23,10 @@ variable "database_use_premium_v2_storage" { description = "If true, the database tier will use premium storage" type = bool } +variable "database_active_active" { + description = "If true, database will deployed with Active/Active (read enabled) configuration" + type = bool + } variable "database_vm_admin_nic_ips" { description = "If provided, the database tier will be configured with the specified IPs (admin subnet)" } variable "database_vm_db_nic_ips" { description = "If provided, the database tier will be configured with the specified IPs" } variable "database_vm_db_nic_secondary_ips" { description = "If provided, the database tier will be configured with the specified IPs as secondary IPs" } diff --git a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/variables_local.tf b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/variables_local.tf index 30a97461ac..384d9d5360 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/hdb_node/variables_local.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/hdb_node/variables_local.tf @@ -167,6 +167,49 @@ locals { null ) + standard_ips = [ + { + name = format("%s%s%s%s", + var.naming.resource_prefixes.db_alb_feip, + local.prefix, + var.naming.separator, + local.resource_suffixes.db_alb_feip + ) + subnet_id = var.database.scale_out ? var.admin_subnet.id : var.db_subnet.id + private_ip_address = length(try(var.database.loadbalancer.frontend_ips[0], "")) > 0 ? ( + var.database.loadbalancer.frontend_ips[0]) : ( + var.database.use_DHCP ? ( + null) : ( + cidrhost( + var.database.scale_out ? var.admin_subnet.address_prefixes[0] : var.db_subnet.address_prefixes[0], + local.hdb_ip_offsets.hdb_lb + )) + ) + private_ip_address_allocation = length(try(var.database.loadbalancer.frontend_ips[1], "")) > 0 ? "Static" : "Dynamic" + }, + { + name = format("%s%s%s%s", + var.naming.resource_prefixes.db_rlb_feip, + local.prefix, + var.naming.separator, + local.resource_suffixes.db_rlb_feip + ) + subnet_id = var.database.scale_out ? var.admin_subnet.id : var.db_subnet.id + private_ip_address = length(try(var.database.loadbalancer.frontend_ips[1], "")) > 0 ? ( + var.database.loadbalancer.frontend_ips[0]) : ( + var.database.use_DHCP ? ( + null) : ( + cidrhost( + var.database.scale_out ? var.admin_subnet.address_prefixes[0] : var.db_subnet.address_prefixes[0], + local.hdb_ip_offsets.hdb_lb + 1 + )) + ) + private_ip_address_allocation = length(try(var.database.loadbalancer.frontend_ips[1], "")) > 0 ? "Static" : "Dynamic" + } + ] + + frontend_ips = slice(local.standard_ips, 0, var.database_active_active ? 2 : 1) + // OS disk to be created for HANA DB nodes // disk_iops_read_write only apply for ultra os_disk = flatten( diff --git a/deploy/terraform/terraform-units/modules/sap_system/output_files/inventory.tf b/deploy/terraform/terraform-units/modules/sap_system/output_files/inventory.tf index 7d82018056..2663cfe3a3 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/output_files/inventory.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/output_files/inventory.tf @@ -187,6 +187,8 @@ resource "local_file" "sap-parameters_yml" { database_cluster_type = var.database_cluster_type database_high_availability = var.database_high_availability database_cluster_ip = try(format("%s/%s", var.database_cluster_ip, var.database_subnet_netmask), "") + database_active_active = var.database_active_active + database_active_active_loadbalancer_ip = var.database_active_active_loadbalancer_ip db_instance_number = try(var.database.instance.number, "00") database_loadbalancer_ip = var.database_loadbalancer_ip db_sid = var.db_sid diff --git a/deploy/terraform/terraform-units/modules/sap_system/output_files/sap-parameters.tmpl b/deploy/terraform/terraform-units/modules/sap_system/output_files/sap-parameters.tmpl index 19d9e57f23..268a7eeb06 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/output_files/sap-parameters.tmpl +++ b/deploy/terraform/terraform-units/modules/sap_system/output_files/sap-parameters.tmpl @@ -125,7 +125,13 @@ db_lb_ip: ${database_loadbalancer_ip} %{~ if platform == "SQLSERVER" } # database_cluster_ip is the IP address of the load balancer for the database cluster in Windows -database_cluster_ip: ${database_cluster_ip} +database_cluster_ip: ${database_cluster_ip} +%{~ endif } + +%{~ if database_active_active } +# If the database will deployed with Active/Active (read enabled) configuration (HANA only) +database_active_active: ${database_active_active} +database_active_active_loadbalancer_ip: ${database_active_active_loadbalancer_ip} %{~ endif } # use_simple_mount defines if simple mount is to be used diff --git a/deploy/terraform/terraform-units/modules/sap_system/output_files/variables_global.tf b/deploy/terraform/terraform-units/modules/sap_system/output_files/variables_global.tf index 51e9c566b5..c21e997e5a 100644 --- a/deploy/terraform/terraform-units/modules/sap_system/output_files/variables_global.tf +++ b/deploy/terraform/terraform-units/modules/sap_system/output_files/variables_global.tf @@ -46,6 +46,11 @@ variable "database_authentication_type" { default = "key" } variable "database_cluster_ip" { description = "This is a Cluster IP address for Windows load balancer for the database" } +variable "database_active_active" { description = "If true, database will deployed with Active/Active (read enabled) configuration (HANA only)" } +variable "database_active_active_loadbalancer_ip" { + description = "DB Active Active Load Balancer IP" + default = "" + } variable "database_loadbalancer_ip" { description = "DB Load Balancer IP" default = ""