frameworkResources/Scripts/add_servers.ps1
Param( [Parameter(Mandatory)] $VmCounts, [Parameter(Mandatory)] $ResourceName, [Parameter(Mandatory)] $Password, [Parameter(Mandatory)] [string]$LicenseDuration, [string]$ArmTemplatePath = ".\AddServer.json", [int]$Port = 8250, [string]$UserProvidedKey, [string]$ScriptsFolderPath = ".\Resources\Scripts" ) . "$ScriptsFolderPath\dashboard_common.ps1" $vms = [System.Collections.ArrayList]@() $newVmsList = [System.Collections.ArrayList]@() $maxServerCount = 0 $userName = "" $resource = $null $resourceGroupName = $null function Enable-SystemAssignedIdentity { param( [Parameter(Mandatory)][string]$VmName ) Write-Host "$((Get-Date).ToString()) - Enabling system-assigned managed identity on $VmName" $vm = Get-AzVM -ResourceGroupName $resourceGroupName -Name $VmName -ErrorAction Stop Update-AzVM -ResourceGroupName $resourceGroupName -VM $vm -IdentityType SystemAssigned -ErrorAction Stop } function GetUploadedVms { param( [string]$ResourceGroup ) $vms = @(Get-AzVM -ErrorAction Stop -ResourceGroupName $ResourceGroup | Where-Object { $_.Tags.ContainsKey("ServerType") -and $_.Tags["ServerType"] -eq "NCache" } | ForEach-Object { $nicId = $_.NetworkProfile.NetworkInterfaces[0].Id $nicName = ($nicId -split "/")[-1] $nic = Get-AzNetworkInterface -ResourceGroupName $resourceGroupName -Name $nicName -ErrorAction Stop $privateIp = $nic.IpConfigurations[0].PrivateIpAddress [PSCustomObject]@{ Name = $_.Name Location = $_.Location VmSize = $_.HardwareProfile.VmSize OsType = $_.StorageProfile.OsDisk.OsType Zone = ($_.Zones[0]) Publisher = $_.StorageProfile.ImageReference.Publisher Offer = $_.StorageProfile.ImageReference.Offer Sku = $_.StorageProfile.ImageReference.Sku Version = $_.StorageProfile.ImageReference.Version NIC = $_.NetworkProfile.NetworkInterfaces.id StorageAccountType = $_.StorageProfile.OsDisk.ManagedDisk.StorageAccountType Disk = $_.StorageProfile.OsDisk.Name Tags = $_.Tags PrivateIp = $privateIp } } ) return , $vms } function RemoveResources { param( [string]$VmName, [string]$DiskName, [string]$NetworkInterfaceName, [string]$PublicIpName, [string]$ResourceGroup, [bool]$UseForce ) if ($UseForce) { Remove-AzVM -ResourceGroupName $ResourceGroup -Name $VmName -Force -ErrorAction SilentlyContinue Remove-AzDisk -ResourceGroupName $ResourceGroup -DiskName $DiskName -Force -ErrorAction SilentlyContinue Remove-AzNetworkInterface -Name $NetworkInterfaceName -ResourceGroupName $ResourceGroup -Force -ErrorAction SilentlyContinue Remove-AzPublicIpAddress -Name $PublicIpName -ResourceGroupName $ResourceGroup -Force -ErrorAction SilentlyContinue } else { Remove-AzVM -ResourceGroupName $ResourceGroup -Name $VmName -ErrorAction SilentlyContinue Remove-AzDisk -ResourceGroupName $ResourceGroup -DiskName $DiskName -ErrorAction SilentlyContinue Remove-AzNetworkInterface -Name $NetworkInterfaceName -ResourceGroupName $ResourceGroup -ErrorAction SilentlyContinue Remove-AzPublicIpAddress -Name $PublicIpName -ResourceGroupName $ResourceGroup -ErrorAction SilentlyContinue } } function CreateStartupCommand { param( [string]$Key, [string]$firstName, [string]$lastName, [string]$email, [string]$company, [string]$environment, [bool]$evalFlag, $OS ) $PrivateIps = @() $evalFlagCasted = [int]$evalFlag $cloudType = "azs" $StartupScriptUrl = "https://ncachedeployments.s3.us-east-1.amazonaws.com/5.3.6-tools/StartupScriptLinux.sh" $paramStr = "-InstallType $cloudType -Key $Key -FirstName $FirstName -LastName $LastName -Email $Email -Environment $ResourceName -IsEvalKey $evalFlagCasted " if (-not $evalFlag) { $paramStr += "-LicenseDuration $LicenseDuration " } if (![string]::IsNullOrWhiteSpace($company)) { $paramStr += "-Company $company" } if ($OS -eq "Windows") { $paramStr += " -Username $script:userName -Password $Password " return ("Invoke-WebRequest -Uri https://ncachedeployments.s3.us-east-1.amazonaws.com/5.3.6-tools/StartupScriptWin_v6.ps1 -OutFile C:/StartupScriptWin_v6.ps1;Unblock-File -Path C:/StartupScriptWin_v6.ps1; C:/StartupScriptWin_v6.ps1 $paramStr") } return ("#!/bin/sh sleep 30; wget -O /tmp/StartupScriptLinux.sh $StartupScriptUrl; chmod +x /tmp/StartupScriptLinux.sh; /tmp/StartupScriptLinux.sh $paramStr" -replace "`r`n", "`n") } function EncryptStartupCommand { param( [string]$StartupCommand ) $bytes = [System.Text.Encoding]::UTF8.GetBytes($StartupCommand) $encoded = [Convert]::ToBase64String($bytes) return $encoded } function EnableCacheServerPublicIp { param( [string]$RuleType ) if ($RuleType -eq "Data" -or $RuleType -eq "All") { return $true } return $false } function InvokeCommandOnServerWindows { $LogFile = "C:\Temp\InstallLog.txt" $evalKey = $resource.Tags['EvaluationKey'] $firstName = $resource.Tags['FirstName'] $lastName = $resource.Tags['LastName'] $company = $resource.Tags['Company'] $email = $resource.Tags['Email'] $setupUrl = $resource.Tags['SetupUrl'] $licenseKey = $resource.Tags["LicenseKey"] $licenseDuration = $resource.Tags["LicenseDuration"] $ruleType = $resource.Tags["RuleType"] $enableCacheServerIp = EnableCacheServerPublicIp -RuleType $ruleType if (![string]::IsNullOrWhiteSpace($UserProvidedKey)) { $licenseKey = $UserProvidedKey } $script = @" New-Item -ItemType Directory -Force -Path "C:\Temp" | Out-Null wget "https://ncachedeployments.s3.us-east-1.amazonaws.com/5.3.6-tools/InstallScript_Win_Server.ps1" -OutFile "C:\Temp\InstallScript_Win_Server.ps1" C:\Temp\InstallScript_Win_Server.ps1 -Key $evalKey -UserName $script:userName -Company $company -FirstName $FirstName -LastName $LastName -Password $Password -Email $Email -SetupUrl $SetupUrl -LicenseKey '$licenseKey' -EnableCacheServerPublicIp `$$enableCacheServerIp -Environment '$ResourceName' -LicenseDuration '$licenseDuration' "@ foreach ($server in $newVmsList) { Write-Host "$((Get-Date).ToString()) - Downloading and Installing NCache on $server" } $jobs = foreach ($server in $newVmsList) { Start-Job -ScriptBlock { param($rg, $vm, $script) Invoke-AzVMRunCommand -ResourceGroupName $rg -VMName $vm -CommandId 'RunPowerShellScript' -ScriptString $script Write-Host "$((Get-Date).ToString()) - Installed NCache on server $server" } -ArgumentList $resourceGroupName, $server, $script } # while (@($jobs | Where-Object { $_.State -eq "Running" }).Count -gt 0) { # BlastFromThePast; # Start-Sleep -Milliseconds 100 # } # BlastFromThePast -Finished; $dots = "" while (@($jobs | Where-Object { $_.State -eq "Running" }).Count -gt 0) { $dots += "." Write-Host -NoNewline "`r$dots" Start-Sleep -Seconds 5 $jobs = $jobs | Get-Job } # Clear dots line $clearLine = " " * $dots.Length Write-Host -NoNewline "`r$clearLine`r" $jobs | Wait-Job $jobs | Receive-Job } function BlastFromThePast([switch]$EndOfLine, [switch]$Finished) { $EscChar = "`r" if ($EndOfLine) { $EscChar = "`b" } if (!$tickcounter) { Set-Variable -Name "tickcounter" -Scope global -Value 0 -Force -Option AllScope } if (!$tickoption) { Set-Variable -Name "tickoption" -Scope global -Value 0 -Force -Option AllScope } $chance = Get-Random -Minimum 1 -Maximum 10 if ($chance -eq 5) { if ($tickoption -eq 1) { $tickoption = 0 }else { $tickoption = 1 } } switch ($tickoption) { 0 { switch ($tickcounter) { 0 { Write-Host "$EscChar|" -NoNewline } 1 { Write-Host "$EscChar/" -NoNewline } 2 { Write-Host "$EscChar-" -NoNewline } 3 { Write-Host "$EscChar\" -NoNewline } } break; } 1 { switch ($tickcounter) { 0 { Write-Host "$EscChar|" -NoNewline } 1 { Write-Host "$EscChar\" -NoNewline } 2 { Write-Host "$EscChar-" -NoNewline } 3 { Write-Host "$EscChar/" -NoNewline } } break; } } if ($tickcounter -eq 3) { $tickcounter = 0 } else { $tickcounter++ } } function InvokeCommandOnServerLinux { foreach ($server in $newVmsList) { Write-Host "$((Get-Date).ToString()) - Downloading and Installing NCache on $server" } $command = CreateScriptBlockLinux $jobs = foreach ($server in $newVmsList) { Start-Job -ScriptBlock { param($rg, $vm, $script) Invoke-AzVMRunCommand -ResourceGroupName $rg -VMName $vm -CommandId 'RunShellScript' -ScriptString $script Write-Host "$((Get-Date).ToString()) - Installed NCache on server $vm" } -ArgumentList $resourceGroupName, $server, $command } while (@($jobs | Where-Object { $_.State -eq "Running" }).Count -gt 0) { BlastFromThePast -Finished; Start-Sleep -Milliseconds 100 } $jobs | Wait-Job $jobs | Receive-Job } function CreateScriptBlockLinux { $evalKey = $resource.Tags['EvaluationKey'] $firstName = $resource.Tags['FirstName'] $lastName = $resource.Tags['LastName'] $company = $resource.Tags['Company'] $email = $resource.Tags['Email'] $setupUrl = $resource.Tags['SetupUrl'] $licenseKey = $resource.Tags["LicenseKey"] $licenseDuration = $resource.Tags["LicenseDuration"] if (![string]::IsNullOrWhiteSpace($UserProvidedKey)) { $licenseKey = $UserProvidedKey } $ruleType = $resource.Tags["RuleType"] $enableCacheServerIp = EnableCacheServerPublicIp -RuleType $ruleType return "sudo wget -O /tmp/InstallScript_Lin_Server.sh https://ncachedeployments.s3.us-east-1.amazonaws.com/5.3.6-tools/InstallScript_Lin_Server.sh; chmod +x /tmp/InstallScript_Lin_Server.sh; /tmp/InstallScript_Lin_Server.sh -FirstName $FirstName -LastName $LastName -Email $Email -Key $evalKey -Company $company -SetupUrl $SetupUrl -PrivateIps '' -LicenseKey '$licenseKey' -Environment '$ResourceName' -EnableCacheServerPublicIp $enableCacheServerIp -LicenseDuration '$LicenseDuration'" } function DownloadAndInstallNCache { param( [Parameter(Mandatory)][string]$OS ) if ($OS -eq "Windows") { InvokeCommandOnServerWindows } else { InvokeCommandOnServerLinux } } function CreateScript { $firstName = $resource.Tags['FirstName'] $lastName = $resource.Tags['LastName'] $email = $resource.Tags['Email'] $company = $resource.Tags['Company'] $licenseKey = $resource.Tags['LicenseKey'] $script:userName = $resource.Tags['UserName'] $isEvalKey = $resource.Tags["IsEvalKey"] $licenseDuration = $resource.Tags["LicenseDuration"] $os = $resource.Tags["OsType"] $IsEval = [System.Convert]::ToBoolean($isEvalKey) $scriptCode = CreateStartupCommand -key $LicenseKey -firstName $FirstName -lastname $LastName -email $Email -company $company -environment $ResourceName -evalFlag $IsEval -OS $os $encodedScript = EncryptStartupCommand -StartupCommand $scriptCode return $encodedScript } function ExtractVmData { return [PSCustomObject]@{ Location = $resource.Tags['Location'] VmSize = $resource.Tags['VmSize'] Zone = $resource.Tags['Zone'] Publisher = $resource.Tags['Publisher'] Offer = $resource.Tags['Offer'] Sku = $resource.Tags['Sku'] Version = $resource.Tags['Version'] StorageAccountType = $resource.Tags['StorageAccountType'] OsType = $resource.Tags['OsType'] CreatePublicIp = $resource.Tags["CreatePublicIp"] ImageVersion = $resource.Tags["ImageVersion"] UseNCacheImage = [System.Convert]::ToBoolean($resource.Tags["UseNCacheImage"]) } } function CreatePublicIp { param( [string]$MachineName ) return "NC-PUBLIC_IP-$($ResourceName)-$($MachineName)" } function ExtractAndCreateNIC() { param( [string]$MachineName ) return "NC-NIC-$($ResourceName)-$($MachineName)" } function CreateNewServersList { for ($i = 1; $i -le $VmCounts; $i++) { $newVmsList.Add("NC-Server-$($maxServerCount+$i)") | Out-Null } } function FindMaxServerCount { for ($i = 0; $i -lt $($vms | Measure-Object).Count; $i++) { $currentVmCount = $vms[$i].Name -split '-' if ([int]$currentVmCount[2] -gt $maxServerCount) { $maxServerCount = [int]$currentVmCount[2] } } return $maxServerCount } function PerformRollback { if ($resourceGroupName) { $uploadedVms = GetUploadedVms -ResourceGroup $nc_resource_group $disks = Get-AzDisk -ResourceGroupName $nc_resource_group | Select-Object -ExpandProperty Name for ($i = 0 ; $i -lt $newVmsList.Count; $i++) { for ($j = 0; $j -lt $uploadedVms.Count; $j++) { if ($newVmsList[$i] -ne $uploadedVms[$j].Name ) { $matchingDisks = $disks | Where-Object { $_ -like "*$($newVmsList[$i])*" } if ( $null -ne $matchingDisks -and $matchingDisks -ne "") { $publicIpName = CreatePublicIp -MachineName $newVmsList[$i] $nicName = ExtractAndCreateNIC -MachineName $newVmsList[$i] RemoveResources -VmName $newVmsList[$i] -DiskName $matchingDisks -NetworkInterfaceName $nicName -PublicIpName $publicIpName -ResourceGroup $nc_resource_group -UseForce $true } } break; } } } } function CheckQuota { param( [string]$Location, [string]$VmSizeName ) (Get-AzComputeResourceSku -Location $Location | Where-Object { $_.ResourceType -eq "virtualMachines" -and $_.Name -eq $VmSizeName }).Capabilities | Where-Object { $_.Name -eq "vCPUs" } | Select-Object -ExpandProperty Value $sku = Get-AzComputeResourceSku -Location $Location ` | Where-Object { $_.ResourceType -eq "virtualMachines" -and $_.Name -eq $VmSizeName } $family = $sku.Family $vcpus = ($sku.Capabilities | Where-Object { $_.Name -eq "vCPUs" }).Value $info = [PSCustomObject]@{ Name = $sku.Name Family = $family vCPUs = $vcpus } $Usage = Get-AzVMUsage -Location $Location | Where-Object { $_.Name.Value -eq $family } ValidateQuota -currentQuota $($Usage.CurrentValue) -limitQuota $($Usage.Limit) -vCpus $vcpus } function ValidateQuota() { param( [int]$currentQuota, [int]$limitQuota, [int]$vCpus ) $myQuota = $VmCounts * $vCpus $total = $myQuota + $currentQuota if ($total -gt $limitQuota) { throw "Quota limit exceeded" } } function ShowDeployedEvs { $vms = Get-AzVM -ResourceGroupName $resourceGroupName -Status -ErrorAction Stop $results = foreach ($vm in $vms) { $nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id $nicName = ($nicId -split '/')[8] $nic = Get-AzNetworkInterface -ResourceGroupName $resourceGroupName -Name $nicName -ErrorAction Stop $privateIp = $nic.IpConfigurations[0].PrivateIpAddress $publicIp = $null $managementLink = $null if ($nic.IpConfigurations[0].PublicIpAddress) { $publicIpId = $nic.IpConfigurations[0].PublicIpAddress.Id $publicIpName = ($publicIpId -split '/')[8] $publicIpObj = Get-AzPublicIpAddress -ResourceGroupName $resourceGroupName -Name $publicIpName -ErrorAction Stop $publicIp = $publicIpObj.IpAddress if ($publicIp) { $managementLink = "http://$publicIp`:8251" } } [PSCustomObject]@{ VMName = $vm.Name PrivateIP = $privateIp PublicIP = $publicIp ManagementLink = $managementLink } } $results | Format-Table -AutoSize } function ExecuteCommands { $resource = Get-AzResourceGroup | Where-Object { $_.Tags -and $_.Tags.Contains("EnvironmentName") -and $_.Tags["EnvironmentName"] -eq $ResourceName } -ErrorAction Stop if (-not $resource) { throw "No such environment exists" } $resourceGroupName = $resource | Select-Object -ExpandProperty resourceGroupName $vms = GetUploadedVms -ResourceGroup $resourceGroupName $maxServerCount = FindMaxServerCount CreateNewServersList $vmData = ExtractVmData $encodedScript = CreateScript # CheckQuota -Location $($vmData.Location) -VmSizeName $($vmData.VmSize) $CreatePublicIp = [System.Convert]::ToBoolean($vmData.CreatePublicIp) New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $ArmTemplatePath -location $($vmData.location) -resource_group_name $ResourceName -vm_names $newVmsList -zone_name $($vmData.zone) -publisher_name $($vmData.publisher) -offer_name $($vmData.offer) -sku_name $($vmData.sku) -version_name $($vmData.version) -os_name $($vmData.osType) -storage_account_type $($vmData.storageAccountType) -vm_size $($vmData.VmSize) -userName $script:userName -password $Password -create_public_ip $CreatePublicIp -image_version $($vmData.ImageVersion) -custom_data $encodedScript -use_ncache_image $($vmData.UseNCacheImage) -Verbose -ErrorVariable MyError | Out-Null if ($MyError) { throw "Exception $($MyError.Exception.Message)" } InstallNCache AddnewServersToCaches ShowDeployedEvs } function InstallNCache { foreach ($server in $newVmsList) { Enable-SystemAssignedIdentity -VmName $server } $os = $resource.Tags['OsType'] $UseNCacheImage = [System.Convert]::ToBoolean($resource.Tags["UseNCacheImage"]) if (-not $UseNCacheImage) { DownloadAndInstallNCache -OS $os } } function AddCacheTagsToNewServers { param( $NewVm, [string]$caches ) $NewVm.Tags["Caches"] = $caches Update-AzTag -ResourceId $NewVm.Id -Tag $NewVm.Tags -Operation Merge | Out-Null $cacheList = $caches -split ',' | ForEach-Object { $_.Trim() } foreach ($cacheName in $cacheList) { if (-not [string]::IsNullOrWhiteSpace($cacheName)) { Update-NcAzDashboards -ScriptsFolderPath $ScriptsFolderPath -ResourceGroupName $NewVm.ResourceGroupName -CacheName $cacheName -SkipClient } } } function AddToCachesWindows { param( [string]$NewVmPrivateIp, [string]$NewVmName, $NewVm ) $cmd = "" $cachesValue = "" $caches = @() if ($vms -and $vms.Count -gt 0) { $vm = $null $cacheVMs = $vms | Where-Object { $_.Tags.ContainsKey("Caches") -and $_.Tags.ContainsKey("InstallMode") } if ($cacheVMs -and $cacheVMs.Count -gt 0) { $vm = $cacheVMs[0] $caches += $vm.Tags["Caches"].Split(",") | ForEach-Object { $_.Trim() } $cachesList = $vm.Tags["Caches"].Split(",") $uniqueCaches = $caches | Sort-Object -Unique $cachesValue = ($uniqueCaches -join ",") if ($cachesList.count -gt 0) { foreach ($cache in $cachesList) { $cmd += "Add-Node -CacheName $cache -NewServer $NewVmPrivateIp -Port $Port -ExistingServer $($vm.PrivateIp)" $cmd += "`n" } } AddCacheTagsToNewServers -NewVm $NewVm -caches $cachesValue $result = Invoke-AzVMRunCommand -ResourceGroupName $resourceGroupName -VMName $NewVmName -CommandId 'RunPowerShellScript' -ScriptString $cmd foreach ($val in $result.Value) { Write-Host $val.Message } } } } function AddToCachesLinux { param( [string]$NewVmPrivateIp, [string]$NewVmName, $NewVm ) $cmd = "" $cachesValue = "" $caches = @() if ($vms -and $vms.Count -gt 0) { $vm = $null if ($vms -and $vms.Count -gt 0) { $vm = $null $cacheVMs = $vms | Where-Object { $_.Tags.ContainsKey("Caches") -and $_.Tags.ContainsKey("InstallMode") } if ($cacheVMs -and $cacheVMs.Count -gt 0) { $vm = $cacheVMs[0] $caches += $vm.Tags["Caches"].Split(",") | ForEach-Object { $_.Trim() } $cachesList = $vm.Tags["Caches"].Split(",") $uniqueCaches = $caches | Sort-Object -Unique $cachesValue = ($uniqueCaches -join ",") if ($cachesList.count -gt 0) { foreach ($cache in $cachesList) { $cmd += "/opt/ncache/bin/tools/add-node -cacheName $cache -newserver $NewVmPrivateIp -port $Port -existingserver $($vm.PrivateIp)" if ($cmd) { $cmd += "; " } } } } AddCacheTagsToNewServers -NewVm $NewVm -caches $cachesValue $result = Invoke-AzVMRunCommand -ResourceGroupName $resourceGroupName -VMName $NewVmName -CommandId 'RunShellScript' -ScriptString $cmd foreach ($val in $result.Value) { Write-Host $val.Message } } } } function GetNewServersPrivateIp { foreach ($server in $newVmsList) { $vm = Get-AzVM -ResourceGroupName $resourceGroupName -Name $server -ErrorAction Stop $nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id $nicName = ($nicId -split "/")[-1] $nic = Get-AzNetworkInterface -ResourceGroupName $resourceGroupName -Name $nicName -ErrorAction Stop $privateIp = $nic.IpConfigurations[0].PrivateIpAddress if ($resource.Tags["OsType"] -eq "Windows") { AddToCachesWindows -NewVmName $server -NewVmPrivateIp $privateIp -NewVm $vm } else { AddToCachesLinux -NewVmName $server -NewVmPrivateIp $privateIp -NewVm $vm } } } function AddnewServersToCaches { GetNewServersPrivateIp } try { if (-not (Get-AzContext)) { Connect-AzAccount if (Get-AzContext) { Write-Host "Deploying resources..." ExecuteCommands } } else { Write-Host "Deploying resources..." ExecuteCommands } } catch { Write-Error $($_.Exception.Message) Write-Error "Machine(s) deployment failed" Write-Warning "Rolling back changes..." PerformRollback } |