Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_linux_function_app: docker block configuration deleted after unrelated change #14702

Closed
dszakallas opened this issue Dec 21, 2021 · 9 comments

Comments

@dszakallas
Copy link

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request

Terraform (and AzureRM Provider) Version

  • Terraform Core version: 1.1.0
  • AzureRM Provider version: 2.90.0

Description / Feedback

What happens:

Whenever I change my azurerm_linux_function_app resource, the docker configuration gets deleted.

What should have happened:

The docker configuration should stay pristine.

Reproducing the issue

The resource in question is

resource "azurerm_linux_function_app" "features_mlops" {
  name                        = "features-mlops"
  resource_group_name         = data.azurerm_resource_group.azurefunctionscontainers.name
  location                    = data.azurerm_resource_group.azurefunctionscontainers.location
  service_plan_id             = azurerm_app_service_plan.features_mlops.id
  storage_account_name        = azurerm_storage_account.features_mlops.name
  storage_account_access_key  = azurerm_storage_account.features_mlops.primary_access_key
  functions_extension_version = "~4"
  builtin_logging_enabled     = false
  tags                        = var.tags

  site_config {
    always_on                                     = false
    container_registry_use_managed_identity       = true
    container_registry_managed_identity_client_id = data.azurerm_user_assigned_identity.features_mlops.client_id
    application_insights_key                      = azurerm_application_insights.features_mlops.instrumentation_key
    application_insights_connection_string        = azurerm_application_insights.features_mlops.connection_string
    application_stack {
      docker {
        registry_url = data.azurerm_container_registry.[REDACTED].login_server
        image_name   = "features/[REDACTED]_features_dataprocessing"
        image_tag    = "development"
      }
    }
  }

  identity {
    type = "UserAssigned"
    identity_ids = [
      data.azurerm_user_assigned_identity.features_mlops.id
    ]
  }

  app_settings = {
    "DOCKER_ENABLE_CI"                         = "true"
    "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" = azurerm_storage_account.features_mlops.primary_connection_string
    "WEBSITE_CONTENTSHARE"                     = "[REDACTED]"
    "WEBSITES_ENABLE_APP_SERVICE_STORAGE"      = "false"
    "AzureWebJobsStorage__blobServiceUri"  = azurerm_storage_account.features_mlops.primary_blob_endpoint
    "AzureWebJobsStorage__queueServiceUri" = azurerm_storage_account.features_mlops.primary_queue_endpoint
    "AzureWebJobsStorage__credential"      = "managedidentity"
    "AzureWebJobsStorage__clientId"        = data.azurerm_user_assigned_identity.features_mlops.client_id
  }
}

I get the following plan and execute it.

$ terraform plan -out plan

[REDACTED]

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_linux_function_app.features_mlops will be updated in-place
  ~ resource "azurerm_linux_function_app" "features_mlops" {
      ~ app_settings                      = {
          + "AzureWebJobsStorage__blobServiceUri"      = "https://[REDACTED]featuresmlops.blob.core.windows.net/"
          + "AzureWebJobsStorage__clientId"            = "[REDACTED]"
          + "AzureWebJobsStorage__credential"          = "managedidentity"
          + "AzureWebJobsStorage__queueServiceUri"     = "https://[REDACTED]featuresmlops.queue.core.windows.net/"
          + "WEBSITES_ENABLE_APP_SERVICE_STORAGE"      = "false"
          + "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" = (sensitive)
          + "WEBSITE_CONTENTSHARE"                     = "[REDACTED]"
            # (6 unchanged elements hidden)
        }
        id                                = "/subscriptions/[REDACTED]/resourceGroups/[REDACTED]/providers/Microsoft.Web/sites/features-mlops"
        name                              = "features-mlops"
        tags                              = {
            "[REDACTED]:owner" = "features"
            "[REDACTED]:team"  = "features"
        }
        # (22 unchanged attributes hidden)



        # (3 unchanged blocks hidden)
    }

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

────────────────────────────────────────────────────────────────────────────────────────────────────────

Saved the plan to: plan

To perform exactly these actions, run the following command to apply:
    terraform apply "plan"

$ terraform apply plan
azurerm_linux_function_app.features_mlops: Modifying... [id=/subscriptions/[REDACTED]/resourceGroups/[REDACTED]/providers/Microsoft.Web/sites/features-mlops]
[REDACTED]
azurerm_linux_function_app.features_mlops: Modifications complete after 45s [id=/subscriptions/[REDACTED]/resourceGroups/[REDACTED]/providers/Microsoft.Web/sites/features-mlops]

However when running plan the second time:

$terraform plan -out plan
Acquiring state lock. This may take a few moments...

[REDACTED]

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_linux_function_app.features_mlops will be updated in-place
  ~ resource "azurerm_linux_function_app" "features_mlops" {
      ~ app_settings                      = {
          + "WEBSITES_ENABLE_APP_SERVICE_STORAGE"      = "false"
          + "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" = (sensitive)
          + "WEBSITE_CONTENTSHARE"                     = "features-mlops-8b11"
            # (10 unchanged elements hidden)
        }
        id                                = "/subscriptions/[REDACTED]/resourceGroups/[REDACTED]/providers/Microsoft.Web/sites/features-mlops"
        name                              = "features-mlops"
        tags                              = {
            "[REDACTED]:owner" = "features"
            "[REDACTED]:team"  = "features"
        }
        # (22 unchanged attributes hidden)



      ~ site_config {
            # (33 unchanged attributes hidden)

          + application_stack {
              + docker {
                  + image_name   = "features/[REDACTED]_features_dataprocessing"
                  + image_tag    = "development"
                  + registry_url = "[REDACTED].azurecr.io"
                }
            }

            # (1 unchanged block hidden)
        }
        # (2 unchanged blocks hidden)
    }

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

────────────────────────────────────────────────────────────────────────────────────────────────────────

Saved the plan to: plan

To perform exactly these actions, run the following command to apply:
    terraform apply "plan"

There are two issues here:

  1. The WEBSITE_ and WEBSITES_ app settings appear as an addition.
  2. The docker block appears as an addition.

I see (1.) as an annoyance, as the env vars are actually there in the environment, so this bug doesn't cause issues. Maybe they get filtered out when Terraform queries the resource?

However (2.) is actually removed, and the Function App stops working. I have to reapply the plan to get the docker configuration back.

@jackofallops
Copy link
Member

Hi @dszakallas - Thanks for opening this issue, and for valuable feedback on the beta resource! It's very much appreciated.

I've reproduced, and have a fix for, the [WEBSITE_|WEBSITES_] part of this issue but I'm struggling to get the application_stack.docker block to disappear. It doesn't appear from the output that Terraform is responsible for the removal? Is it possible something else was acting on the resource?

@dszakallas
Copy link
Author

Hi @jackofallops. Thanks for your reply. Nothing else acts on the resource, the removal of the docker configuration is in effect right after applying the plan. I am not 100% sure on this but it seems that these two issues appear together. I couldn't reproduce a disappearing docker block without a WEBSITE_ addition. On a related note, the WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE flags seem to be autoconfigured (i.e when I create a resource, these are automatically created), so I wonder if it makes sense to include them in the resource at all.

@jackofallops
Copy link
Member

Hi @dszakallas - As ever, "it depends". Depending on the use case for the app, they may be required to be set manually. The provider accounts for the cases where they are required but not specified by generating the values (and subsequently filtering them out for the state, which is the source of the problem I've now addressed in #14815 ) However, there are cases where these need to be specified manually, such as when using a storage account that has additional restrictions/policies on it that would prevent Terraform retrieving the data required to populate these settings. If you're happy/willing to try this configuration again after the changes in 14815 are merged and released, could you feed back here with the outcome?

NB: I saw from your config you were using the older azurerm_app_service_plan, was there a reason you didn't use the beta replacement? (azurerm_service_plan) - Just looking for as much feedback on the beta resources as I can get 😅

@dszakallas
Copy link
Author

Yes, I am happy to give feedback on #14815. The reason for not using azurerm_service_plan is that I wasn't aware of it until now. Thanks, I'll try out. :)

@chris-hibberd
Copy link

chris-hibberd commented Apr 12, 2022

I think we're seeing the same issue as point 2, above, across our function apps. Each time we apply a plan that contains a azurerm_linux_function_app resource, the linux_fx_version is cleared in the state and the deployed resource. Re-applying the same configuration results in the linux_fx_version being reset correctly.

For example, this plan was generated by Terraform (v1.0.0, azurerm v3.0.2) despite there being no change to the Terraform configuration:

  # module.hub-data-etl-functionapp.azurerm_linux_function_app.functionapp will be updated in-place
  ~ resource "azurerm_linux_function_app" "functionapp" {
      ~ app_settings                      = {
          + "APPINSIGHTS_INSTRUMENTATIONKEY" = (sensitive)
            # (6 unchanged elements hidden)
        }
        id                                = "/subscriptions/***/resourceGroups/dev-core-infrastructure-rg/providers/Microsoft.Web/sites/dev-etl-func"
        name                              = "dev-etl-func"
        tags                              = {}
        # (24 unchanged attributes hidden)



      ~ site_config {
          - application_insights_key                = (sensitive value)
            # (25 unchanged attributes hidden)

            # (1 unchanged block hidden)
        }
        # (2 unchanged blocks hidden)
    }

When it was applied, the linux_fx_version string in the state and the Function App changed from "PYTHON|3.8" to an empty string. Re-planning exactly the same configuration then generated this plan:

  # module.hub-data-etl-functionapp.azurerm_linux_function_app.functionapp will be updated in-place
  ~ resource "azurerm_linux_function_app" "functionapp" {
      ~ app_settings                      = {
          + "APPINSIGHTS_INSTRUMENTATIONKEY" = (sensitive)
            # (6 unchanged elements hidden)
        }
        id                                = "/subscriptions/***/resourceGroups/dev-core-infrastructure-rg/providers/Microsoft.Web/sites/dev-etl-func"
        name                              = "dev-etl-func"
      ~ tags                              = {
          - "hidden-link: /app-insights-instrumentation-key" = <KEY MANUALLY REMOVED FOR THIS POST> -> null
          - "hidden-link: /app-insights-resource-id"         = "/subscriptions/***/resourceGroups/dev-core-infrastructure-rg/providers/microsoft.insights/components/dev-monitor-appi" -> null
        }
        # (24 unchanged attributes hidden)



      ~ site_config {
          - application_insights_key                = (sensitive value)
            # (24 unchanged attributes hidden)

          + application_stack {
              + python_version              = "3.8"
              + use_dotnet_isolated_runtime = false
            }
        }
        # (2 unchanged blocks hidden)
    }

When it was applied, the linux_fx_version string in the state and the Function App changed back to "PYTHON|3.8".

The resource is configured as follows:

resource "azurerm_service_plan" "functionapp-service-plan" {
  name                = join("-", [var.env, var.component, "plan"])
  resource_group_name = azurerm_resource_group.functionapp-resource-group.name
  location            = var.resource_group_location
  os_type             = "Linux"
  sku_name            = "Y1"
}

resource "azurerm_linux_function_app" "functionapp" {
  name                        = join("-", [var.env, var.component, "func"])
  resource_group_name         = var.resource_group_name
  location                    = var.resource_group_location
  service_plan_id             = azurerm_service_plan.functionapp-service-plan.id
  storage_account_name        = azurerm_storage_account.functionapp-storage-account.name
  storage_account_access_key  = azurerm_storage_account.functionapp-storage-account.primary_access_key
  functions_extension_version = "~3"
  daily_memory_time_quota     = 1000


  site_config {
    application_stack {
      python_version = "3.8"
    }
    use_32_bit_worker = false
  }

  identity {
    type = "SystemAssigned"
  }

  app_settings = merge(
    {
      https_only               = true
      WEBSITE_RUN_FROM_PACKAGE = "https://${azurerm_storage_account.functionapp-storage-account.name}.blob.core.windows.net/${azurerm_storage_container.deployments.name}/${azurerm_storage_blob.appcode.name}${data.azurerm_storage_account_sas.sas.sas}"
    }, var.function_app_env
  )
}

This implication of this is that every time we deploy any infrastructure changes, we have to apply them twice, and our Function Apps are broken between the two applies. This is a new issue since we upgraded to v3 of azurerm.

@chris-hibberd
Copy link

I've bumped the azurerm provider to version 3.1.0 and moved our application insights key from being set directly as APPINSIGHTS_INSTRUMENTATIONKEY in the app_settings attribute to being passed in via the site_config.application_insights_key attribute. I no longer see the issue I described here and can redeploy the function apps without losing any configuration.

@elliotchaim
Copy link

I'm also experiencing this issue. It seems to happen every time I change the value of app_settings

@jackofallops
Copy link
Member

I believe this to have been resolved by #16442 (I can't reproduce on v3.3.0 or later), so I'm going to close this for now. If this is still an issue, we can re-open.

Thanks!

@github-actions
Copy link

github-actions bot commented Jun 4, 2022

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 have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants