How to migrate from azurerm_static_site to azurerm_static_web_app without destroying existing resources

According to this site: azurerm_static_site | Resources | hashicorp/azurerm | Terraform | Terraform Registry
azurerm_static_site will be deprecated in the future in favour of azurerm_static_web_app.

We want to migrate to the new resource without destroying our existing apps. I tried to use a moved block, however that will not work because move between different resource types is not support.

It would be nice if there was a kind of upgrade path to smooth migrate to the new resource type without the need of destroy our running apps. Anyone any suggestion?

1 Like

Running into something similar. Following for updates.

Both AzureRM provider resources are Azure /Microsoft.Web/staticSites so adding a new resource block to your config for azurerm_static_web_app will result in:

│ Error: A resource with the ID "/{redacted}/resourceGroups/better-hen/providers/Microsoft.Web/staticSites/better-hen" already exists - to be managed via Terraform this resource needs to be imported into the State. Please see the resource documentation for "azurerm_static_web_app" for more information.

While not automated, the following workflows should result in migrating from the AzureRM provider azurerm_static_siteazurerm_static_web_app resource.

  1. Add new azurerm_static_web_app resource block to module
  2. Add import block to module
    2.1 Optionally use terraform plan --generate-config-out to create full populated resource block config and update module
  3. Import existing resource into azurerm_static_web_app
  4. Remove azurerm_static_site resource from module AND from terraform state (terraform state rm ....)
  5. Run plan/apply to verify your infrastructure matches the configuration

Note: There is a risk here that you may inadvertently destroy existing resources so take care and double check everything, all messages and test in a non-production environment.


What is an interesting point is that Terraform allows two resources in the state with the same Azure Resource ID. So given the following module:

resource "random_pet" "name" {` 

resource "azurerm_resource_group" "example" {
  name     =
  location = "West Europe"

resource "azurerm_static_site" "example" {
  name                =
  resource_group_name =
  location            = azurerm_resource_group.example.location

resource "azurerm_static_web_app" "example" {
  name                =
  resource_group_name =
  location            = azurerm_resource_group.example.location

import {
  to = azurerm_static_web_app.example
  id = "/subscriptions/{redacted}/resourceGroups/better-hen/providers/Microsoft.Web/staticSites/better-hen"

Running a terraform plan provides:

Terraform will perform the following actions:

  # azurerm_static_web_app.example will be imported
    resource "azurerm_static_web_app" "example" {
        api_key                            = (sensitive value)
        app_settings                       = {}
        configuration_file_changes_enabled = true
        default_host_name                  = ""
        id                                 = "/subscriptions/{redacted}/resourceGroups/better-hen/providers/Microsoft.Web/staticSites/better-hen" 
        location                           = "westeurope"
        name                               = "better-hen"
        preview_environments_enabled       = true
        resource_group_name                = "better-hen"
        sku_size                           = "Free"
        sku_tier                           = "Free"
        tags                               = {}

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.

And actually doing the apply results in the following:

Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.

With the following in state:

> terraform state list
azurerm_resource_group.example <--
azurerm_static_web_app.example <--

> terraform state show azurerm_static_site.example
# azurerm_static_site.example:
resource "azurerm_static_site" "example" {
    default_host_name   = ""
    id                  = "/subscriptions/{redacted}/resourceGroups/better-hen/providers/Microsoft.Web/staticSites/better-hen"

> terraform state show azurerm_static_web_app.example
# azurerm_static_web_app.example:
resource "azurerm_static_web_app" "example" {
    default_host_name  = ""
    id                 = "/subscriptions/{redacted}/resourceGroups/better-hen/providers/Microsoft.Web/staticSites/better-hen"     

Note the resource ID for both Terraform resources is the same.

At this point the azurerm_static_site resource in the module and the state should be removed.
If only remove the azurerm_static_site in the module and plan-apply then your Azure resource will be destroyed - which you do not want:

  # azurerm_static_site.example will be destroyed
  # (because azurerm_static_site.example is not in configuration)
  - resource "azurerm_static_site" "example" {
      - id  = "/subscriptions/{redacted}/resourceGroups/better-hen/providers/Microsoft.Web/staticSites/better-hen" ...

Plan: 0 to add, 0 to change, 1 to destroy.

But if you remove from both module and state:

> terraform state rm azurerm_static_site.example   
Removed azurerm_static_site.example
Successfully removed 1 resource instance(s).
> terraform plan      

No changes. Your infrastructure matches the configuration.

What may be an issue is if the AzureRM resources have slightly different arguments/settings. If you do not set the new azurerm_static_web_app to match what will be extracted from Azure as part of the import process it may result in an import + change or an import + destroy/recreate

To mitigate this you could use the terraform plan --generate-config-out to generate the fully populated azurerm_static_web_app resource block to incorporate into your module before then carrying out the import.

Also bear in mind that now the terraform resource address has changed from azurerm_static_site.example

That any references to this resource in the module code will now need to be updated.


Happy Terraforming