deploy/scripts/pwsh/SAPDeploymentUtilities/Internal/new_sapworkloadzone.ps1 (443 lines of code) (raw):
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
function New-SAPWorkloadZone {
<#
.SYNOPSIS
Deploy a new SAP Workload Zone
.DESCRIPTION
Deploy a new SAP Workload Zone
.PARAMETER Parameterfile
This is the parameter file for the system
.PARAMETER Force
This is the parameter that forces the script to delete the local terrafrom state file artifacts
.PARAMETER Deployerstatefile
This is the deployer terraform state file name
.PARAMETER DeployerEnvironment
This is the deployer environment name
.EXAMPLE
#
#
# Import the module
Import-Module "SAPDeploymentUtilities.psd1"
New-SAPWorkloadZone -Parameterfile .\PROD-WEEU-SAP00-infrastructure.json
.LINK
https://github.com/Azure/sap-automation
.NOTES
v0.1 - Initial version
.
#>
<#
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
#>
[cmdletbinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory = $true)][string]$Parameterfile,
[Parameter(Mandatory = $false)][string]$Deployerstatefile,
[Parameter(Mandatory = $false)][string]$Deployerenvironment,
[Parameter(Mandatory = $false)][string]$State_subscription,
[Parameter(Mandatory = $false)][string]$Vault,
[Parameter(Mandatory = $false)][string]$StorageAccountName,
[Parameter(Mandatory = $false)][string]$Subscription,
[Parameter(Mandatory = $false)][string]$SPN_id,
[Parameter(Mandatory = $false)][string]$SPN_password,
[Parameter(Mandatory = $false)][string]$Tenant_id,
[Parameter(Mandatory = $false)][Switch]$Force,
[Parameter(Mandatory = $false)][Switch]$Silent
)
if ($true -eq $Force) {
Remove-Item ".terraform" -ErrorAction SilentlyContinue -Recurse
Remove-Item "terraform.tfstate" -ErrorAction SilentlyContinue
Remove-Item "terraform.tfstate.backup" -ErrorAction SilentlyContinue
}
$CachePath = (Join-Path -Path $Env:APPDATA -ChildPath "terraform.d\plugin-cache")
if ( -not (Test-Path -Path $CachePath)) {
New-Item -Path $CachePath -ItemType Directory
}
$env:TF_PLUGIN_CACHE_DIR = $CachePath
Write-Host -ForegroundColor green ""
$Type = "sap_landscape"
Write-Host -ForegroundColor green "Deploying the" $Type
Add-Content -Path "deployment.log" -Value ("Deploying the: " + $Type)
Add-Content -Path "deployment.log" -Value (Get-Date -Format "yyyy-MM-dd HH:mm")
$fInfo = Get-ItemProperty -Path $Parameterfile
if ($false -eq $fInfo.Exists ) {
Write-Error ("File " + $Parameterfile + " does not exist")
return
}
$DataDir = Join-Path -Path $fInfo.Directory.FullName -ChildPath ".terraform"
$saName = $StorageAccountName
$repo = ""
$Environment = ""
$region = ""
$KeyValuePairs = @{}
if ($fInfo.Extension -eq ".tfvars") {
$paramContent = Get-Content -Path $Parameterfile
foreach ($param in $paramContent) {
if ($param.Contains("=")) {
$KeyValuePairs.Add($param.Split("=")[0].ToLower(), $param.Split("=")[1].Replace("""", ""))
}
}
$Environment = $KeyValuePairs["environment"]
$region = $KeyValuePairs["location"]
}
else {
$jsonData = Get-Content -Path $Parameterfile | ConvertFrom-Json
$Environment = $jsonData.infrastructure.environment
$region = $jsonData.infrastructure.region
}
$combined = $Environment + $region
$mydocuments = [environment]::getfolderpath("mydocuments")
$fileINIPath = $mydocuments + "\sap_deployment_automation.ini"
if ($false -eq (Test-Path $fileINIPath )) {
Write-Host "No ini file"
New-Item -Path $mydocuments -Name "sap_deployment_automation.ini" -ItemType "file" -Value "[$combined]`nDeployer=`nSubscription=$Subscription`nSTATE_SUBSCRIPTION=$State_subscription`nVault=$vault`nREMOTE_STATE_SA=$StorageAccountName" -Force
}
$iniContent = Get-IniContent -Path $fileINIPath
if ($true -eq $Force) {
$iniContent.Remove($combined)
Out-IniFile -InputObject $iniContent -Path $fileINIPath
$iniContent = Get-IniContent -Path $fileINIPath
}
$changed = $false
if ($null -eq $iniContent["Common"]) {
$repo = Read-Host -Prompt "Please enter path to the repo"
$Category1 = @{"repo" = $repo }
$iniContent += @{"Common" = $Category1 }
$changed = $true
}
else {
$repo = $iniContent["Common"]["repo"]
if ($null -eq $repo -or "" -eq $repo) {
$repo = Read-Host -Prompt "Please enter path to the repo"
$iniContent["Common"]["repo"] = $repo
$changed = $true
}
}
if ($changed) {
Out-IniFile -InputObject $iniContent -Path $fileINIPath
}
$terraform_module_directory = Join-Path -Path $repo -ChildPath "\deploy\terraform\run\$Type"
$Env:TF_DATA_DIR = $DataDir
$changed = $false
$landscape_tfstate_key = $fInfo.Name.replace($fInfo.Extension, ".terraform.tfstate")
$ctx = Get-AzContext
if ($null -eq $ctx) {
Connect-AzAccount
}
$foo = az account show
$accountData = $foo | ConvertFrom-Json
try {
if($accountData.user.cloudShellID)
{
Write-Error ("Please login using either an account or a Service Principal")
return
}
}
catch {
}
$current_Subscription = (Get-AzContext).Subscription.Id
if ($State_subscription.Length -gt 0) {
if ($current_Subscription -ne $State_subscription) {
Write-Host "Changing the subscription to: " $State_subscription
Select-AzSubscription -SubscriptionId $State_subscription
}
}
$deployercombined = $Environment + $region
$vaultName = ""
if ($null -eq $iniContent[$combined]) {
if ($StorageAccountName.Length -gt 0) {
$rID = Get-AzResource -Name $StorageAccountName -ResourceType Microsoft.Storage/storageAccounts
$rgName = $rID.ResourceGroupName
$tfstate_resource_id = $rID.ResourceId
$Category1 = @{"REMOTE_STATE_RG" = $rgName; "REMOTE_STATE_SA" = $StorageAccountName; "tfstate_resource_id" = $tfstate_resource_id ; "Landscape" = $landscape_tfstate_key; "Vault" = $Vault ; "STATE_SUBSCRIPTION" = $State_subscription; "Subscription" = $Subscription }
$iniContent += @{$combined = $Category1 }
Out-IniFile -InputObject $iniContent -Path $fileINIPath
$iniContent = Get-IniContent -Path $fileINIPath
}
else {
if ($StorageAccountName.Length -gt 0) {
}
else {
if ($null -ne $Deployerenvironment -and "" -ne $Deployerenvironment) {
$deployercombined = $Deployerenvironment + $region
}
else {
$Deployerenvironment = Read-Host -Prompt "Please specify the environment name for the deployer"
$deployercombined = $Deployerenvironment + $region
}
if ($null -ne $iniContent[$deployercombined]) {
Write-Host "Reading the state information from the deployer"
if ($StorageAccountName.Length -eq 0) {
$rgName = $iniContent[$deployercombined]["REMOTE_STATE_RG"]
$saName = $iniContent[$deployercombined]["REMOTE_STATE_SA"]
$tfstate_resource_id = $iniContent[$deployercombined]["tfstate_resource_id"]
$deployer_tfstate_key = $iniContent[$deployercombined]["Deployer"]
$vault = $iniContent[$deployercombined]["Vault"]
$Category1 = @{"REMOTE_STATE_RG" = $rgName; "REMOTE_STATE_SA" = $saName; "tfstate_resource_id" = $tfstate_resource_id ; "Landscape" = $landscape_tfstate_key; "Deployer" = $deployer_tfstate_key; "Vault" = $Vault; }
$iniContent += @{$combined = $Category1 }
Out-IniFile -InputObject $iniContent -Path $fileINIPath
$iniContent = Get-IniContent -Path $fileINIPath
}
}
else {
if ($StorageAccountName.Length -eq 0) {
Write-Error "The Terraform state information is not available"
$saName = Read-Host -Prompt "Please specify the storage account name for the terraform storage account"
$rID = Get-AzStorageAccount -Name $saName
$rgName = $rID.ResourceGroupName
$tfstate_resource_id = $rID.ResourceId
$Category1 = @{"REMOTE_STATE_RG" = $rgName; "REMOTE_STATE_SA" = $saName; "tfstate_resource_id" = $tfstate_resource_id ; "Landscape" = $landscape_tfstate_key }
$iniContent += @{$combined = $Category1 }
Out-IniFile -InputObject $iniContent -Path $fileINIPath
$iniContent = Get-IniContent -Path $fileINIPath
}
}
}
}
}
else {
$deployer_tfstate_key = $iniContent[$combined]["Deployer"]
if ($null -eq $deployer_tfstate_key -or "" -eq $deployer_tfstate_key) {
$deployer_tfstate_key = $Deployerstatefile
$iniContent[$combined]["Deployer"] = $Deployerstatefile
}
$iniContent[$combined]["Landscape"] = $landscape_tfstate_key
$changed = $true
Out-IniFile -InputObject $iniContent -Path $fileINIPath
$iniContent = Get-IniContent -Path $fileINIPath
}
# Subscription
$sub = $iniContent[$combined]["subscription"]
if ($sub -ne $Subscription) {
$sub = $Subscription
$iniContent[$combined]["subscription"] = $Subscription
$changed = $true
}
if ($null -eq $sub -or "" -eq $sub) {
$sub = Read-Host -Prompt "Please enter the subscription for the deployment"
$iniContent[$combined]["subscription"] = $sub
$changed = $true
}
$vaultname = $iniContent[$combined]["Vault"]
if ($Vault -ne $vaultname) {
$vaultname = $Vault
$iniContent[$combined]["Vault"] = $vaultname
$changed = $true
}
$state_subscription_id = $iniContent[$combined]["STATE_SUBSCRIPTION"]
if ($State_subscription -ne $state_subscription_id) {
$state_subscription_id = $State_subscription
$iniContent[$combined]["STATE_SUBSCRIPTION"] = $state_subscription_id
$changed = $true
}
if ($changed) {
Out-IniFile -InputObject $iniContent -Path $fileINIPath
}
$bAsk = $true
if ($null -ne $vault -and "" -ne $vault) {
if ($null -eq (Get-AzKeyVaultSecret -VaultName $vaultname -Name ($Environment + "-client-id") )) {
$bAsk = $true
if (($null -ne $SPN_id) -and ($null -ne $SPN_password) -and ($null -ne $Tenant_id)) {
Set-SAPSPNSecrets -Region $region -Environment $Environment -VaultName $vaultname -SPN_id $SPN_id -SPN_password $SPN_password -Tenant_id $Tenant_id -Workload
$iniContent = Get-IniContent -Path $fileINIPath
$step = 2
$iniContent[$combined]["step"] = $step
Out-IniFile -InputObject $iniContent -Path $fileINIPath
$bAsk = $false
}
}
else {
$bAsk = $false
}
}
if ($bAsk) {
$ans = Read-Host -Prompt "Do you want to enter the Workload SPN secrets Y/N?"
if ("Y" -eq $ans) {
$vault = $iniContent[$combined]["Vault"]
if (($null -eq $vault ) -or ("" -eq $vault)) {
$vault = Read-Host -Prompt "Please enter the vault name"
$iniContent[$combined]["Vault"] = $vault
Out-IniFile -InputObject $iniContent -Path $fileINIPath
}
try {
Set-SAPSPNSecrets -Region $region -Environment $Environment -VaultName $vault -Workload
$iniContent = Get-IniContent -Path $fileINIPath
}
catch {
return
}
}
}
if ($StorageAccountName.Length -gt 0) {
$saName = $StorageAccountName
}
else {
if ($iniContent[$combined]["REMOTE_STATE_SA"].Trim().Length -gt 0) {
$saName = $iniContent[$combined]["REMOTE_STATE_SA"].Trim()
}
}
if ($null -eq $saName -or "" -eq $saName) {
$saName = Read-Host -Prompt "Please specify the storage account name for the terraform storage account"
$rID = Get-AzResource -Name $saName -ResourceType Microsoft.Storage/storageAccounts
$rgName = $rID.ResourceGroupName
$tfstate_resource_id = $rID.ResourceId
$iniContent[$combined]["REMOTE_STATE_SA"] = $saName
$iniContent[$combined]["REMOTE_STATE_RG"] = $rgName
$iniContent[$combined]["tfstate_resource_id"] = $tfstate_resource_id
Out-IniFile -InputObject $iniContent -Path $fileINIPath
}
if ($null -eq $tfstate_resource_id -or "" -eq $tfstate_resource_id) {
if ($null -ne $saName -and "" -ne $saName) {
$rID = Get-AzResource -Name $saName -ResourceType Microsoft.Storage/storageAccounts
$rgName = $rID.ResourceGroupName
$tfstate_resource_id = $rID.ResourceId
$iniContent[$combined]["REMOTE_STATE_RG"] = $rgName
$iniContent[$combined]["tfstate_resource_id"] = $tfstate_resource_id
Out-IniFile -InputObject $iniContent -Path $fileINIPath
}
}
Write-Host -ForegroundColor green "Initializing Terraform New-SAPWorkloadZone"
$terraform_module_directory = Join-Path -Path $repo -ChildPath "\deploy\terraform\run\$Type"
$Env:TF_DATA_DIR = (Join-Path -Path $fInfo.Directory.FullName -ChildPath ".terraform")
Write-Host -ForegroundColor green "Initializing Terraform New-SAPWorkloadZone"
$Command = " init -upgrade=true -reconfigure -backend-config ""subscription_id=$state_subscription_id"" -backend-config ""resource_group_name=$rgName"" -backend-config ""storage_account_name=$saName"" -backend-config ""container_name=tfstate"" -backend-config ""key=$envkey"" "
if (Test-Path ".terraform" -PathType Container) {
if (Test-Path ".\.terraform\terraform.tfstate" -PathType Leaf) {
$jsonData = Get-Content -Path .\.terraform\terraform.tfstate | ConvertFrom-Json
if ("azurerm" -eq $jsonData.backend.type) {
$Command = " init -upgrade=true"
}
}
}
$Cmd = "terraform -chdir=$terraform_module_directory $Command"
Add-Content -Path "deployment.log" -Value $Cmd
Write-Verbose $Cmd
& ([ScriptBlock]::Create($Cmd))
if ($LASTEXITCODE -ne 0) {
$Env:TF_DATA_DIR = $null
throw "Error executing command: $Cmd"
}
$deployer_tfstate_key_parameter = ""
$tfstate_parameter = " -var tfstate_resource_id=" + $tfstate_resource_id
if ($Deployerstatefile.Length -gt 0) {
$deployer_tfstate_key_parameter = " -var deployer_tfstate_key=" + $Deployerstatefile
}
else {
if ($deployer_tfstate_key.Length -gt 0) {
$deployer_tfstate_key_parameter = " -var deployer_tfstate_key=" + $deployer_tfstate_key
}
}
$Command = " init -upgrade=true -backend-config ""subscription_id=$state_subscription_id"" -backend-config ""resource_group_name=$rgName"" -backend-config ""storage_account_name=$saName"" -backend-config ""container_name=tfstate"" -backend-config ""key=$envkey"" "
if (Test-Path ".terraform" -PathType Container) {
if (Test-Path ".\.terraform\terraform.tfstate" -PathType Leaf) {
$jsonData = Get-Content -Path .\.terraform\terraform.tfstate | ConvertFrom-Json
if ("azurerm" -eq $jsonData.backend.type) {
$Command = " init -upgrade=true"
}
}
}
$Cmd = "terraform -chdir=$terraform_module_directory $Command"
Add-Content -Path "deployment.log" -Value $Cmd
Write-Verbose $Cmd
& ([ScriptBlock]::Create($Cmd))
if ($LASTEXITCODE -ne 0) {
$Env:TF_DATA_DIR = $null
throw "Error executing command: $Cmd"
}
$deployer_tfstate_key_parameter = ""
$tfstate_parameter = " -var tfstate_resource_id=" + $tfstate_resource_id
if ($Deployerstatefile.Length -gt 0) {
$deployer_tfstate_key_parameter = " -var deployer_tfstate_key=" + $Deployerstatefile
}
else {
if ($deployer_tfstate_key.Length -gt 0) {
$deployer_tfstate_key_parameter = " -var deployer_tfstate_key=" + $deployer_tfstate_key
}
}
Write-Host -ForegroundColor green "Running refresh, please wait"
$Command = " refresh -var-file " + $fInfo.Fullname + $tfstate_parameter + $landscape_tfstate_key_parameter + $deployer_tfstate_key_parameter
$Cmd = "terraform -chdir=$terraform_module_directory $Command"
Add-Content -Path "deployment.log" -Value $Cmd
Write-Verbose $Cmd
$Command = " output automation_version"
$Cmd = "terraform -chdir=$terraform_module_directory $Command"
Add-Content -Path "deployment.log" -Value $Cmd
Write-Verbose $Cmd
$versionLabel = & ([ScriptBlock]::Create($Cmd)) | Out-String
if ("" -eq $versionLabel) {
Write-Host ""
Write-Host -ForegroundColor red "The environment was deployed using an older version of the Terrafrom templates"
Write-Host ""
Write-Host -ForegroundColor red "!!! Risk for Data loss !!!"
Write-Host ""
Write-Host -ForegroundColor red "Please inspect the output of Terraform plan carefully before proceeding"
Write-Host ""
if ($PSCmdlet.ShouldProcess($Parameterfile)) {
$ans = Read-Host -Prompt "Do you want to continue Y/N?"
if ("Y" -eq $ans) {
}
else {
$Env:TF_DATA_DIR = $null
return
}
}
}
else {
Write-Host ""
Write-Host -ForegroundColor green "The environment was deployed using the $versionLabel version of the Terrafrom templates"
Write-Host ""
Write-Host ""
}
Write-Host -ForegroundColor green "Running plan, please wait"
$Command = " plan -no-color -var-file " + $fInfo.Fullname + $tfstate_parameter + $landscape_tfstate_key_parameter + $deployer_tfstate_key_parameter
$Cmd = "terraform -chdir=$terraform_module_directory $Command"
Add-Content -Path "deployment.log" -Value $Cmd
Write-Verbose $Cmd
$planResults = & ([ScriptBlock]::Create($Cmd)) | Out-String
if ($LASTEXITCODE -ne 0) {
$Env:TF_DATA_DIR = $null
throw "Error executing command: $Cmd"
}
$planResultsPlain = $planResults -replace '\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]', ''
if ( $planResultsPlain.Contains('Infrastructure is up-to-date')) {
Write-Host ""
Write-Host -ForegroundColor Green "Infrastructure is up to date"
Write-Host ""
$Env:TF_DATA_DIR = $null
return;
}
Write-Host $planResults
if (-not $planResultsPlain.Contains('0 to change, 0 to destroy') ) {
Write-Host ""
Write-Host -ForegroundColor red "!!! Risk for Data loss !!!"
Write-Host ""
Write-Host -ForegroundColor red "Please inspect the output of Terraform plan carefully before proceeding"
Write-Host ""
if ($PSCmdlet.ShouldProcess($Parameterfile)) {
$ans = Read-Host -Prompt "Do you want to continue Y/N?"
if ("Y" -ne $ans) {
$Env:TF_DATA_DIR = $null
return
}
}
}
if ($PSCmdlet.ShouldProcess($Parameterfile)) {
Write-Host -ForegroundColor green "Running apply"
if ($Silent) {
$Command = " apply --auto-approve -var-file " + $fInfo.Fullname + $tfstate_parameter + $landscape_tfstate_key_parameter + $deployer_tfstate_key_parameter
}
else {
$Command = " apply -var-file " + $fInfo.Fullname + $tfstate_parameter + $landscape_tfstate_key_parameter + $deployer_tfstate_key_parameter
}
Add-Content -Path "deployment.log" -Value $Cmd
Write-Verbose $Cmd
$Cmd = "terraform -chdir=$terraform_module_directory $Command"
& ([ScriptBlock]::Create($Cmd))
if ($LASTEXITCODE -ne 0) {
$Env:TF_DATA_DIR = $null
throw "Error executing command: $Cmd"
}
}
$Env:TF_DATA_DIR = $null
}