欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Azure]使用Powershell将ARM虚拟机(托管磁盘)加入可用性集

程序员文章站 2023-12-30 16:17:46
...

前面一篇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是区分托管和非托管的。

上一篇:

下一篇: