hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.53k stars 4.6k forks source link

azurerm_function_app Unclear request to replace resource from PLAN output #9315

Closed mcalnd70 closed 3 years ago

mcalnd70 commented 3 years ago

Community Note

Terraform (and AzureRM Provider) Version

Terraform 0.12.20 (also tried 0.13.5 to attempt to fix) AzureRM Provider 2.16.0 (also tried 2.36.0 to attempt to fix)

Affected Resource(s)

Terraform Configuration Files

terraform {
}

provider "azurerm" {
  version = "=2.16.0"
  features {}  
}

# Define Resource Group for Function Apps
resource "azurerm_resource_group" "go-1" {
  name     = "MyResourceGroup"
  location = "westeurope"

  tags = {
    Environment = "Sandbox"
    Creator = "MyCreatorTag"
    Owner = "MyDepartment"
  }
}
# Define Storage Account
resource "azurerm_storage_account" "go-1" {
  name                     = "mystorageaccountunique"
  resource_group_name      = azurerm_resource_group.go-1.name
  location                 = azurerm_resource_group.go-1.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  access_tier              = "Hot"
  account_kind             = "StorageV2"
  enable_https_traffic_only = true

 tags = {
    Environment = azurerm_resource_group.go-1.tags.Environment
    Creator = azurerm_resource_group.go-1.tags.Creator
    Owner = azurerm_resource_group.go-1.tags.Owner
  }
}
# Define App Service Plan 1
resource "azurerm_app_service_plan" "go-1" {
  name                = "MyAppPlan"
  location            = azurerm_resource_group.go-1.location
  resource_group_name = azurerm_resource_group.go-1.name
  kind                = "Windows"
  sku {
    tier = "Basic"
    size = "B1"
  }
  tags = {
    Environment = azurerm_resource_group.go-1.tags.Environment
    Creator = azurerm_resource_group.go-1.tags.Creator
    Owner = azurerm_resource_group.go-1.tags.Owner
  }
}
# Define Function App 1
resource "azurerm_function_app" "go-1" {
  name                      = "MyFunctionApp"
  location                  = azurerm_resource_group.go-1.location
  resource_group_name       = azurerm_resource_group.go-1.name
  app_service_plan_id       = azurerm_app_service_plan.go-1.id
  storage_connection_string = azurerm_storage_account.go-1.primary_connection_string
  version                   = "~2"
  identity {
      type = "SystemAssigned"   
  }  
  app_settings = {
        WEBSITE_ENABLE_SYNC_UPDATE_SITE = "SetByFACodeReleasePipeline"
        WEBSITE_RUN_FROM_PACKAGE = "SetByFACodeReleasePipeline"
  }
  site_config {
    use_32_bit_worker_process = "true"
    always_on = "true"
  }
  lifecycle {
     ignore_changes = [
        app_settings["WEBSITE_ENABLE_SYNC_UPDATE_SITE"],
        app_settings["WEBSITE_RUN_FROM_PACKAGE"]
     ]
  }
}

Debug Output

Panic Output

Expected Behaviour

Plan reports No changes. Infrastructure is up-to-date. as nothing has changed versus the state file

Actual Behaviour

Plan reports that the Function App must be replaced - but the reason given that forces this replacement is unclear. As far as I can see the (a) the resource exists in Azure correctly (b) the state is saved correctly.

I have run the following commands to remove the state and re-import...

  1. terraform state rm azurerm_function_app.go-1
  2. terraform import azurerm_function_app.go-1 /subscriptions/00000000-0000-0000-0000-00000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Web/sites/MyFunctionApp

...however the PLAN output still demands azurerm_function_app.go-1 must be replaced. It's not exactly clear what is forcing this replacement demand, having checked out the running Function App in Azure, the Azure Resource Manager site, the contents of the state file (before and after, and when doing the re-import into the statefile

Of note: the following items are marked as - red in the PLAN output...

- daily_memory_time_quota        = 0 -> null

- {
    - password = "myblankedoutpasswordforsite"
    - username = "$MyFunctionApp"
  },

- tags                           = {} -> null

- identity_ids = [] -> null

- pre_warmed_instance_count = 0 -> null
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

azurerm_resource_group.go-1: Refreshing state... [id=/subscriptions/00000000-0000-0000-0000-00000000000/resourceGroups/MyResourceGroup]
azurerm_app_service_plan.go-1: Refreshing state... [id=/subscriptions/00000000-0000-0000-0000-00000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Web/serverfarms/MyAppPlan]
azurerm_storage_account.go-1: Refreshing state... [id=/subscriptions/00000000-0000-0000-0000-00000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Storage/storageAccounts/mystorageaccountunique]
azurerm_function_app.go-1: Refreshing state... [id=/subscriptions/00000000-0000-0000-0000-00000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Web/sites/MyFunctionApp]

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # azurerm_function_app.go-1 must be replaced
-/+ resource "azurerm_function_app" "go-1" {
        app_service_plan_id            = "/subscriptions/00000000-0000-0000-0000-00000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Web/serverfarms/MyAppPlan"
      ~ app_settings                   = {
          ~ "WEBSITE_ENABLE_SYNC_UPDATE_SITE"        = "true" -> "SetByFACodeReleasePipeline"
          ~ "WEBSITE_RUN_FROM_PACKAGE"               = "1" -> "SetByFACodeReleasePipeline"
        }
      ~ client_affinity_enabled        = false -> (known after apply)
      - daily_memory_time_quota        = 0 -> null
      ~ default_hostname               = "MyFunctionApp.azurewebsites.net" -> (known after apply)
        enable_builtin_logging         = true
        enabled                        = true
        https_only                     = false
      ~ id                             = "/subscriptions/00000000-0000-0000-0000-00000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Web/sites/MyFunctionApp" -> (known after apply)
      ~ kind                           = "functionapp" -> (known after apply)
        location                       = "westeurope"
        name                           = "MyFunctionApp"
      ~ outbound_ip_addresses          = "1.2.3.4,5.6.7.8" -> (known after apply)
      ~ possible_outbound_ip_addresses = "1.2.3.4,5.6.7.8" -> (known after apply)
        resource_group_name            = "MyResourceGroup"
      ~ site_credential                = [
          - {
              - password = "myblankedoutpasswordforsite"
              - username = "$MyFunctionApp"
            },
        ] -> (known after apply)
      ~ storage_account_access_key     = (sensitive value)
      ~ storage_account_name           = "mystorageaccountunique" -> (known after apply)
      ~ storage_connection_string      = (sensitive value)
      - tags                           = {} -> null
        version                        = "~2"

      ~ auth_settings {
          ~ additional_login_params        = {} -> (known after apply)
          ~ allowed_external_redirect_urls = [] -> (known after apply)
          + default_provider               = (known after apply)
          ~ enabled                        = false -> (known after apply)
          + issuer                         = (known after apply)
          + runtime_version                = (known after apply)
          ~ token_refresh_extension_hours  = 0 -> (known after apply)
          ~ token_store_enabled            = false -> (known after apply)
          + unauthenticated_client_action  = (known after apply)

          + active_directory {
              + allowed_audiences = (known after apply)
              + client_id         = (known after apply)
              + client_secret     = (sensitive value)
            }

          + facebook {
              + app_id       = (known after apply)
              + app_secret   = (sensitive value)
              + oauth_scopes = (known after apply)
            }

          + google {
              + client_id     = (known after apply)
              + client_secret = (sensitive value)
              + oauth_scopes  = (known after apply)
            }

          + microsoft {
              + client_id     = (known after apply)
              + client_secret = (sensitive value)
              + oauth_scopes  = (known after apply)
            }

          + twitter {
              + consumer_key    = (known after apply)
              + consumer_secret = (sensitive value)
            }
        }

      + connection_string {
          + name  = (known after apply)
          + type  = (known after apply)
          + value = (sensitive value)
        }

      ~ identity {
          - identity_ids = [] -> null
          ~ principal_id = "00000000-0000-0000-0000-00000000000" -> (known after apply)
          ~ tenant_id    = "00000000-0000-0000-0000-00000000000" -> (known after apply)
            type         = "SystemAssigned"
        }

      ~ site_config {
            always_on                 = true
          ~ ftps_state                = "AllAllowed" -> (known after apply)
            http2_enabled             = false
          ~ ip_restriction            = [] -> (known after apply)
          + linux_fx_version          = (known after apply)
          ~ min_tls_version           = "1.2" -> (known after apply)
          - pre_warmed_instance_count = 0 -> null
            use_32_bit_worker_process = true
            websockets_enabled        = false

          ~ cors {
              ~ allowed_origins     = [] -> (known after apply)
              ~ support_credentials = false -> (known after apply)
            }
        }
    }

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

Steps to Reproduce

  1. terraform init
  2. terraform plan

Important Factoids

West Europe region of Azure - Function Apps have been running for around 1 year. I'm unsure if this is a Terraform issue, or an Azure API or Resource Manager backend issue, but so far I have been unable to understand what the exact issue is.

References

mcalnd70 commented 3 years ago

I've done a lot of RCA on this and I believe I have discovered the reason. I'm working through the post mortem of it now. Please don't assign this to anyone, I'll endeavour to post back some findings for the community in due course.

mcalnd70 commented 3 years ago

This can now be closed - I eventually found the issue via a lot of trial and error. The appsetting "AzureWebJobsStorage" was changed via a FA code CI/CD pipeline to become a Key Vault Reference object. This conflicted with the Terraform main.tf's definition of "storage_connection_string", no a KV Reference Object.

ghost commented 3 years ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 hashibot-feedback@hashicorp.com. Thanks!