天天看點

[Azure]使用Powershell将ARM虛拟機(托管磁盤)加入可用性集

前面一篇Blob說明了非托管磁盤虛拟機如何使用Powershell通過重建的方式加入可用性集,這一篇給大家提供托管磁盤的版本。

托管磁盤其實與非托管磁盤的代碼幾乎一樣,差別僅僅在于托管磁盤添加磁盤的方式以及可用性集的類型稍有不同,思路是一樣的,話不多說,我們直接看代碼:

param(
    [Parameter(Mandatory = $true)] 
    [string]$SubscriptionName, 
 
    [Parameter(Mandatory = $true)]
    [string]$ResourceGroupName,

    [Parameter(Mandatory = $true)]
    [string]$VMName,

    [Parameter(Mandatory = $true)]
    [string]$AvailabilitySetName
)

Function GetResourceNameFromResourceId($resourceId)
{
    return $resourceId.Substring($resourceId.LastIndexOf('/') + 1);
}

Function GetResourcePropertyFromResourceId($resourceId, $propertyName)
{
    $propertyName = $propertyName + "/";
    $rgName = $resourceId.Substring($resourceId.IndexOf($propertyName) + $propertyName.Length);
    return $rgName.Substring(0, $rgName.IndexOf("/"));
}

Function CollectVMInformation($rgName, $vmName, $avaSetName)
{
    $vmInfo = @{};
    $vmInfo.Add("ResourceGroup", $rgName);
    $vmInfo.Add("Name", $vmName);
    
    $vm = Get-AzureRmVM -ResourceGroupName $rgName -Name $vmName -ErrorAction Ignore -WarningAction Ignore;
    if ($vm -eq $null)
    {
        return $null;
    }

    $vmInfo.Add("Size", $vm.HardwareProfile.VmSize);
    $vmInfo.Add("Location", $vm.Location);
    if (!(CreateAvailabilitySet $rgName $avaSetName $vm.Location))
    {
        return $null;
    }
    $avaSet = Get-AzureRmAvailabilitySet -ResourceGroupName $rgName -Name $avaSetName;
    $vmInfo.Add("AvailabilitySet", $avaSet.Id);

    $vmInfo.Add("OSType", $vm.StorageProfile.OsDisk.OsType.ToString());

    #network properties
    $nicId = ($vm.NetworkProfile.NetworkInterfaces | where {$_.Primary -eq $true}).Id;
    if ($nicId -eq $null -and $vm.NetworkProfile.NetworkInterfaces.Count -eq 1)
    {
        $nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id;
    }
    #$nicName = GetResourceNameFromResourceId $nicId;
    #$nic = Get-AzureRmNetworkInterface -Name $nicName -ResourceGroupName $rgName;
    #$subnetId = $nic.IpConfigurations[0].Subnet.Id;
    #$subnetName = GetResourceNameFromResourceId $subnetId;
    #$vnetName = GetResourcePropertyFromResourceId $subnetId "virtualNetworks";
    #$vmInfo.Add("VirtualNetwork", $vnetName);
    #$vmInfo.Add("Subnet", $subnetName);
    $vmInfo.Add("PrimaryNetworkInterfaceId", $nicId);

    $secondaryNics = @($vm.NetworkProfile.NetworkInterfaces | where {$_.Primary -eq $false});
    $vmInfo.Add("SecondaryNetworkInterfaces", $secondaryNics);
    #$vnet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName;
    #$subnet01 = Get-AzureRmVirtualNetworkSubnetConfig -Name $subnetName -VirtualNetwork $vnet;

    #disk
    $vmInfo.Add("OSDisk", $vm.StorageProfile.OsDisk);
    $vmInfo.Add("DataDisks", @($vm.StorageProfile.DataDisks));

    return $vmInfo;
}

Function DeleteOldVM($rgName, $vmName)
{
    [void](Remove-AzureRmVM -ResourceGroupName $rgName -Name $vmName -Force);
    #if lease is not broken, we need to sleep for some time
    #sleep 10
}

Function CreateAvailabilitySet($rgName, $avaSetName, $location)
{
    $avaSet = Get-AzureRmAvailabilitySet -ResourceGroupName $rgName -Name $avaSetName -ErrorAction Ignore;
    if ($avaSet -eq $null)
    {
        $avaSet = New-AzureRmAvailabilitySet -ResourceGroupName $rgName -Name $avaSetName -Location $location -Sku "Aligned" -PlatformUpdateDomainCount 5 -PlatformFaultDomainCount 2 -Managed;
        return $true;
    } 
    elseif ($avaSet.Sku -ne "Aligned")
    {
        Write-Host "There's an existing availability set whose sku is not Aligned, conflict with managed-disk";
        return $false;
    }
    else 
    {
        return $true;
    }
}

Function RebuildVM($vmInfo)
{
    #basic information
    $rgName = $vmInfo["ResourceGroup"];
    $vmName = $vmInfo["Name"];
    $vmSize = $vmInfo["Size"];
    $location = $vmInfo["Location"];
    $osType = $vmInfo["OSType"];

    #network
    #$vnetName = $vmInfo["VirtualNetwork"];
    #$subnetName = $vmInfo["Subnet"];
    $primaryNicId = $vmInfo["PrimaryNetworkInterfaceId"];
    $secondaryNics = $vmInfo["SecondaryNetworkInterfaces"];
    
    #disk
    $osDisk = $vmInfo["OSDisk"];
    $dataDisks = $vmInfo["DataDisks"];

    $avaSetId = $vmInfo["AvailabilitySet"];
    $vmconfig = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize -AvailabilitySetId $avaSetId;
    $vmconfig = $vmconfig | Set-AzureRmVMBootDiagnostics -Disable;

    if ($osType -eq "Windows")
    {
        $vmconfig = $vmconfig | Set-AzureRmVMOSDisk -ManagedDiskId $osDisk.ManagedDisk.Id -Caching $osDisk.Caching -CreateOption attach -Windows;
    } else {
        $vmconfig = $vmconfig | Set-AzureRmVMOSDisk -ManagedDiskId $osDisk.ManagedDisk.Id -Caching $osDisk.Caching -CreateOption attach -Linux;
    }
    #下面這個步驟是必須要有而且非常重要的,實測下來發現上面的指令有個小bug,就是托管磁盤添加後,磁盤名預設會被設定成虛拟機名稱
    #導緻建立的時候報錯“New-AzureRmVM : Changing property 'osDisk.name' is not allowed”
    $vmconfig.StorageProfile.OsDisk.Name = $osDisk.Name;
    $vmconfig.StorageProfile.ImageReference = $null;

    $index = 0;
    foreach ($dataDisk in $dataDisks)
    {
        $vmconfig = $vmconfig | Add-AzureRmVMDataDisk -ManagedDiskId $dataDisk.ManagedDisk.Id -Lun $dataDisk.Lun -Caching $dataDisk.Caching -CreateOption attach;
        #下面這個步驟是必須要有而且非常重要的,實測下來發現上面的指令有個小bug,就是托管磁盤添加後,磁盤名預設會被設定成虛拟機名稱
        #導緻建立的時候報錯“New-AzureRmVM : Changing property 'dataDisk.name' is not allowed”
        $vmconfig.StorageProfile.DataDisks[$index].Name = $dataDisk.Name;
        $index += 1;
    }

    $vmconfig = $vmconfig | Add-AzureRmVMNetworkInterface -Id $primaryNicId -Primary;
    foreach ($secondaryNic in $secondaryNics)
    {
        $secondaryNicId = $secondaryNic.Id;
        $vmconfig = $vmconfig | Add-AzureRmVMNetworkInterface -Id $secondaryNicId;
    }

    [void](New-AzureRmVM -ResourceGroupName $rgName -Location $location -VM $vmconfig);
}

[void](Select-AzureRmSubscription -SubscriptionName $SubscriptionName);

Write-Host "Collecting VM information...";
$vmInfo = (CollectVMInformation $ResourceGroupName $VMName $AvailabilitySetName);
if ($vmInfo -eq $null)
{
    Write-Host "Failed to collect vm information." -ForegroundColor Red;
    return;
}

Write-Host "Deleting old VM...";
DeleteOldVM $ResourceGroupName $VMName;

Write-Host "Rebuilding VM...";
RebuildVM $vmInfo;

Write-Host "Finished";
           

腳本運作示例:

[Azure]使用Powershell将ARM虛拟機(托管磁盤)加入可用性集

腳本參數中指定的AvailabilitySetName可以是已有的,也可以指定不存在的,如果不存在的話,會建立一個AvailabilitySet,注意AvailabilitySet是區分托管和非托管的。

繼續閱讀