We are in the process of re-writing our Terraform modules to make use of “for_each” instead of “count” and we are finding difficulties migrating networks deployed with the old module to the new one. I would like to know if there is an official procedure for this.
The main problems we are finding and solution approach we are taking:
- If you try to apply the new code in an already existing vnet Terraform will plan to destroy every subnet and create it with the new nomenclature:
- Ok, don’t panic, lets rename all the subnets in the state file instead of destroy/add them:
terraform state mv 'module.network.azurerm_subnet.subnet' 'module.network.azurerm_subnet.subnet["westeurope-dev-app"]'
The main problem is that “count” deploys a ‘list’ of resources while “for_each” creates a ‘map’ and the mv command only renames the resource but it doesn’t change the list to a map so once you finish renaming subnets you end up with an empty list to the eyes of Terraform because it cannot access its elements (a list element should be accessed by position ‘number’, not by ‘key’". You will also experience some Terraform crashes after this movement because of “nill interface”…
Clue is in the state file:
"each": "map", versus
- Ok, after many try/test we found two ways to “fix” this new problem:
- By removing only one subnet from the state file and importing it again Terraform changes from list to map and everything seems fine, is it?
terraform state rm 'module.network.azurerm_subnet.subnet["westeurope-dev-app"]'
terraform import 'module.network.azurerm_subnet.subnet["westeurope-dev-app"]' "/subscriptions/BLAHBLAH/providers/Microsoft.Network/virtualNetworks/westeurope-vnet/subnets/westeurope-dev-app"
- Edit state file with your favourite vi flavour and change from list to map. Is this correct?
We would like to script a solution to be able to migrate all our networks but we would appreciate some official confirmation from Hashicorp to be sure we are not fixing something and breaking another.