3

A historically grown project with it's associated infrastructure on Azure must be split up. Luckily, it is well structured and as a result it is pretty clear that we need to move two resource groups and it's affiliated resources to a new Azure subscription.

  • I have checked, most of the resource can be moved, thus don't have to be created anew and data can be preserved.

  • For those resources that cannot be moved, luckily we are using terraform, which can be run to re-create those resources.

  • The resources that need to be moved is an entire terraform-project, so there is no need to remove resources from the current configuration files. All of it needs to go to a new subscription.

So far so good, but now I need to understand how to practically proceed, so that terraform is aware of the moved resources. The only option I currently see is to manually move the resources on the Azure portal, change subscription on the CLI/for terraform and then run an terraform state rm; terraform import or a terraform mv for each of the resources.

Isn't there an easier way to achieve this? It seems overly cumbersome and basically would make it easier to just delete the entire infrastructure in the current subscription and recreate it via terraform in the new subscription (not an option!)

dmeu
  • 3,842
  • 5
  • 27
  • 43

2 Answers2

5

It is NOT possible to move resources from one resource group to another simply via changing resource_group_name parameter in *tf file. Terraform 1.0.2 will attempt to destroy such a resource, therefore trying to setup a multi-subscription terraform workspace is futile. Also as docs say:

resource_group_name - (Required) The name of the Resource Group in which the Linux Virtual Machine should be exist. Changing this forces a new resource to be created.

TL;DR - there is no native mechanism for migrating Azure resources between resource groups or subscriptions via terraform

As you point out, moving resources manually and retaining them in Terraform would require some state file manipulation. Fortunately Azure resource IDs are pretty straightforward, so a simple string processing in bash can do the trick.

Quick and dirty bash script could just replace old subscription UUID with new and be similar to this (WARNING - Correct implementation depends on your setup - do some testing before running all the statements):

# Extract the identifying URLs using terraform plan
terraform  plan | grep "Refreshing state" > terraform-current-states.txt
# Extract the states we know from the configuration
terraform state list > terraform-state-list.txt

# Subscription strings
OLD_SUBSCRIPTION=11111111-1111-1111-1111-111111111111
NEW_SUBSCRIPTION=00000000-0000-0000-0000-000000000000
# Resource group strings (other name)
OLD_RG='SOME_NAME'
NEW_RG='ANOTHER_NAME'

# Iterate over state list
cat terraform-state-list.txt | while read RESOURCE; do
  AZURE_ID=$(grep "${RESOURCE}"  terraform-current-states.txt | cut -d"=" -f2 | tr -d ']')

  # null resources etc can be filtered out - no AZURE_ID
  if [ -z "$AZURE_ID" ]; then
    continue
  fi

  # print out the current resource and azure id mapping as a comment
  echo "# ${RESOURCE} ${AZURE_ID}"

  # replace the subscription and resource group strings (and remove weird characters from terraform
  NEW_AZURE_ID=$(echo ${AZURE_ID} | sed "s/${OLD_SUBSCRIPTION}/${NEW_SUBSCRIPTION}/" | sed "s/${OLD_RG}/${NEW_RG}/g" | sed "s/\x1b\[[0-9;]*m//g")

  # replace the current terraform state with a "state rm" and then "import" command
  echo "terraform state rm ${RESOURCE}; terraform import ${RESOURCE} ${NEW_AZURE_ID}
  "
done > terraform-migration-generated-script.sh

The above produces a ready-to-use terraform-migration-generated-script.sh script with terraform rm and terraform import commands.

Don`t forget about state backup or even terraform state pull and push to different location before you start.

dmeu
  • 3,842
  • 5
  • 27
  • 43
ValueError
  • 136
  • 3
  • Thanks for your insights and suggested solution, @rogue_white_belt ! This has clarified a lot for me. I'll have a go and report back in some days – dmeu Sep 23 '21 at 05:43
  • 2
    this seems to be working. Notice that I had to change quite a few things in the bash script, but the general idea is much the same. I incorporated the changes into your answers (apparently I can do that...) for future reference. Thanks again for your input! – dmeu Sep 24 '21 at 07:56
1

This been a massive problem for me, but there's official way to do this and it's totally possible. You have to remove the resource from state, and import it again.

Short examples:

Get resource id

$ echo azurerm_autoscale_setting.example.id | terraform console
/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/microsoft.insights/autoscalesettings/setting1

Than remove the resource from state:

$ terraform state rm azurerm_autoscale_setting.example
Removed azurerm_autoscale_setting.example
Successfully removed 1 resource instance(s).

Now go to azure portal and move the resource, when you'll be moving, it will be determined if it can be moved. Actually I'd do this first, only then start touching terraform state.

$ terraform import [resourcename].[identifier] [resourceid]

Example:

$ terraform import azurerm_monitor_autoscale_setting.test /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/microsoft.insights/autoscalesettings/setting1
azurerm_monitor_autoscale_setting.test: Importing from ID "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/microsoft.insights/autoscalesettings/setting1"...
azurerm_monitor_autoscale_setting.test: Import prepared!
  Prepared azurerm_monitor_autoscale_setting for import
azurerm_monitor_autoscale_setting.test: Refreshing state... [id=/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/microsoft.insights/autoscalesettings/setting1]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

And now your terraform plan should not show any changes. Enjoy!

Official manual for azurerm provider how to migrate resources:

https://registry.terraform.io/providers/hashicorp/azurerm/2.35.0/docs/guides/migrating-between-renamed-resources

holms
  • 9,112
  • 14
  • 65
  • 95