testscripts/setup.ps1 (330 lines of code) (raw):
<#
.SYNOPSIS
Sets the deployment up with one command. This tries to be smart about
what you want and does the provisioning and deployment steps in one
command.
.DESCRIPTION
When installing the Relecloud web app, you have to make many choices - are
you running in network isolation mode? Do you need a hub? Would you like
to save money by deploying with a common app service plan? This script
will prompt you for these choices and then deploy the infrastructure for
you.
.PARAMETER CommonAppServicePlan
If included, deploy a common app service plan.
.PARAMETER NoCommonAppServicePlan
If included, do not deploy a common app service plan.
.PARAMETER Hub
If included, deploy a hub network. No effect if not using network isolation
.PARAMETER NoHub
If included, do not deploy a hub network.
.PARAMETER Isolated
If included, isolate the application in a VNET.
.PARAMETER NotIsolated
If included, do not isolate the application in a VNET.
.PARAMETER Name
The environment name to use.
.PARAMETER Production
If included, use production settings.
.PARAMETER Development
If included, use development settings.
.PARAMETER SingleLocation
The default behavior creating an Azure deployment targeting a single Azure region.
.PARAMETER MultiLocation
If included, do not prompt for any information. This will use the default
settings for all options.
.PARAMETER NoPrompt
If included, do not prompt for any information. This will use the default
settings for all options.
#>
Param(
[switch]$CommonAppServicePlan,
[switch]$NoCommonAppServicePlan,
[switch]$Hub,
[switch]$NoHub,
[switch]$Isolated,
[switch]$NotIsolated,
[string]$Name = "",
[switch]$Production,
[switch]$Development,
[switch]$NoPrompt,
[switch]$SingleLocation,
[string]$AzureLocation = "",
[switch]$MultiLocation,
[string]$SecondAzureLocation = ""
)
function FormatMenu {
param([array]$items, [int]$position)
for ($i = 0 ; $i -le $items.Length; $i++) {
$item = $items[$i]
if ($i -eq $position) {
Write-Host "> $($item)" -ForegroundColor Green
} else {
Write-Host " $($item)"
}
}
}
function ShowMenu {
param([string]$title, [array]$keys, [array]$items, [string]$defaultValue)
$vkeycode = 0
$pos = [array]::FindIndex($keys, [Predicate[string]] { param($s) $s -eq $defaultValue })
$startPos = [System.Console]::CursorTop
if ($items.Length -gt 0) {
try {
[System.Console]::CursorVisible = $false
FormatMenu -items $items -position $pos
while ($vkeycode -ne 13 -and $vkeycode -ne 27) {
$press = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
$vkeycode = $press.VirtualKeyCode
if ($vkeycode -eq 27) {
Write-Host "`nERROR: Escape pressed; aborting setup" -ForegroundColor Red
[System.Console]::CursorVisible = $true
[System.Environment]::Exit(1)
}
if ($vkeycode -eq 35) {
$pos = $items.Length - 1
}
if ($vkeycode -eq 36) {
$pos = 0
}
if ($vkeycode -eq 38 -or $press.Character -eq 'k') {
$pos--
}
if ($vkeycode -eq 40 -or $press.Character -eq 'j') {
$pos++
}
if ($pos -lt 0) {
$pos = 0
}
if ($pos -ge $items.Length) {
$pos = $items.Length - 1
}
[System.Console]::SetCursorPosition(0, $startPos)
FormatMenu -items $items -position $pos
}
}
finally {
$yPos = $startPos + $items.Length
if ($yPos -ge $Host.UI.RawUI.BufferSize.Height) {
Clear-Host
} else {
[System.Console]::SetCursorPosition(0, $yPos)
}
[System.Console]::CursorVisible = $true
}
}
else {
Write-Host "`nERROR: No items provided for question; aborting setup" -ForegroundColor Red
[System.Console]::CursorVisible = $true
[System.Environment]::Exit(1)
}
return $keys[$pos]
}
# End of function definitions
# Check for required features
if ((Get-Module -ListAvailable -Name Az) -and (Get-Module -Name Az.Resources -ErrorAction SilentlyContinue)) {
Write-Debug "The 'Az.Resources' module is installed and imported."
if (Get-AzContext -ErrorAction SilentlyContinue) {
Write-Debug "The user is authenticated with Azure."
}
else {
Write-Error "You are not authenticated with Azure. Please run 'Connect-AzAccount' to authenticate before running this script."
exit 10
}
}
else {
try {
Write-Host "Importing 'Az.Resources' module"
Import-Module -Name Az.Resources -ErrorAction Stop
Write-Debug "The 'Az.Resources' module is imported successfully."
if (Get-AzContext -ErrorAction SilentlyContinue) {
Write-Debug "The user is authenticated with Azure."
}
else {
Write-Error "You are not authenticated with Azure. Please run 'Connect-AzAccount' to authenticate before running this script."
exit 11
}
}
catch {
Write-Error "Failed to import the 'Az' module. Please install and import the 'Az' module before running this script."
exit 12
}
}
# End of feature checking
# Check for conflicting parameters
if ($CommonAppServicePlan -and $NoCommonAppServicePlan) {
"You cannot specify both -CommonAppServicePlan and -NoCommonAppServicePlan"
exit 1
}
if ($Hub -and $NoHub) {
"You cannot specify both -Hub and -NoHub"
exit 1
}
if ($Isolated -and $NotIsolated) {
"You cannot specify both -Isolated and -NotIsolated"
exit 1
}
if ($Production -and $Development) {
"You cannot specify both -Production and -Development"
exit 1
}
if ($SingleLocation -and $MultiLocation) {
"You cannot specify both -SingleLocation and -MultiLocation"
exit 1
}
if ($Production -and $NotIsolated) {
"The Production scenario requires network isolation to be enabled"
exit 1
}
if (!$SingleLocation -and !$MultiLocation -and !$NotIsolated) {
"You must specify either -SingleLocation or -MultiLocation"
exit 1
}
if ($Isolated -and $NoHub) {
Write-Host 'Warning:' -ForegroundColor Yellow -BackgroundColor Black
Write-Host "When deployed with isolation certain features, and access, will only be availble from within the vnet. You must attach a hub to activate these features."
}
# End of parameter checking
# Start of script
Write-Host "Relecloud Application Setup" -ForegroundColor Yellow -BackgroundColor Black
$defaultEmailAddress = (Get-AzContext).Account.Id
if (!$NoPrompt) {
$emailAddr = Read-Host -Prompt "`nWhat is your email address? [default: $defaultEmailAddress]"
if ($emailAddr -eq "") {
$emailAddr = $defaultEmailAddress
}
}
$defaultName = (Get-AzAdUser -UserPrincipalName $emailAddr).DisplayName
if (!$NoPrompt) {
$ownerName = Read-Host -Prompt "`nWhat is your name? [default: $defaultName]"
if ($ownerName -eq "") {
$ownerName = $defaultName
}
if ($ownerName -eq "") {
$ownerName = $emailAddr
}
}
$currentDate = Get-Date -Format "yyyyMMddHHmm"
$defaultName = "fe-$currentDate"
$environmentName = $defaultName
$truefalse = @("true", "false")
if ($Name -ne "") {
$environmentName = $Name
} elseif (!$NoPrompt) {
$environmentName = Read-Host -Prompt "`nWhat should the environment name be? [default: $defaultName]"
if ($environmentName -eq "") {
$environmentName = $defaultName
}
}
$environmentType = "dev"
if ($Development) {
$environmentType = "dev"
} elseif ($Production) {
$environmentType = "prod"
} elseif (!$NoPrompt) {
Write-Host "`nWhat environment stage are you deploying?"
$items = @( "Development", "Production" )
$environmentType = ShowMenu -keys @( "dev", "prod") -items $items -defaultValue $environmentType
}
$networkIsolation = $environmentType -eq "prod"
if ($Isolated) {
$networkIsolation = $true
} elseif ($NotIsolated) {
$networkIsolation = $false
} elseif (!$NoPrompt) {
Write-Host "`nDo you want the environment to be network isolated (in a VNET)?"
$items = @( "Yes - use network isolation", "No - do not use network isolation" )
$isIsolated = ShowMenu -keys $truefalse -items $items -defaultValue $(if ($networkIsolation -eq $true) { "true" } else { "false" })
$networkIsolation = $isIsolated -eq "true"
}
$deployHubNetwork = $networkIsolation -eq $true -and $environmentType -eq "dev"
if ($networkIsolation) {
if ($Hub) {
$deployHubNetwork = $true
} elseif ($NoHub) {
$deployHubNetwork = $false
} elseif (!$NoPrompt) {
Write-Host "`nDo you want to deploy a hub network with an Azure Firewall, Bastion, and Jump box?"
$items = @( "Yes - deploy a hub network", "No - do not deploy a hub network" )
$useHub = ShowMenu -keys $truefalse -items $items -defaultValue $(if ($deployHubNetwork -eq $true) { "true" } else { "false" })
$deployHubNetwork = $useHub -eq "true"
}
}
$casp = $environmentType -eq "dev"
if ($CommonAppServicePlan) {
$casp = $true
} elseif ($NoCommonAppServicePlan) {
$casp = $false
} elseif (!$NoPrompt) {
Write-Host "`nDo you want to use a common App Service Plan for all App Services?"
$items = @( "Use a common App Service Plan for all App Services", "Use a dedicated App Service Plan for each App Service" )
$sCasp = ShowMenu -keys $truefalse -items $items -defaultValue $(if ($casp -eq $true) { "true" } else { "false" })
$casp = $sCasp -eq "true"
}
$defaultAzureLocation = "westus3"
# if azure location was set then use it, otherwise use the default
$azureLocationCmd = $AzureLocation
if ($null -eq $AzureLocation -or $AzureLocation -eq "") {
$azureLocationCmd = $defaultAzureLocation
}
$defaultSecondAzureLocation = "eastus"
if ($null -eq $SecondAzureLocation -or $SecondAzureLocation -eq "") {
$secondAzureLocationCmd = $defaultSecondAzureLocation
}
$subscriptionName = (Get-AzContext).Subscription.Name
Write-Host "`nProposed settings:" -ForegroundColor Yellow
Write-Host "`tSubscription name: $subscriptionName"
Write-Host "`tOwner name: $ownerName"
Write-Host "`tEmail address: $emailAddr"
Write-Host "`tEnvironment name: $environmentName"
Write-Host "`tEnvironment type: $environmentType"
Write-Host "`tNetwork isolation: $networkIsolation"
Write-Host "`tDeploy hub network: $deployHubNetwork"
Write-Host "`tAzure location: $azureLocationCmd"
Write-Host "`tDeploy second location: $MultiLocation"
if ($MultiLocation) {
Write-Host "`tSecond Azure location: $secondAzureLocationCmd"
}
Write-Host "`tUse common App Service Plan: $casp"
if (!$NoPrompt) {
Write-Host "`nDo you want to proceed with the deployment?"
$items = @("Continue to deployment.", "Cancel deployment.")
$q = ShowMenu -keys $truefalse -items $items -defaultValue "false"
if ($q -eq "false") {
exit 0
}
}
# Check if any object has the "Name" property equal to "$environmentName"
$jsonEnvironmentOutput = (azd env list -o json)
$envList = $jsonEnvironmentOutput | ConvertFrom-Json
$environmentFound = $false
foreach ($env in $envList) {
if ($env.Name -eq $environmentName) {
$environmentFound = $true
break
}
}
if ($environmentFound) {
Write-Host "`nWARNING: Environment $environmentName already exists. " -ForegroundColor Yellow
# Select the existing environment
azd env select $environmentName
} else {
# Create the environment
azd env new $environmentName
}
$azureSubscriptionId = (Get-AzContext).Subscription.Id
azd env set AZURE_SUBSCRIPTION_ID $azureSubscriptionId
azd env set AZURE_LOCATION $azureLocationCmd
azd env set AZURE_ENV_TYPE $environmentType
azd env set NETWORK_ISOLATION $(if ($networkIsolation) { "true" } else { "false" })
azd env set DEPLOY_HUB_NETWORK $(if ($deployHubNetwork) { "true" } else { "false" })
azd env set COMMON_APP_SERVICE_PLAN $(if ($casp) { "true" } else { "false" })
azd env set OWNER_EMAIL $emailAddr
azd env set OWNER_NAME "$ownerName"
if ($MultiLocation) {
azd env set SECONDARY_AZURE_LOCATION $secondAzureLocationCmd
}
if ($NoPrompt) {
azd provision --no-prompt
} else {
azd provision
}