Terraform-provider-azurerm: Function app unexpected update in place

Created on 22 Sep 2018  路  9Comments  路  Source: terraform-providers/terraform-provider-azurerm

Hello folks!

I am always receiving the following when make-planning my function app:

~ module.scrutinizer_lambda.azurerm_function_app.lambda_app
      app_settings.%:                           "7" => "8"
      app_settings.FUNCTIONS_EXTENSION_VERSION: "" => "beta"

sometimes it's this:

~ module.commit_event_lambda.azurerm_function_app.lambda_app
      app_settings.%:                           "10" => "11"
      app_settings.FUNCTIONS_EXTENSION_VERSION: "" => "beta"

I would not know what that can mean but it always modifies something.

Terraform Version

Terraform v0.11.8
+ provider.azurerm v1.15.0

Affected Resource(s)

  • azurerm_function_app

Terraform Configuration Files

resource "azurerm_function_app" "lambda_app" {
  name                      = "${local.full_prefix}-app"
  location                  = "${var.location}"
  resource_group_name       = "${var.resource_group_name}"
  app_service_plan_id       = "${var.service_plan_id}"
  storage_connection_string = "${var.storage_connection_string}"

  https_only = "true"
  version    = "beta"

  # https://stackoverflow.com/questions/49842499/deploy-azure-function-using-terraform
  app_settings = "${merge(
    var.lambda_variables,
    map(
      "FUNCTIONS_EXTENSION_VERSION",        "beta",
      "WEBSITE_NODE_DEFAULT_VERSION",       "10.6.0",
      "HASH",                               "${base64sha256(file(var.artifact_path))}",
      "WEBSITE_RUN_FROM_ZIP",               "${azurerm_storage_blob.artifact_blob.url}${var.storage_sas}",
      "AZURE_STORAGE_CONNECTION_STRING",    "${var.storage_connection_string}"
      )
  )}"

  tags = "${local.tags}"
}

Expected Behavior

It should not touch any resource.

Actual Behavior

It always reports an update in-place.

Steps to Reproduce

  1. terraform plan
bug servicfunctions

Most helpful comment

This trick behavior has been changed in Terraform 0.12 and is documented here
https://www.terraform.io/docs/configuration/resources.html#lifecycle-lifecycle-customizations

You have to create a fake value to avoid any creation/destroy change.

You can also ignore specific map elements by writing references like tags["Name"] in the ignore_changes list, though with an important caveat: the ignoring applies only to in-place updates to an existing key. Adding or removing a key is treated by Terraform as a change to the containing map itself rather than to the individual key, and so if you wish to ignore changes to a particular tag made by an external system you must ensure that the Terraform configuration creates a placeholder element for that tag name so that the external system changes will be understood as an in-place edit of that key:

resource "aws_instance" "example" {
  # ...

  tags = {
    # Initial value for Name is overridden by our automatic scheduled
    # re-tagging process; changes to this are ignored by ignore_changes
    # below.
    Name = "placeholder"
  }

  lifecycle {
    ignore_changes = [
      tags["Name"],
    ]
  }
}

All 9 comments

@arichiardi I am not 100% sure but I think when using WEBSITE_RUN_FROM_ZIP the work behind the scenes (kudu) adds/removes items from app settings.

You can using ignore_changes

resource "azurerm_function_app" "lambda_app" {
  name                      = "${local.full_prefix}-app"
  location                  = "${var.location}"
  resource_group_name       = "${var.resource_group_name}"
  app_service_plan_id       = "${var.service_plan_id}"
  storage_connection_string = "${var.storage_connection_string}"

  https_only = "true"
  version    = "beta"

  # https://stackoverflow.com/questions/49842499/deploy-azure-function-using-terraform
  app_settings = "${merge(
    var.lambda_variables,
    map(
      "FUNCTIONS_EXTENSION_VERSION",        "beta",
      "WEBSITE_NODE_DEFAULT_VERSION",       "10.6.0",
      "HASH",                               "${base64sha256(file(var.artifact_path))}",
      "WEBSITE_RUN_FROM_ZIP",               "${azurerm_storage_blob.artifact_blob.url}${var.storage_sas}",
      "AZURE_STORAGE_CONNECTION_STRING",    "${var.storage_connection_string}"
      )
  )}"

  tags = "${local.tags}"

  lifecycle {
      ignore_changes = [
         "app_settings.KEYNAME",
     ]
  }
}

You may have to play with it a bit, to get the correct property.

looks like they updated the variable name to WEBSITE_RUN_FROM_PACKAGE

Updated, missed lifecycle block.

Thanks a lot for the answer, not at the keyboard but I will definitely work around that by adding the ignore_changes line.

@arichiardi
FWIW: This what we needed to ignore because of the Azure Pipeline Release deployment step:

lifecycle {
    ignore_changes = [
      "app_settings.%",
      "app_settings.MSDEPLOY_RENAME_LOCKED_FILES",
      "site_config.0.scm_type",
    ]
  }

For more details on lifecycle

I did the above, it works, but I needed to add:

app_settings.FUNCTIONS_EXTENSION_VERSION

Hi,

I tried in my case to use ignore settings in differents ways, but never works :(
Here some ways that I used (I'm in TF 12.5)

way 1 ->

    lifecycle {
      ignore_changes = [
        "app_settings.FUNCTIONS_EXTENSION_VERSION",
      ]
    }

way 2 ->

    lifecycle {
      ignore_changes = [
        app_settings.FUNCTIONS_EXTENSION_VERSION,
      ]
    }

way 3 ->

    lifecycle {
      ignore_changes = [
        app_settings.["FUNCTIONS_EXTENSION_VERSION"],
      ]
    }

etc... everytime, I've TF who want update this settings.
Someone can say me the correct syntax that I need please ?

Thanks
Regards
Alexandre

Hi,
When i try this :
image

Result :
image

Impossible to ignore both parameters !
Someone Help

This trick behavior has been changed in Terraform 0.12 and is documented here
https://www.terraform.io/docs/configuration/resources.html#lifecycle-lifecycle-customizations

You have to create a fake value to avoid any creation/destroy change.

You can also ignore specific map elements by writing references like tags["Name"] in the ignore_changes list, though with an important caveat: the ignoring applies only to in-place updates to an existing key. Adding or removing a key is treated by Terraform as a change to the containing map itself rather than to the individual key, and so if you wish to ignore changes to a particular tag made by an external system you must ensure that the Terraform configuration creates a placeholder element for that tag name so that the external system changes will be understood as an in-place edit of that key:

resource "aws_instance" "example" {
  # ...

  tags = {
    # Initial value for Name is overridden by our automatic scheduled
    # re-tagging process; changes to this are ignored by ignore_changes
    # below.
    Name = "placeholder"
  }

  lifecycle {
    ignore_changes = [
      tags["Name"],
    ]
  }
}

For those having problems with this you need to add a placeholder too. Check this thread.

This is what worked for me:

resource "azurerm_function_app" "maibeer" {
  name                       = local.env.func_app_name
  location                   = local.env.location
  resource_group_name        = local.env.resource_group_name
  app_service_plan_id        = azurerm_app_service_plan.default.id
  storage_account_name       = azurerm_storage_account.default.name
  storage_account_access_key = azurerm_storage_account.default.primary_access_key
  os_type                    = "linux"
  version                    = "~3"

  app_settings = {
    "FUNCTIONS_WORKER_RUNTIME"              = "python"
    "MAIBEER_COSMOSDB_CONNECTION_STRING"    = azurerm_cosmosdb_account.default.connection_strings[0]
    "MAIBEER_KEYVAULT_URI"                  = azurerm_key_vault.default.vault_uri
    "APPINSIGHTS_INSTRUMENTATIONKEY"        = azurerm_application_insights.maibeer.instrumentation_key
    "WEBSITE_RUN_FROM_PACKAGE"              = "ThisWillBeSetToAnURLByAzureDevOpsDeploy", // managed by Azure DevOps (must be not null)
    "WEBSITE_ENABLE_SYNC_UPDATE_SITE"       = "true"           // managed by Azure DevOps (must be not null)
  }

  site_config {
    # only for free plan
    use_32_bit_worker_process = local.env.func_use_32_bit_worker_process
  }

  identity {
    type                      = "SystemAssigned"
  }

  lifecycle {
    ignore_changes = [ 
      app_settings["WEBSITE_RUN_FROM_PACKAGE"],
      app_settings["WEBSITE_ENABLE_SYNC_UPDATE_SITE"]
    ] 
  }

  tags = local.tags

}

It looks like this functionality will be added to 0.14: https://github.com/hashicorp/terraform/pull/26421

Was this page helpful?
0 / 5 - 0 ratings