Documents/Add-HPCIaasNode-Scripts/Add-HPCIaaSNode.ps1 (312 lines of code) (raw):
<#
.Synopsis
Add IaaS nodes to Microsoft HPC Cluster in Windows Azure as IaaS.
.DESCRIPTION
This script add new IaaS nodes to Microsoft HPC Cluster in Windows Azure as IaaS.
.EXAMPLE
Add-HPCIaasNode.ps1 -ServiceName "cloud service name" -ImageName "vm image name" -Quantity "1" -InstanceSize "Large" -DomainUserName "user" -DomainUserPassword "password"
#>
Param
(
[Parameter(Mandatory=$true)]
[String] $ServiceName,
[Parameter(Mandatory=$true)]
[String] $ImageName,
[Parameter(Mandatory=$true)]
[Int] $Quantity,
[Parameter(Mandatory=$true)]
[String] $InstanceSize,
[Parameter(Mandatory=$true)]
[String] $DomainUserName,
[Parameter(Mandatory=$false)]
[String] $DomainUserPassword = "",
[Parameter(Mandatory=$false)]
[String] $NodeNameSeries = ""
)
. "$PSScriptRoot\IaaSAzureCmdLib.ps1"
. "$PSScriptRoot\HPCIaaSNodeMgmtUtil.ps1"
if ($Quantity -le 0)
{
Write-Error "Quantity must be larger than 0"
return
}
elseif ($Quantity -gt 50)
{
Write-Error "You cann't deploy $Quantity virtual machines to one cloud service. Cannot deploy more than 50 virtual machines under one cloud service."
return
}
LoadAzureAndHpcModules
try
{
# Get and validate pre-config information: subscription id, location, vnet, subnet, affinity group
# get from registry key
$iaasInfo = GetIaaSInfo
TraceInfo "PROGRESS:5"
# check whether the subscription is existed by Get-AzureSubscription, if yes, Select-AzureSubscription
TraceInfo "Selecting Azure subscription $($iaasInfo.SubscriptionId)"
$subscriptionName = SelectAzureSubscription $iaasInfo.SubscriptionId
# check vnet, subnet is existed, vnet is in location
TraceInfo "Validating virtual network $($iaasInfo.VNet) and subnet $($iaasInfo.SubNet)"
ValidateAzureVNet $iaasInfo.VNet $iaasInfo.SubNet $iaasInfo.Location
# validate service, image is correct
$deloymentLabel = GetHpcDeploymentLabel $iaasInfo.VNet
TraceInfo "Validating cloud service $ServiceName"
$serviceState = ValidateCloudService $ServiceName $iaasInfo.VNet $iaasInfo.Location $iaasInfo.AffinityGroup $deloymentLabel $Quantity
if ($serviceState -eq "NotCreated")
{
throw "Cloud service $ServiceName doesn't exist in current subscription $subscriptionName. You must create it first."
}
TraceInfo "Validating Azure virtual machine image $ImageName"
$image = InvokeAzureCmdWithRetry -Command "Get-AzureVMImage" | where-object {$_.ImageName -eq $ImageName}
$isLinux = $false
if ($image -ne $null)
{
if ($image.Location.Split(";").Contains($iaasInfo.Location) -eq $false)
{
throw "Azure image $ImageName must be in region $($iaasInfo.Location)"
}
if ($image.OS -eq "Linux")
{
$isLinux = $true
}
if ($image.Category -ne "User")
{
throw "The Azure image must be user customized and the HPC Pack compute node role or broker node role must already be installed."
}
# set current Azure storage account
$mediaLink = $image.MediaLink
if (($mediaLink -eq $null) -and ($image.OSDiskConfiguration -ne $null))
{
$mediaLink = $image.OSDiskConfiguration.MediaLink
}
if ($mediaLink -eq $null)
{
throw "Invalid virtual machine image. Cannot find the MediaLink for image $ImageName."
}
$storageAccount = GetStorageAccountFromMediaLink $mediaLink
Set-AzureSubscription -SubscriptionName $subscriptionName -CurrentStorageAccountName $storageAccount
}
else
{
throw "Cannot find Azure virtual machine image $ImageName. Check the image name."
}
# validate user name and password
TraceInfo "Validating domain user name and password"
if ([String]::IsNullOrEmpty($DomainUserPassword))
{
$secPsw = Read-Host -Prompt "Please input the password for the domain user $DomainUserName" -AsSecureString
$DomainUserPassword = ConvertSecureStrToPlain -SecurePassword $secPsw
}
$sepidx = $DomainUserName.IndexOf('\')
$userDomain = $null
if ($sepidx -gt 1)
{
$userDomain = $DomainUserName.Substring(0, $sepidx)
}
if ([String]::IsNullOrEmpty($userDomain))
{
# using domain of head node
$userDomain = (Get-WmiObject Win32_ComputerSystem).Domain
}
$userName = $DomainUserName.Substring($sepidx+1, ($DomainUserName.Length - $sepidx)-1)
$userDomain = ValidateCredentials $userDomain $userName $DomainUserPassword
TraceInfo "PROGRESS:10"
# new Azure VMs
# get node name series
$usingHpcNamingSeries = $false
if([String]::IsNullOrEmpty($NodeNameSeries))
{
$NodeNameSeries = "AzureVMCN-%0000%"
if([String]::IsNullOrEmpty($NodeNameSeries))
{
throw "Specify the node naming series or configure the naming of new nodes in the HPC cluster."
}
}
TraceInfo "Validating node naming series ......"
ValidateNodeNameSeries $NodeNameSeries
TraceInfo "Generating node names ......"
$existedAzureNodes = GetAzureVMs $iaasInfo
$retry=0
while($true)
{
try
{
$nodeList = GenerateHpcNodeName $NodeNameSeries $Quantity $usingHpcNamingSeries $existedAzureNodes
break;
}
catch
{
if($retry -lt 100)
{
$retry++
Start-Sleep -Seconds 6
}
else
{
thrown
}
}
}
$localAdminCred = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList @($userName, (ConvertTo-SecureString -String $DomainUserPassword -AsPlainText -Force))
$domainUserCred = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList @("$userDomain\$userName", (ConvertTo-SecureString -String $DomainUserPassword -AsPlainText -Force))
TraceInfo "PROGRESS:15"
Write-Host
TraceInfo "Starting to create $Quantity Azure virtual machines one by one"
$step = 0
$clusterName = $env:COMPUTERNAME
$AzureSizeInfo = @{"Small"=@{"Core"=1;"Socket"=1;"Memory"=1750}; `
"Medium"=@{"Core"=2;"Socket"=1;"Memory"=3500}; `
"Large"=@{"Core"=4;"Socket"=1;"Memory"=7000}; `
"ExtraLarge"=@{"Core"=8;"Socket"=1;"Memory"=14000};`
"A5"=@{"Core"=2;"Socket"=1;"Memory"=14000};`
"A6"=@{"Core"=4;"Socket"=1;"Memory"=28000};`
"A7"=@{"Core"=8;"Socket"=1;"Memory"=56000};`
"A8"=@{"Core"=8;"Socket"=1;"Memory"=56000};`
"A9"=@{"Core"=16;"Socket"=1;"Memory"=112000}`
}
$linuxNodes = @{}
$stepPercent = [math]::Floor(75/$Quantity)
foreach($node in $nodeList)
{
$step ++
TraceInfo "($step / $Quantity) Creating Azure virtual machine $node ......"
if ($isLinux)
{
if ($AzureSizeInfo.Keys -notcontains $InstanceSize)
{
throw "$InstanceSize is not supported!"
}
$vm = New-AzureVMConfig -Name $node -InstanceSize $InstanceSize -ImageName $ImageName
$vm = $vm | `
Add-AzureProvisioningConfig -Linux -LinuxUser $localAdminCred.UserName -Password $localAdminCred.GetNetworkCredential().Password |`
Set-AzureSubnet -SubnetNames $iaasInfo.SubNet
if(($InstanceSize -eq "A8") -or ($InstanceSize -eq "A9"))
{
$vm = $vm | Set-AzureVMExtension -ExtensionName "HpcVmDrivers" -Publisher "Microsoft.HpcCompute" -Version "1.*"
}
New-AzureVMWithRetry -VM $vm -ServiceName $ServiceName -VNetName $iaasInfo.VNet -DeploymentLabel $deloymentLabel
$linuxNodes[$node] = $InstanceSize
}
else
{
CreateDomainJoinedVMWithCustomScript -VMName $node `
-ServiceName $ServiceName `
-VMSize $InstanceSize `
-ImageName $ImageName `
-VNetName $iaasInfo.VNet `
-SubnetName $iaasInfo.SubNet `
-LocalAdminCred $localAdminCred `
-DomainUserCred $domainUserCred `
-DomainFQDN $userDomain `
-DeploymentLabel $deloymentLabel `
-ClusterName $clusterName *>$null
}
$percent = $stepPercent*$step + 15
TraceInfo "PROGRESS:$percent"
}
if ($isLinux)
{
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\HPC\IaaSInfo -Name NodeType -Value Linux
TraceInfo "Checking HPC nodes group for linux nodes"
AddHpcLinuxGroup *>$null
}
if ($linuxNodes.Count -gt 0)
{
TraceInfo "PROGRESS:95"
$nodeStatus = @{}
foreach ($node in $linuxNodes.Keys)
{
# add unmanagement node to HPC
$size = $linuxNodes[$node]
$info = $AzureSizeInfo[$size]
AddUnManagedNodeWithRetry $node $info.Core $info.Socket $info.Memory *>$null
$nodeStatus[$node] = $false
}
TraceInfo "Waiting for linux nodes ready ......"
# add ip to host file
while ($true)
{
$ipToAdd = @{}
$deployment = InvokeAzureCmdWithRetry -Command "Get-AzureDeployment -ServiceName $ServiceName -ErrorAction SilentlyContinue"
foreach ($role in $deployment.RoleInstanceList)
{
if ($linuxNodes.Keys -ccontains $role.HostName)
{
$ipToAdd[$role.IPAddress] = $role.HostName
}
}
if ($ipToAdd.Keys.Count -lt $linuxNodes.Keys.Count)
{
Start-Sleep -Seconds 5
}
else
{
break
}
}
$existingHostEntry = Get-HostNames.ps1
foreach ($entry in $existingHostEntry)
{
if ($ipToAdd.Keys -ccontains $entry.IpAddress)
{
Remove-HostNames.ps1 $entry.Hostname
}
}
foreach ($ip in $ipToAdd.Keys)
{
Add-HostNames.ps1 $ip $ipToAdd[$ip]
}
while ($true)
{
$snapshotNodeStatus = @{}
foreach ($node in $nodeStatus.Keys)
{
$snapshotNodeStatus[$node] = $nodeStatus[$node]
}
$falseNodes = 0
foreach ($node in $snapshotNodeStatus.Keys)
{
if ($snapshotNodeStatus[$node] -eq $false)
{
$pingInfo = C:\ConfigureLinux\TestStream.exe $node
if (-not $?)
{
$falseNodes++
TraceWarning "Linux node $node is still not ready!"
}
else
{
$info = $pingInfo -join ","
if ($info -like "*Exception*")
{
TraceWarning "Linux node $node is still not ready!"
$falseNodes++
}
else
{
TraceInfo "Linux node $node is ready"
$nodeStatus[$node] = $true
}
}
}
}
if($falseNodes -gt 0)
{
Start-Sleep -Seconds 5
}
else
{
break
}
}
}
}
catch
{
TraceToLogFile $_
throw
}
Write-Host
TraceInfo "All Azure virtual machines have been created. It may take several minutes to start the virtual machines; please wait. The nodes will be automatically added to the HPC cluster."