cluster_azure-repository_app-service/cluster_azure-repository_app-service.ps1 (316 lines of code) (raw):

<# .Synopsis Deploys an Azure Storage Account, Elasticsearch cluster and Azure App Service. .Description The Storage account is configured with the azure-repository plugin to be used for snapshot/restore for the Elasticsearch cluster. The Azure App Service is connected to the Virtual Network deployed as part of the cluster so that it can connect to the cluster. .Example & .\cluster_azure-repository_app-service.ps1 -AdminUserName "russ" ` -AdminPassword $(ConvertTo-SecureString -String "Password1234" -AsPlainText -Force) ` -SecurityAdminPassword $(ConvertTo-SecureString -String "Password123" -AsPlainText -Force) ` -SecurityReadPassword $(ConvertTo-SecureString -String "Password123" -AsPlainText -Force) ` -SecurityKibanaPassword $(ConvertTo-SecureString -String "Password123" -AsPlainText -Force) .Example & .\cluster_azure-repository_app-service.ps1 -ClientId "clientid" ` -ClientSecret $(ConvertTo-SecureString -String "clientsecret" -AsPlainText -Force) ` -TenantId "tenantid" -SubscriptionId "subscriptionid" ` -AdminUserName "russ" -AdminPassword $(ConvertTo-SecureString -String "Password1234" -AsPlainText -Force) ` -SecurityAdminPassword $(ConvertTo-SecureString -String "Password123" -AsPlainText -Force) ` -SecurityReadPassword $(ConvertTo-SecureString -String "Password123" -AsPlainText -Force) ` -SecurityKibanaPassword $(ConvertTo-SecureString -String "Password123" -AsPlainText -Force) .Parameter ClientId the client id to log in with a Service Principal .Parameter ClientSecret the client secret to log in with a Service Principal .Parameter TenantId the tenant id to log in with a Service Principal .Parameter SubscriptionId the subscription id to deploy the resources to. If the current session is not logged into the Azure account, user will be prompted to log in and select a SubscriptionId .Parameter AdminUserName the admin username in order to log into VMs deployed in the Elasticsearch cluster .Parameter AdminPassword the admin password in order to log into VMs deployed in the Elasticsearch cluster .Parameter SecurityAdminPassword the password to log into the Elasticsearch cluster through X-Pack Security with user 'es_admin' (2.x) or 'elastic' (5.x) .Parameter SecurityReadPassword the password to log into the Elasticsearch cluster through X-Pack Security with user 'es_read' .Parameter SecurityKibanaPassword the password to log into the Elasticsearch cluster through X-Pack Security with user 'es_kibana' #> [CmdletBinding()] Param( [Parameter(Mandatory=$false)] [string] $ClientId, [Parameter(Mandatory=$false)] [securestring] $ClientSecret, [Parameter(Mandatory=$false)] [string] $TenantId, [Parameter(Mandatory=$false)] [string] $SubscriptionId, [Parameter(Mandatory=$true)] [string] $AdminUserName, [Parameter(Mandatory=$true)] [securestring] $AdminPassword, [Parameter(Mandatory=$true)] [securestring] $SecurityAdminPassword, [Parameter(Mandatory=$true)] [securestring] $SecurityReadPassword, [Parameter(Mandatory=$true)] [securestring] $SecurityKibanaPassword ) $ErrorActionPreference = "Stop" function Write-Log($Message, $ForegroundColor) { if ($ForegroundColor -eq $null) { $ForegroundColor = "White" } Write-Host "[$(Get-Date -format 'u')] $message" -ForegroundColor $ForegroundColor } function Show-Custom($title, $optionValues, $optionDescriptions) { Write-Host $title Write-Host for($i = 0; $i -lt $optionValues.Length; $i++) { Write-Host "$($i+1))" $optionDescriptions[$i] } Write-Host while($true) { Write-Host "Choose an option: " $option = Read-Host $option = $option -as [int] if($option -ge 1 -and $option -le $optionValues.Length) { return $optionValues[$option-1] } } } function Show-Subscription() { # Choose subscription. If there's only one we will choose automatically $subs = Get-AzureRmSubscription $subscriptionId = "" if($subs.Length -eq 0) { Write-Error "No subscriptions bound to this account." return } if($subs.Length -eq 1) { $subscriptionId = $subs[0].SubscriptionId } else { $subscriptionChoices = @() $subscriptionValues = @() foreach($subscription in $subs) { $subscriptionChoices += "$($subscription.SubscriptionName) ($($subscription.SubscriptionId))"; $subscriptionValues += ($subscription.SubscriptionId); } $subscriptionId = Show-Custom "Choose a subscription" $subscriptionValues $subscriptionChoices } return $subscriptionId } function New-StorageAccount($storageAccountResourceGroup, $storageAccountName, $location) { $account = Get-AzureRmStorageAccount -ResourceGroupName $storageAccountResourceGroup -Name $storageAccountName -ErrorAction Ignore if ($account -ne $null) { Write-Log "Storage account $storageAccountName in resource group $storageAccountResourceGroup already exists. Using this." -ForegroundColor "green" return } Write-Log "Creating Storage account $storageAccountName in resource group $storageAccountResourceGroup" New-AzureRmResourceGroup -Name $storageAccountResourceGroup -Location $location New-AzureRmStorageAccount -ResourceGroupName $storageAccountResourceGroup -AccountName $storageAccountName -Type "Standard_LRS" -Location $location Write-Log "Finished creating Storage account" -ForegroundColor "green" } function New-ElasticsearchCluster($resourceGroupName, $clusterName, $location, $elasticTemplateUri, $elasticParameters) { $resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName -Location $location -ErrorAction Ignore if ($resourceGroup -ne $null) { Write-Log "Resource group $resourceGroupName already exists. Using this." -ForegroundColor "green" return } Write-Log "Deploying Elasticsearch cluster $clusterName from $elasticTemplateUri" New-AzureRmResourceGroup -Name $resourceGroupName -Location $location New-AzureRmResourceGroupDeployment -Name $clusterName -ResourceGroupName $resourceGroupName -TemplateUri $elasticTemplateUri -TemplateParameterObject $elasticParameters Write-Log "Finished Deploying Elasticsearch cluster" -ForegroundColor "green" } function New-Website($resourceGroupName, $webAppName, $location, $webAppParameters) { $resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName -Location $location -ErrorAction Ignore if ($resourceGroup -ne $null) { Write-Log "Resource group $resourceGroupName already exists. Using this." -ForegroundColor "green" return } $deployFromGithubTemplate = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-web-app-github-deploy/azuredeploy.json" New-AzureRmResourceGroup -Name $resourceGroupName -Location $location New-AzureRmResourceGroupDeployment -Name $webAppName -ResourceGroupName $resourceGroupName ` -TemplateUri $deployFromGithubTemplate -TemplateParameterObject $webAppParameters Write-Log "Finished Deploying Nusearch website" -ForegroundColor "green" } function Add-VNetGateway($resourceGroupName, $vnetName, $vnetIpName, $location, $vnetIpConfigName, $vnetGatewayName, $certificateData, $vnetPointToSiteAddressSpace) { $gateway = Get-AzureRmVirtualNetworkGateway -Name $vnetGatewayName -ResourceGroupName $resourceGroupName -ErrorAction Ignore if ($gateway -ne $null) { Write-Log "Virtual Network Gateway $vnetGatewayName already exists. Using this." -ForegroundColor "green" return } $vnet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $resourceGroupName $subnet = Get-AzureRmVirtualNetworkSubnetConfig -Name "GatewaySubnet" -VirtualNetwork $vnet Write-Log "Creating a public IP address for this Virtual Network" $pip = New-AzureRmPublicIpAddress -Name $vnetIpName -ResourceGroupName $resourceGroupName -Location $location -AllocationMethod Dynamic $ipconf = New-AzureRmVirtualNetworkGatewayIpConfig -Name $vnetIpConfigName -Subnet $subnet -PublicIpAddress $pip Write-Log "Finished creating a public IP address for this Virtual Network" -ForegroundColor "green" Write-Log "Adding a root certificate to this Virtual Network" $root = New-AzureRmVpnClientRootCertificate -Name "AppServiceCertificate.cer" -PublicCertData $certificateData Write-Log "Finished Adding a root certificate to this Virtual Network" -ForegroundColor "green" Write-Log "Creating Virtual Network Gateway. This may take up to an hour." $gateway = New-AzureRmVirtualNetworkGateway -Name $vnetGatewayName -ResourceGroupName $resourceGroupName ` -Location $location -IpConfigurations $ipconf -GatewayType Vpn -VpnType RouteBased -EnableBgp $false ` -GatewaySku Basic -VpnClientAddressPool $vnetPointToSiteAddressSpace -VpnClientRootCertificates $root Write-Log "Finished creating Virtual Network Gateway" -ForegroundColor "green" } function Add-AppServiceToExistingVnet($subscriptionId, $webAppResourceGroup, $webAppName, $vnetName, $vnetResourceGroup) { Write-Log "Getting App information" $webApp = Get-AzureRmResource -ResourceName $webAppName -ResourceType "Microsoft.Web/sites" ` -ApiVersion 2015-08-01 -ResourceGroupName $webAppResourceGroup $location = $webApp.Location $webAppConfig = Get-AzureRmResource -ResourceName "$($webAppName)/web" -ResourceType "Microsoft.Web/sites/config" ` -ApiVersion 2015-08-01 -ResourceGroupName $webAppResourceGroup $vnet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $vnetResourceGroup # Virtual Network settings $vnetName = $vnet.Name $vnetGatewayName="$($vnetName)-gateway" $vnetIpName="$($vnetName)-gateway-ip" $vnetIpConfigName="$($vnetName)-gateway-ip-conf" $vnetGatewayAddressSpace="10.0.0.128/28" $vnetPointToSiteAddressSpace="172.16.0.0/16" Write-Log "Creating Virtual Network Connection for website $webAppName to Virtual Network $($vnet.Name)" $virtualNetworkParameters = @{ "vnetResourceId" = "/subscriptions/$($subscriptionId)/resourceGroups/$($vnet.ResourceGroupName)/providers/Microsoft.Network/virtualNetworks/$($vnetName)" } $virtualNetworkConnection = New-AzureRmResource -Location $location -Properties $virtualNetworkParameters -ResourceName "$($webAppName)/$($vnet.Name)" -ResourceType "Microsoft.Web/sites/virtualNetworkConnections" -ApiVersion 2015-08-01 -ResourceGroupName $webAppResourceGroup -Force Write-Log "Virtual Network Connection created" -ForegroundColor "green" $gatewaySubnet = Get-AzureRmVirtualNetworkSubnetConfig -Name "GatewaySubnet" -VirtualNetwork $vnet -ErrorAction Ignore if ($gatewaySubnet -ne $null) { Write-Log "GatewaySubnet already exists for Virtual Network $($vnet.Name). Using this." -ForegroundColor "green" } else { Write-Log "Creating GatewaySubnet in Virtual Network $($vnet.Name)" Add-AzureRmVirtualNetworkSubnetConfig -Name "GatewaySubnet" -AddressPrefix $vnetGatewayAddressSpace -VirtualNetwork $vnet Set-AzureRmVirtualNetwork -VirtualNetwork $vnet Write-Log "GatewaySubnet created in Virtual Network $($vnet.Name)" -ForegroundColor "green" } # Create the VNet Gateway Add-VNetGateway $vnet.ResourceGroupName $vnetName $vnetIpName $location $vnetIpConfigName $vnetGatewayName $virtualNetworkConnection.Properties.CertBlob $vnetPointToSiteAddressSpace $gateway = Get-AzureRmVirtualNetworkGateway -ResourceGroupName $vnet.ResourceGroupName -Name $vnetGatewayName # Now finish joining by getting the VPN package and giving it to the App Write-Log "Retrieving VPN Package and supplying to Web App" $packageUri = Get-AzureRmVpnClientPackage -ResourceGroupName $vnet.ResourceGroupName -VirtualNetworkGatewayName $gateway.Name -ProcessorArchitecture Amd64 # Put the VPN client configuration package onto the App $virtualNetworkGatewayParameters = @{ "vnetName" = $vnet.Name; "vpnPackageUri" = $packageUri.ToString().Trim('"') } Write-Log "Adding website $webAppName to Virtual Network $($vnet.Name)" New-AzureRmResource -Location $location -Properties $virtualNetworkGatewayParameters -ResourceName "$($webAppName)/$($vnet.Name)/primary" -ResourceType "Microsoft.Web/sites/virtualNetworkConnections/gateways" -ApiVersion 2015-08-01 -ResourceGroupName $webAppResourceGroup -Force Write-Log "Finished adding website $webAppName to Virtual Network $($vnet.Name)" -ForegroundColor "green" } function Add-AppSettings($resourceGroupName, $webAppName, $appSettings) { Write-Log "Updating App Settings for website" $webApp = Get-AzureRMWebAppSlot -ResourceGroupName $resourceGroupName -Name $webAppName -Slot production $existingAppSettings = $webApp.SiteConfig.AppSettings $hash = @{} foreach ($kvp in $existingAppSettings) { $hash[$kvp.Name] = $kvp.Value } foreach ($kvp in $appSettings.GetEnumerator()) { $hash[$kvp.Name] = $kvp.Value } Set-AzureRMWebAppSlot -ResourceGroupName $resourceGroupName -Name $webAppName -AppSettings $hash -Slot production Write-Log "App Settings for website updated" -ForegroundColor "green" } ################## # Start of Process ################## try { if ($ClientId -and $ClientSecret -and $TenantId -and $SubscriptionId) { $credential = new-object -typename System.Management.Automation.PSCredential ` -argumentlist $ClientId, $ClientSecret Add-AzureRmAccount -Credential $credential -Tenant $TenantId -ServicePrincipal -ErrorAction Stop } Select-AzureRmSubscription -SubscriptionId $SubscriptionId -ErrorAction Stop } catch { Write-Host "Please Login" Login-AzureRmAccount $SubscriptionId = Show-Subscription Select-AzureRmSubscription -SubscriptionId $SubscriptionId } $location = "Australia Southeast" ################################################################################################# # Create the storage account, or use existing one if resource group with same name already exists ################################################################################################# $storageAccountResourceGroup = "nusearch-storage" $storageAccountName = "nusearchdata" New-StorageAccount $storageAccountResourceGroup $storageAccountName $location $storageAccountKeys = Get-AzureRmStorageAccountKey -ResourceGroupName $storageAccountResourceGroup -Name $storageAccountName ######################################################################################### # Create the cluster, or use existing one if resource group with same name already exists ######################################################################################### $templateVersion = "5.1.2" $clusterResourceGroup = "nusearch-cluster" $clusterName = "nusearch-cluster" $templateUrl = "https://raw.githubusercontent.com/elastic/azure-marketplace/$templateVersion/src" $mainTemplate = "$templateUrl/mainTemplate.json" # parameters match those of the version of the template that we are targeting $templateParameters = @{ "artifactsBaseUrl"= $templateUrl "esClusterName" = $clusterName "adminUsername" = $AdminUserName "vNetLoadBalancerIp" = "10.0.0.4" "vNetName" = "es-net" "authenticationType" = "password" "adminPassword" = $AdminPassword "securityAdminPassword" = $SecurityAdminPassword "securityReadPassword" = $SecurityReadPassword "securityKibanaPassword" = $SecurityKibanaPassword "azureCloudPlugin" = "Yes" "azureCloudStorageAccountName" = $storageAccountName "azureCloudStorageAccountKey" = $storageAccountKeys[0].Value } New-ElasticsearchCluster $clusterResourceGroup $clusterName $location $mainTemplate $templateParameters ######################################################################################### # Create the website, or use existing one if resource group with same name already exists ######################################################################################### $webAppResourceGroup = "nusearch-web" $webAppName = "nusearch-app" $webAppParameters = @{ "siteName" = $webAppName "hostingPlanName" = "nusearch" "sku" = "S1" "workerSize" = "1" "repoURL" = "https://github.com/elastic/elasticsearch-net-example.git" "branch" = "5.x-deploy" } New-Website $webAppResourceGroup $webAppName $location $webAppParameters ######################################## # Add the website to the Virtual Network ######################################## Add-AppServiceToExistingVnet $subscriptionId $webAppResourceGroup $webAppName $templateParameters.vNetName $clusterResourceGroup ################################################################################ # Update the app settings for the website to point to the internal load balancer ################################################################################ $appSettings = @{ "ElasticClient:Host" = "$($templateParameters.vNetLoadBalancerIp)" "ElasticClient:Username" = "es_read" "ElasticClient:Password" = $SecurityReadPassword } Add-AppSettings $webAppResourceGroup $webAppName $appSettings <# TODO: automate these as part of the example Configure azure repository for snapshots ---------------------------------------- PUT _snapshot/nusearchdata { "type": "azure", "settings": { "container": "backups" } } POST _snapshot/nusearchdata/_verify GET _snapshot/nusearchdata/_all POST /_snapshot/nusearchdata/snapshot_1/_restore?wait_for_completion=true Need to Sync Network in Azure Portal! ------------------------------------- nusearch-web -> App Service Plan -> Networking -> VNet Integration -> click network name -> click Sync Network #>