Documents/Add-HPCIaasNode-Scripts/IaaSAzureCmdLib.ps1 (652 lines of code) (raw):
# -----------------------------------------------------------------------------
# Script : IaaSAzureCmdLib.ps1
# Author : Microsoft HPC Pack team
# Version: 4.3.0
# Summary: The wrapper library for Azure Cmdlets
# -----------------------------------------------------------------------------
<#
.SYNOPSIS
Invoke an Azure cmdlet with retries
.DESCRIPTION
Invoke an Azure cmdlet with retries. The Azure cmdlet must be a "query" command (typically, Get-Azurexxx or Test-Azurexxx), must not modify any Azure resources.
.EXAMPLE
InvokeAzureCmdWithRetry -Command "Get-AzureVMImage"
InvokeAzureCmdWithRetry -Command "Get-AzureDeployment -ServiceName testservice" -RetryTimes 10
#>
function InvokeAzureCmdWithRetry
{
Param
(
[Parameter(Mandatory=$true)]
[String] $Command,
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 20
)
# if ErrorAction is not specified, specify it as Stop so that the error can be thrown by "Invoke-Expression" command.
if(($Command -notmatch " -ErrorAction ") -and ($Command -notmatch " -EA "))
{
$newCommand = $Command + " -ErrorAction Stop"
}
else
{
$newCommand = $Command
}
$retry = 0
while($true)
{
try
{
$ret = Invoke-Expression -Command $newCommand
return $ret
}
catch
{
$caughtException = $_.Exception
$errMsg = "Failed to execute the command '$Command': " + ($_ | Out-String)
$shouldThrow = $true
if($caughtException -is [Microsoft.WindowsAzure.CloudException])
{
if($_.Exception.ErrorCode -eq "ResourceNotFound")
{
TraceInfo "The command '$Command' executed: ResourceNotFound"
return
}
$shouldThrow = $false
}
elseif(($caughtException -is [System.Net.Http.HttpRequestException]) -or ($caughtException -is [System.Threading.Tasks.TaskCanceledException]))
{
$shouldThrow = $false
}
}
if($shouldThrow -or ($retry -ge $RetryTimes))
{
TraceError $errMsg
throw $caughtException
}
else
{
TraceWarning $errMsg
TraceInfo "Retry to execute the command '$Command' after 10 seconds"
Start-Sleep -Seconds 10
$retry++
}
}
}
function New-AzureServiceWithRetry
{
Param
(
# The Name
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$true)]
[String] $AffinityGroupName,
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 20
)
$retry = 0
while($true)
{
try
{
TraceInfo "Creating the cloud service $ServiceName in the affinity group $AffinityGroupName"
New-AzureService -ServiceName $ServiceName -AffinityGroup $AffinityGroupName -ErrorAction Stop | Out-Null
TraceInfo "The cloud service $ServiceName created in the affinity group $AffinityGroupName"
return
}
catch
{
TraceWarning ("Failed to create cloud service $ServiceName :" + ($_ | Out-String))
}
$service = InvokeAzureCmdWithRetry -Command "Get-AzureService -ServiceName $ServiceName"
if($service -ne $null)
{
TraceInfo "Cloud service $ServiceName Created"
return
}
if($retry -lt $RetryTimes)
{
TraceInfo "Retry to create cloud service $ServiceName after 10 seconds"
Start-Sleep -Seconds 10
$retry++
}
else
{
throw "Failed to create cloud service $ServiceName after $RetryTimes retries"
}
}
}
function New-AzureVMWithRetry
{
Param
(
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$true)]
[Microsoft.WindowsAzure.Commands.ServiceManagement.Model.PersistentVM] $VM,
[Parameter(Mandatory=$true)]
[String] $VNetName,
[Parameter(Mandatory=$true)]
[String] $DeploymentLabel,
[Parameter(Mandatory=$false)]
[Switch] $WaitForBoot,
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 20
)
$retry = 0
$vmname = $VM.RoleName
while($true)
{
try
{
TraceInfo "Creating the virtual machine $vmname in cloud service $ServiceName"
if($WaitForBoot.IsPresent)
{
New-AzureVM -VMs $VM -ServiceName $ServiceName -DeploymentLabel $DeploymentLabel -VNetName $VNetName -WaitForBoot -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null
}
else
{
New-AzureVM -VMs $VM -ServiceName $ServiceName -DeploymentLabel $DeploymentLabel -VNetName $VNetName -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null
}
TraceInfo "The virtual machine $vmname Created in cloud service $ServiceName"
return
}
catch
{
TraceWarning ("Failed to create the virtual machine $vmname : " + ($_ | Out-String))
}
$newvm = InvokeAzureCmdWithRetry -Command "Get-AzureVM -ServiceName $ServiceName -Name $vmname"
if($newvm -ne $null)
{
TraceInfo "The virtual machine $vmname Created in cloud service $ServiceName"
return
}
if($retry -lt $RetryTimes)
{
TraceInfo "Retry to create the virtual machine $vmname after 10 seconds"
Start-Sleep -Seconds 10
$retry++
}
else
{
throw "Failed to create the virtual machine $vmname after $RetryTimes retries"
}
}
}
function Update-AzureVMWithRetry
{
Param
(
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$true)]
[String] $Name,
[Parameter(Mandatory=$true)]
[Microsoft.WindowsAzure.Commands.ServiceManagement.Model.PersistentVM] $VM,
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 20
)
$retry = 0
while($true)
{
try
{
TraceInfo "Updating the virtual machine $Name in cloud service $ServiceName ..."
Update-AzureVM -Name $Name -ServiceName $ServiceName -VM $VM -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null
TraceInfo "The virtual machine $Name updated."
return
}
catch
{
TraceWarning ("Failed to update the virtual machine $Name : " + ($_ | Out-String))
}
if($retry -lt $RetryTimes)
{
TraceInfo "Retry to update the virtual machine $Name after 10 seconds"
Start-Sleep -Seconds 10
$retry++
}
else
{
throw "Failed to update the virtual machine $Name after $RetryTimes retries"
}
}
}
function New-AzureAffinityGroupWithRetry
{
Param
(
# The Name
[Parameter(Mandatory=$true)]
[String] $Name,
[Parameter(Mandatory=$true)]
[String] $Location,
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 20
)
$retry = 0
while($true)
{
try
{
TraceInfo "Creating the affinity group $Name at region $Location"
New-AzureAffinityGroup -Name $Name -Location $Location -Label $Name -ErrorAction Stop | Out-Null
TraceInfo "The affinity group $Name created at region $Location"
return
}
catch
{
TraceWarning ("Failed to create affinity group $Name : " + ($_ | Out-String))
}
$ag = InvokeAzureCmdWithRetry -Command "Get-AzureAffinityGroup -Name $Name"
if($ag -ne $null)
{
TraceInfo "The affinity group $Name Created"
return
}
if($retry -lt $RetryTimes)
{
TraceInfo "Retry to create the affinity group $Name after 10 seconds"
Start-Sleep -Seconds 10
$retry++
}
else
{
throw "Failed to create the affinity group $Name after $RetryTimes retries"
}
}
}
function New-AzureStorageAccountWithRetry
{
Param
(
# The Name
[Parameter(Mandatory=$true)]
[String] $StorageAccountName,
[Parameter(Mandatory=$true)]
[String] $Location,
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 20
)
$retry = 0
while($true)
{
try
{
TraceInfo "Creating the storage account $StorageAccountName at region $Location"
New-AzureStorageAccount -StorageAccountName $StorageAccountName -Location $Location -ErrorAction Stop | Out-Null
TraceInfo "Storage account $StorageAccountName created at region $Location"
return
}
catch
{
TraceWarning ("Failed to create the storage account $StorageAccountName : " + ($_ | Out-String))
}
$storage = InvokeAzureCmdWithRetry -Command "Get-AzureStorageAccount -StorageAccountName $StorageAccountName"
if($storage -ne $null)
{
TraceInfo "Storage account $StorageAccountName Created"
return
}
if($retry -lt $RetryTimes)
{
TraceInfo "Retry to create the storage account $StorageAccountName after 10 seconds"
Start-Sleep -Seconds 10
$retry++
}
else
{
throw "Failed to create the storage account $StorageAccountName after $RetryTimes retries"
}
}
}
function Save-AzureVMImageWithRetry
{
Param
(
[Parameter(Mandatory=$true)]
[String] $Name,
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$true)]
[String] $ImageName,
[Parameter(Mandatory=$false)]
[String] $ImageLabel = "HPC Image",
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 20
)
$retry = 0
while($true)
{
$service = $null
try
{
TraceInfo "Saving Azure VM Image $ImageName"
Save-AzureVMImage -Name $Name -ServiceName $ServiceName -ImageName $ImageName -ImageLabel $ImageLabel -OSState Generalized -ErrorAction Stop | Out-Null
TraceInfo "The VM image $ImageName was saved"
return
}
catch
{
TraceWarning ("Failed to save the VM image $ImageName :" + ($_ | Out-String))
}
$image = InvokeAzureCmdWithRetry -Command "Get-AzureVMImage -ImageName $ImageName"
if($image -ne $null)
{
TraceInfo "The VM image $ImageName already saved"
return
}
if($retry -lt $RetryTimes)
{
TraceInfo "Retry to save the VM image $ImageName after 10 seconds"
Start-Sleep -Seconds 10
$retry++
}
else
{
throw "Failed to save the VM image $ImageName after $RetryTimes retries"
}
}
}
function Get-AzureVNetSiteWithRetry
{
Param
(
# The Name
[Parameter(Mandatory=$true)]
[String] $VNetName
)
$vnetSite = $null
try
{
$vnetSite = InvokeAzureCmdWithRetry -Command "Get-AzureVNetSite -VNetName $VNetName"
}
catch
{
}
return $vnetSite
}
function Remove-AzureVMWithRetry
{
Param
(
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$true)]
[String] $VMName,
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 3
)
$retry = 0
TraceInfo "Trying to remove the virtual machine $VMName from the cloud service $ServiceName"
while($true)
{
try
{
TraceInfo "Removing the virtual machine $VMName from the cloud service $ServiceName"
Remove-AzureVM -Name $VMName -ServiceName $ServiceName -DeleteVHD -ErrorAction Stop -WarningAction SilentlyContinue
TraceInfo "The virtual machine $VMName removed from the cloud service $ServiceName"
return
}
catch
{
TraceWarning ("Failed to remove the virtual machine $VMName : " + ($_ | Out-String))
}
$vm = InvokeAzureCmdWithRetry -Command "Get-AzureVM -ServiceName $ServiceName -Name $VMName -WarningAction SilentlyContinue"
if($vm -eq $null)
{
TraceInfo "The virtual machine $VMName already removed from the cloud service $ServiceName"
return
}
if($retry -lt $RetryTimes)
{
TraceInfo "Retry to remove the virtual machine $VMName after 5 seconds"
Start-Sleep -Seconds 5
$retry++
}
else
{
throw "Failed to remove the virtual machine $VMName after $RetryTimes retries"
}
}
}
function Remove-AzureServiceWithRetry
{
Param
(
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$false)]
[Int] $RetryTimes = 3
)
$retry = 0
TraceInfo "Trying to remove the cloud service $ServiceName"
while($true)
{
try
{
TraceInfo "Removing the cloud service $ServiceName"
Remove-AzureService -ServiceName $ServiceName -DeleteAll -Force -ErrorAction Stop -WarningAction SilentlyContinue
TraceInfo "The cloud service $ServiceName removed"
return
}
catch
{
TraceWarning ("Failed to remove the cloud service $ServiceName : " + ($_ | Out-String))
}
$svc = InvokeAzureCmdWithRetry -Command "Get-AzureService -ServiceName $ServiceName"
if($svc -eq $null)
{
TraceInfo "The cloud service $ServiceName already removed"
return
}
if($retry -lt $RetryTimes)
{
TraceInfo "Retry to remove the cloud service $ServiceName after 5 seconds"
Start-Sleep -Seconds 5
$retry++
}
else
{
throw "Failed to remove the cloud service $ServiceName after $RetryTimes retries"
}
}
}
function GetStorageAccountFromMediaLink
{
param
(
[Parameter(Mandatory=$true)]
[String] $MediaLink
)
if($MediaLink -ne $null)
{
$startIndex = $MediaLink.IndexOf("//") + 2
$endIndex = $MediaLink.IndexOf(".")
if(($endIndex -gt ($startIndex + 2)) -and ($startIndex -gt 0))
{
return $MediaLink.Substring($startIndex, $endIndex - $startIndex)
}
}
return ""
}
function DecodeLabelIfBase64Encoded
{
param($orgLabel)
try
{
$bytes = [System.Convert]::FromBase64String($orgLabel)
return [System.Text.Encoding]::UTF8.GetString($bytes)
}
catch
{
return $orgLabel
}
}
<#
.SYNOPSIS
Check whether a VM exists in the given cloud service
.DESCRIPTION
Check whether a VM exists in the given cloud service
.EXAMPLE
VMExists -Name "vmname" -ServiceName "servicename"
#>
function VMExists
{
param
(
#The name of VM
[Parameter(Mandatory=$true)]
[String] $Name,
#The name of the host cloud service
[Parameter(Mandatory=$true)]
[String] $ServiceName
)
$vm = InvokeAzureCmdWithRetry -Command "Get-AzureVM -Name $Name -ServiceName $ServiceName"
if ($vm -ne $null)
{
return $true
}
return $false
}
<#
.SYNOPSIS
Wait the specified VMs in a cloud service to become the target status
.DESCRIPTION
Wait the specified VMs to become the target status in a given maximum waiting time, throw if the timer expires
.EXAMPLE
The following example will wait the VM "mytestvm" in cloud service "mytestservice" to become 'ReadyRole' for a maximum time 900 seconds
WaitForVMReady -VMName @("testvm1", "testvm2") -ServiceName "mytestservice" -MaxWaitSeconds 900
#>
function WaitForVMReady
{
param
(
[Parameter(Mandatory=$true)]
[String[]] $VMName,
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$false)]
[String] $TargetStatus = "ReadyRole",
[Parameter(Mandatory=$false)]
[ValidateRange(0, 3600)]
[int] $MaxWaitSeconds = 1800
)
TraceInfo "Waiting for the following VM(s) to become $TargetStatus status: $VMName"
$noReadyVMNames = $VMName
$beginTime = Get-Date
while ($noReadyVMNames.Count -gt 0)
{
$vms = @(InvokeAzureCmdWithRetry -Command "Get-AzureVM -ServiceName $ServiceName -WarningAction SilentlyContinue" | ?{($noReadyVMNames -contains $_.InstanceName) -and ($_.InstanceStatus -eq $TargetStatus)})
if($vms.Count -gt 0)
{
TraceInfo "The following VM(s) are now in $TargetStatus status: $($vms.InstanceName)"
if($vms.Count -eq $noReadyVMNames.Count)
{
break
}
$noReadyVMNames = @($noReadyVMNames | ?{$vms.InstanceName -notcontains $_})
}
$timeSpan = (Get-Date) - $beginTime
$elapsedSeconds = [int]$timeSpan.TotalSeconds
if ($elapsedSeconds -ge $MaxWaitSeconds)
{
throw "Timed out waiting for the following virtual machine(s) to become $TargetStatus : $noReadyVMNames"
}
Start-Sleep -Seconds 10
}
}
function CreateDomainJoinedVM
{
param
(
[Parameter(Mandatory=$true)]
[String] $VMName,
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$true)]
[String] $VMSize,
[Parameter(Mandatory=$true)]
[String] $ImageName,
[Parameter(Mandatory=$true)]
[String] $VNetName,
[Parameter(Mandatory=$true)]
[String] $SubnetName,
[Parameter(Mandatory=$true)]
[PSCredential] $LocalAdminCred,
[Parameter(Mandatory=$true)]
[PSCredential] $DomainUserCred,
[Parameter(Mandatory=$true)]
[String] $DomainFQDN,
[Parameter(Mandatory=$true)]
[String] $DeploymentLabel,
[Parameter(Mandatory=$false)]
[ValidateSet("ReadOnly","ReadWrite")]
[String] $HostCaching = "",
[Parameter(Mandatory=$false)]
[String] $HnNameFile = "",
[Parameter(Mandatory=$false)]
[Switch] $Wait
)
TraceInfo "Creating a domain joined VM $VMName in Service $ServiceName `n Size: `t$VMSize`n Image: `t$ImageName`n VNet: `t$VNetName`n Subnet:`t$SubnetName`n Domain:`t$DomainFQDN"
$netbios = $DomainFQDN.Split(".")[0].ToUpper()
$domainUserName = $DomainUserCred.UserName
if($DomainUserCred.UserName.Contains("\"))
{
$domainUserName = $domainUserName.Split("\")[1]
}
try
{
if([String]::IsNullOrEmpty($HostCaching))
{
$vm = New-AzureVMConfig -Name $VMName -InstanceSize $VMSize -ImageName $ImageName
}
else
{
$vm = New-AzureVMConfig -Name $VMName -InstanceSize $VMSize -HostCaching $HostCaching -ImageName $ImageName
}
if ([String]::IsNullOrEmpty($HnNameFile))
{
$vm = $vm | `
Add-AzureProvisioningConfig -AdminUsername $LocalAdminCred.UserName -Password $LocalAdminCred.GetNetworkCredential().Password `
-Domain $netbios -DomainUserName $domainUserName -DomainPassword $DomainUserCred.GetNetworkCredential().Password `
-JoinDomain $DomainFQDN -WindowsDomain
}
else
{
$vm = $vm | `
Add-AzureProvisioningConfig -AdminUsername $LocalAdminCred.UserName -Password $LocalAdminCred.GetNetworkCredential().Password `
-Domain $netbios -DomainUserName $domainUserName -DomainPassword $DomainUserCred.GetNetworkCredential().Password `
-JoinDomain $DomainFQDN -WindowsDomain -CustomDataFile $HnNameFile
}
$vm = $vm | `
Set-AzureVMBGInfoExtension | `
Set-AzureSubnet -SubnetNames $SubnetName
if(($VMSize -eq "A8") -or ($VMSize -eq "A9"))
{
$vm = $vm | Set-AzureVMExtension -ExtensionName "HpcVmDrivers" -Publisher "Microsoft.HpcCompute" -Version "1.*"
}
New-AzureVMWithRetry -VM $vm -ServiceName $ServiceName -VNetName $VNetName -DeploymentLabel $DeploymentLabel
}
catch
{
TraceError "Failed to create a VM $VMName joined to domain $DomainFQDN in cloud service $ServiceName"
throw
}
if ($Wait.IsPresent)
{
WaitForVMReady -VMName $VMName -ServiceName $ServiceName
}
}
function ConvertSecureStrToPlain
{
param
(
[Parameter(Mandatory=$true)]
[System.Security.SecureString] $SecurePassword
)
$pswPointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$plainPsw = [Runtime.InteropServices.Marshal]::PtrToStringAuto($pswPointer)
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($pswPointer)
return $plainPsw
}