Moving resources with ARM

Resource Groups allow you to manage multiple resources within Azure as a logical group. Resource Groups are enabled via the Azure Resource Manager (ARM), which is the new mechanism for managing and securing resources in Azure.

If you have created resources via the old Azure Portal or Service Management APIs, then you may notice that they belong to Default-XXXX Resource Groups when viewed in the new Azure Portal.

Current State

As you can see from the following view of one of my subscriptions in the new Azure Portal, I have a Storage Account that is part of a Resource Group named Default-Storage-WestUS. I originally created this Storage Account in the old Azure Portal but have re-used it for the pbubuntu VM. The VM and its associated Cloud Service were created via the new Azure Portal and were placed into a Resource Group named pbubuntu.

Azure Resources - Before

I’ve been cleaning up a number of orphaned Default-XXXX Resource Groups this week. I did however want to keep the portalvhds2knfjr67c7f3q Storage Account, since it held the VHD for my VM. I was looking for a way to move a resource from one Resource Group to another. I wanted to move the portalvhds2knfjr67c7f3q Storage Account into my pbubuntu Resource Group.

Trying to move the resource

I discovered the Azure PowerShell cmdlet Move-AzureResource and the Move a resource section in the Using Azure PowerShell with Azure Resource Manager blog post described exactly what I was trying to do. But when I tried to run the cmdlet it returned immediately (with no error) and no effect on my resources.

PS C:\> Get-AzureResource -ResourceId /subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/Default-Storage-WestUS/providers/Microsoft.ClassicStorage/storageAccounts/portalvhds2knfjr67c7f3q | Move-AzureResource -DestinationResourceGroupName pbubuntu

When I involved Fiddler in the debugging effort I noticed that there was no traffic being sent across the wire. No REST API calls were being made. Then I discovered this issue on GitHub – #379 Moving Azure resources doesn’t do anything. This was related to version 0.9.1 of the Azure PowerShell cmdlets – which is what I was running.

No problem I thought, I’ll use the Azure xplat cli, but quickly found that the move feature was not yet implemented on the resource command …

Ok – back to basics then.

I’d look up the REST API endpoint and payloads and use raw REST calls. I opened up the Azure Resource Manager REST API Reference on MSDN and tried to find the REST API for moving a resource. Nothing … This was not going well.

Diving into cmdlet source code

My next step was to download the Azure PowerShell code from GitHub and attempt to discover the REST API endpoint and payload from the Move-AzureResource cmdlet source code. I built the code and ran the MoveResourceTest test to start debugging the cmdlet.

Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.MoveAzureResourceCommand

I managed to extract the REST API endpoint (managementUri) and infer the payload structure from the ResourceBatchMoveParameters class. I confirmed my findings with Ilya Grebnov, the Architect and Lead Engineer of Azure Resource Manager.

Thanks to Ilya for getting back to me so quickly and for correcting my initial attempt at the payload.

Moving that resource !

ARMClient is a simple command line tool to invoke the Azure Resource Manager API and can be found on GitHub. It is fairly low level and allows you to interact with the raw REST API directly. ARMClient is great in that it manages the Azure authentication tokens for you. Have a look at the ARMClient: a command line tool for the Azure API blog post to understand this tool better.

ARMClient is available via chocolatey and I installed it as follows:

choco install armclient

I then created the payload in a file named move-resource.json. The targetResourceGroup is the full path to the Resource Group I’d like to move the resource to. In this case it’s the pbubuntu Resource Group in my subscription. The resources collection contains the full path to the resources I’d like to move. My collection consists solely of my portalvhds2knfjr67c7f3q Storage Account.

{
  "targetResourceGroup": "/subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/pbubuntu",
  "resources": [
    "/subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/Default-Storage-WestUS/providers/Microsoft.ClassicStorage/storageAccounts/portalvhds2knfjr67c7f3q"
  ]
}

You will be required to authenticate yourself to use the ARMClient. You can do that as follows:

PS C:\> armclient login

Then I issued a POST to the REST API endpoint for moving a resource out of my Default-Storage-WestUS Resource Group. I included a reference to my move-resource.json file (you need to include the @ prefix) and switched on verbose mode to get as much detail as possible.

PS C:\> armclient post https://management.azure.com/subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/Default-Storage-WestUS/moveResources?api-version=2015-01-01 @C:\Dev\move-resource.json -verbose
---------- Request -----------------------

POST /subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/Default-Storage-WestUS/moveResources?api-version=2015-01-01 HTTP/1.1
Host: management.azure.com
Authorization: Bearer eyJ0eXAiOiJKV...
User-Agent: ARMClient/1.0.0.0
Accept: application/json
x-ms-request-id: 586648f9-d5ad-43de-b281-e0269ec3cd48

{
"targetResourceGroup": "/subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/pbubuntu",
"resources": [
"/subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/Default-Storage-WestUS/providers/Microsoft.ClassicStorage/storageAccounts/portalvhds2knfjr67c7f3q"
]
}
---------- Response (5333 ms) ------------

HTTP/1.1 202 Accepted
Pragma: no-cache
Retry-After: 15
x-ms-ratelimit-remaining-subscription-writes: 1199
x-ms-request-id: acc728c3-7086-4774-9665-e30d15bf6084
x-ms-correlation-request-id: acc728c3-7086-4774-9665-e30d15bf6084
x-ms-routing-request-id: AUSTRALIAEAST:20150526T044311Z:acc728c3-7086-4774-9665-e30d15bf6084
Strict-Transport-Security: max-age=31536000; includeSubDomains
Cache-Control: no-cache
Date: Tue, 26 May 2015 04:43:11 GMT
Location: https://management.azure.com/subscriptions/[MY_SUBSCRIPTION_ID]/operationresults/eyJqb2JJZCI6IlJFU09VUkNFQkFUQ0hNT1ZFSk9CLURFRkFVTFQ6MkRTVE9SQUdFOjJEV0VTVFVTLVdFU1RVUyIsImpvYkxvY2F0aW9uIjoid2VzdHVzIn0?api-version=2015-01-01

After a few seconds, a quick check with the Get-AzureResource cmdlet (filtered to the pbubuntu Resource Group) showed that my Storage Account had been moved.

PS C:\> Get-AzureResource -ResourceGroupName pbubuntu

Name              : pbubuntu
ResourceId        : /subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/pbubuntu/providers/Microsoft.ClassicCompute/domainNames/pbubuntu
ResourceName      : pbubuntu
ResourceType      : Microsoft.ClassicCompute/domainNames
ResourceGroupName : pbubuntu
Location          : westus
SubscriptionId    : [MY_SUBSCRIPTION_ID]

Name              : pbubuntu
ResourceId        : /subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/pbubuntu/providers/Microsoft.ClassicCompute/virtualMachines/pbubuntu
ResourceName      : pbubuntu
ResourceType      : Microsoft.ClassicCompute/virtualMachines
ResourceGroupName : pbubuntu
Location          : westus
SubscriptionId    : [MY_SUBSCRIPTION_ID]

Name              : portalvhds2knfjr67c7f3q
ResourceId        : /subscriptions/[MY_SUBSCRIPTION_ID]/resourceGroups/pbubuntu/providers/Microsoft.ClassicStorage/storageAccounts/portalvhds2knfjr67c7f3q
ResourceName      : portalvhds2knfjr67c7f3q
ResourceType      : Microsoft.ClassicStorage/storageAccounts
ResourceGroupName : pbubuntu
Location          : westus
SubscriptionId    : [MY_SUBSCRIPTION_ID]

End State

And checking the new Azure Portal also confirms my portalvhds2knfjr67c7f3q Storage Account has indeed been moved into my pbubuntu Resource Group.

Azure Resources - After

I’m hoping that the next release of the Azure PowerShell cmdlets will fix the Move-AzureResource cmdlet and that the Azure xplat cli will implement this functionality in the near future. In the interim, you can use ARMClient and the endpoint and payload as described in this post.

Advertisements