Friday, February 1, 2013

Reincarnating - Exporting - Importing an Azure Virtual Machine and Service

There are times when I really like the fact that I have to figure stuff out.  And then I have to do it again, and then for a co-worker.  Then before you know it I have to do it in a really serious way.

You could also describe this as Exporting and Importing an entire multi-machine Service.

Why might you want to do this?

  • Moving a Service from one Subscription to another.
  • Moving a Service from one Storage Account to another.
  • Rebuilding a Service in place to force the machines to new hardware.
  • Recover a ‘misbehaving’ machine.
  • Fixing / changing configurations of the Virtual Network or subnet (okay, you would have to modify the XML files, but still).
  • Bringing your machine / service configuration down to earth (without some other tool).

In this case there are the traditional IaaS / Datacenter reasons, of which there a few.  But from the PaaS side there might be lots of reasons.  And coming for a datacenter background, the PaaS thinking around this simply seems foreign and strange, but it really is the ‘cloud’ way of thinking about this – when you are working at an abstracted layer.

In my case; this script began with having to destroy and reincarnate Virtual Machines in Azure (over and over again, for various reasons).  Then I had to move my entire Service to an entirely different Account and thus Subscription.  So it evolved into that.

To complicate things I use Virtual Networks (the Azure software defined networking abstraction) and its Subnets.

Why would you need to reincarnate a Virtual Machine?  (and why are you using this reincarnate word?).

I love the term ‘reincarnate’ when describing changing the configuration of an Azure machine.  Due to the PaaS beginnings it is a fitting description of what actually happens.  The virtual disk stays intact, only the configuration and the deployed machine go away.

For example, you want to move a VM to a different Virtual Network, or Subnet.  You need to destroy it and make it again.  If you want to change the Affinity Group, you need to destroy and make again.  If something on Azure is going all pear-shaped – what do they recommend?  Delete and recreate.

What happens when you reincarnate?  Well, for starters you end up on a different stamp.  Your machine will literally be some place else in the infrastructure.  If you are like me and constantly play with Beta releases, this can be a great thing (or a not so great thing).

Any way, lets get to preserving my script where I can find it in the future when I need it again.  The other thing this will demonstrate is walking through various things in Azure and dependency chains.

 

#Azure cmdlets v0.6.9

Import-Module -Name Azure

# Download the settings file.  This only needs to be done once, until the certificates expire.
# Get-AzurePublishSettingsFile # (this opens an IE window.  Logon.  A certificate is generated in all accounts that your Microsoft Account has access to and embedded in the settings file.  Download the settings file.)

Import-AzurePublishSettingsFile 'C:\Users\Public\Documents\MyServices.publishsettings'

###### start Azure Subscription Selector  ######
Get-AzureSubscription | ft
$sourceSub = [string](Read-Host -Prompt "Type the name of the SOURCE Subscription")
Select-AzureSubscription -SubscriptionName $sourceSub

Get-AzureStorageAccount | ft
$sourceStor = [string](Read-Host -Prompt "Type the name of the SOURCE Storage Account")
$sourceStorKey = Get-AzureStorageKey -StorageAccountName $sourceStor
Set-AzureSubscription -SubscriptionName $sourceSub -CurrentStorageAccount $sourceStor

Get-AzureStorageAccount | ft
$targetStor = [string](Read-Host -Prompt "Type the name of the TARGET Storage Account")
$targetStorKey = Get-AzureStorageKey -StorageAccountName $targetStor

Get-AzureSubscription | ft
$targetSub = [string](Read-Host -Prompt "Type the name of the TARGET Subscription")
Select-AzureSubscription -SubscriptionName $targetSub
###### end Azure Subscription Selector ######

###### start Azure Service VM export ######
Get-AzureService | ft ServiceName, Description, AffinityGroup, URL
$sourceSer = [string](Read-Host -Prompt "Type the name of the SOURCE Service")
Get-AzureVM -ServiceName $sourceSer | ft
$myVm = Read-Host -Prompt "what is the VM name you want to export?  (type '*' for all)"

If ($myVm -eq "*") {
    $path = 'C:\users\public\Downloads\azure\' + $sourceSer
    if ((Test-Path -Path $path -PathType Container) -eq $false) {New-Item -ItemType directory -Path $path}
    Get-AzureVNetConfig -ExportToFile ($path + "\vnetconfig.xml")
     Get-AzureVM -ServiceName $sourceSer | foreach { 
         $vmpath = $path + '\' + $_.Name + '.xml'
         Export-AzureVM -ServiceName $sourceSer -Name $_.Name -Path $vmpath
    }
}
else{
    $path = 'C:\users\public\Downloads\azure\' + $sourceSer 
    if ((Test-Path -Path $path -PathType Container) -eq $false) {New-Item -ItemType directory -Path $path}
    Get-AzureVNetConfig -ExportToFile ($path + "\vnetconfig.xml")
    $vmpath = $path + '\' + $myVm + '.xml'
    Export-AzureVM -ServiceName $sourceSer -Name $myVm -Path $vmpath
}
###### end Azure Service VM export ######

##### Start Service and Deployment deletion #####
$vms = Get-AzureVM -ServiceName $sourceSer

###### start Azure Service Removal ######
If ($myVm -eq "*") {
    foreach($vm in $vms){
        Remove-AzureVM -ServiceName $sourceSer -Name $vm.name
    }
    Start-Sleep 10
    Remove-AzureDeployment -ServiceName $sourceSer -Slot Production -Force
    Start-Sleep 10
    Remove-AzureService -ServiceName $sourceSer -Force
}
###### end Azure Service Removal ######

# Remove-AzureDisk to de-register from the VHD Library and remove the lease before the blobs can be copied to another Storage account
If ($myVm -eq "*") {
    foreach ($vm in $vms) {
        $osDisk = Get-AzureOSDisk -VM $vm
        $dataDisk = Get-AzureDataDisk -VM $vm
        If ($osDisk -ne $null){ Remove-AzureDisk -DiskName $osDisk.DiskName }
        Foreach ($dat in $dataDisk){
            If ($dat -ne $null){ Remove-AzureDisk -DiskName $dat.DiskName }
        }
    }
}

##### end Service and Deployment deletion ######

###### start Azure VM VHD copy ######


At this writing this is all hand wavy because the PowerShell cmdlets don’t support it yet.  I used a third party GUI that did the copying using the Azure Storage API.

 

## Start VHD registration with the VHD Library ##
Add-AzureDisk -OS Windows -MediaLocation
http://mydemo.blob.core.windows.net/vhds/myDemo-Foo-2013-1-8-762B.vhd -DiskName 'myDemo-Foo-0-2013010819464B' -Label Foo
Add-AzureDisk -OS Windows -MediaLocation
http://mydemo.blob.core.windows.net/vhds/MyDemo-Bar-2013-1-8-761B.vhd -DiskName 'myDemo-Bar-0-2013010819450B' -Label Bar
## End VHD registration with the VHD Library ##

###### end Azure VM VHD copy ######

 

##### start create new Service / VMs #####
# Query New Service name, and Subscription name
# $targetSer = $sourceSer  # for reincarnation

$vms = @()
$path = 'C:\users\public\Downloads\azure\' + $targetSer
$vmsToImport = Get-ChildItem $path

foreach ($vm in $vmsToImport) { 
    if ($vm.Name -match 'vnetconfig'){
        [xml]$vNetConfig = Get-Content -Path $vm.FullName  # if modification, it needs to happen, but this can be used later
        Set-AzureVNetConfig -ConfigurationPath $vm.FullName  -ErrorAction Continue  #if adding a VNet to a Subscription with an existing VNet, this will falsely error.  Check after this step to be sure the VNet created before adding the VMs.
    }
    else {
        $vms += Import-AzureVM -Path $vm.FullName
    }
}

# Choose the VNet to properly fill the following.  This is at the Subscription level
Get-AzureVNetSite | ft Name, AddressSpacePrefixes, AffinityGroup, Subnets, DnsServers, InUse
$myVNet = Read-Host "What is the Name of your target Virtual Network for the Domain Controller / DNS Server?"
$myVNet = Get-AzureVNetSite -VNetName $myVNet
# no need to query the subnet because the VM configurations contain that.

If ((Test-AzureName -Service $targetSer) -eq $false){
    # Importing to Existing Service is the assumption
    New-AzureVM -ServiceName $targetSer -VMs $vms -VNetName $myVNet.Name
}
else {
    # Creating new Service is the Assumption
    New-AzureVM -ServiceName $targetSer -VMs $vms -Location "You Should Know" -VNetName $myVNet.Name -AffinityGroup "SorryIDidn’tQuery"
}

##### end create new Service / VMs #####

No comments: