Azurerm diagnostic setting updating when app service changes

Hey, I just posted this as a Terraform azurerm bug but it was closed as its a configuration issue instead. azurerm_monitor_diagnostic_setting updating when azurerm_app_service app_settings change - shouldn't happen!!! · Issue #14320 · hashicorp/terraform-provider-azurerm · GitHub

Community Note

  • Please vote on this issue by adding a :+1: 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
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform (and AzureRM Provider) Version

Affected Resource(s)

  • azurerm_monitor_diagnostic_setting
  • azurerm_app_service

Terraform Configuration Files

resource "azurerm_resource_group" "main" {
  name     = "${var.env}-rg"
  location = var.location
}

resource "azurerm_app_service_plan" "main" {
  name                = "${var.env}-asp"
  location            = var.location
  resource_group_name = azurerm_resource_group.main.name
  sku {
    tier = "Standard"
    size = "S1"
  }
}

resource "azurerm_app_service" "main" {  
  name                    = "${var.env}-webapp"
  location                = var.location
  resource_group_name     = azurerm_resource_group.main.name
  app_service_plan_id     = azurerm_app_service_plan.main.id

   app_settings = {
    "SOME_KEY" = random_id.main.dec
  }
}

resource "azurerm_log_analytics_workspace" "main" {
  name                = "${var.env}-law"
  location            = var.location
  resource_group_name = azurerm_resource_group.main.name
  sku                 = "PerGB2018"
  retention_in_days   = 30
}

data "azurerm_monitor_diagnostic_categories" "main" {
  resource_id = azurerm_app_service.main.id
}

resource "azurerm_monitor_diagnostic_setting" "main" { 
  name                       = "${var.env}-diags"
  target_resource_id         = azurerm_app_service.main.id
  log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id

  dynamic "log" {
    iterator = entry
    for_each = data.azurerm_monitor_diagnostic_categories.main.logs

    content {
      category = entry.value
      enabled  = true

      retention_policy {
        enabled = true
        days    = 30
      }
    }
  }

  dynamic "metric" {
    iterator = entry
    for_each = data.azurerm_monitor_diagnostic_categories.main.metrics

    content {
      category = entry.value
      enabled  = true

      retention_policy {
        enabled = true
        days    = 30
      }
    }
  }
}

resource "random_id" "main" {
  keepers = {
    first = "${timestamp()}"
  }     
  byte_length = 8
}

Expected Behaviour

Terraform just to update the value for SOME_KEY in app_settings.

Actual Behaviour

Terraform will perform the following actions:

  # data.azurerm_monitor_diagnostic_categories.main will be read during apply
  # (config refers to values not yet known)
 <= data "azurerm_monitor_diagnostic_categories" "main"  {
      ~ id          = "/subscriptions/123abc/resourceGroups/guydiagtest-rg/providers/Microsoft.Web/sites/guydiagtest-webapp" -> (known after apply)
      ~ logs        = [
          - "AppServiceAppLogs",
          - "AppServiceAuditLogs",
          - "AppServiceConsoleLogs",
          - "AppServiceHTTPLogs",
          - "AppServiceIPSecAuditLogs",
          - "AppServicePlatformLogs",
        ] -> (known after apply)
      ~ metrics     = [
          - "AllMetrics",
        ] -> (known after apply)
        # (1 unchanged attribute hidden)

      + timeouts {
          + read = (known after apply)
        }
    }

  # azurerm_app_service.main will be updated in-place
  ~ resource "azurerm_app_service" "main" {
      ~ app_settings                      = {
          - "SOME_KEY" = "13005899551313681603"
        } -> (known after apply)
        id                                = "/subscriptions/123abc/resourceGroups/guydiagtest-rg/providers/Microsoft.Web/sites/guydiagtest-webapp"
        name                              = "guydiagtest-webapp"
        tags                              = {}
        # (15 unchanged attributes hidden)




        # (4 unchanged blocks hidden)
    }

  # azurerm_monitor_diagnostic_setting.main will be updated in-place
  ~ resource "azurerm_monitor_diagnostic_setting" "main" {
        id                         = "/subscriptions/123abc/resourceGroups/guydiagtest-rg/providers/Microsoft.Web/sites/guydiagtest-webapp|guydiagtest-diags"
        name                       = "guydiagtest-diags"
        # (2 unchanged attributes hidden)

      - log {
          - category = "AppServiceAppLogs" -> null
          - enabled  = true -> null

          - retention_policy {
              - days    = 30 -> null
              - enabled = true -> null
            }
        }
      - log {
          - category = "AppServiceAuditLogs" -> null
          - enabled  = true -> null

          - retention_policy {
              - days    = 30 -> null
              - enabled = true -> null
            }
        }
      - log {
          - category = "AppServiceConsoleLogs" -> null
          - enabled  = true -> null

          - retention_policy {
              - days    = 30 -> null
              - enabled = true -> null
            }
        }
      - log {
          - category = "AppServiceHTTPLogs" -> null
          - enabled  = true -> null

          - retention_policy {
              - days    = 30 -> null
              - enabled = true -> null
            }
        }
      - log {
          - category = "AppServiceIPSecAuditLogs" -> null
          - enabled  = true -> null

          - retention_policy {
              - days    = 30 -> null
              - enabled = true -> null
            }
        }
      - log {
          - category = "AppServicePlatformLogs" -> null
          - enabled  = true -> null

          - retention_policy {
              - days    = 30 -> null
              - enabled = true -> null
            }
        }
      + log {
          + category = (known after apply)
          + enabled  = (known after apply)

          + retention_policy {
              + days    = (known after apply)
              + enabled = (known after apply)
            }
        }

      - metric {
          - category = "AllMetrics" -> null
          - enabled  = true -> null

          - retention_policy {
              - days    = 30 -> null
              - enabled = true -> null
            }
        }
      + metric {
          + category = (known after apply)
          + enabled  = (known after apply)

          + retention_policy {
              + days    = (known after apply)
              + enabled = (known after apply)
            }
        }
    }

  # random_id.main must be replaced
-/+ resource "random_id" "main" {
      ~ b64_std     = "tH48u9R23MM=" -> (known after apply)
      ~ b64_url     = "tH48u9R23MM" -> (known after apply)
      ~ dec         = "13005899551313681603" -> (known after apply)
      ~ hex         = "b47e3cbbd476dcc3" -> (known after apply)
      ~ id          = "tH48u9R23MM" -> (known after apply)
      ~ keepers     = {
          - "first" = "2021-11-24T12:08:01Z"
        } -> (known after apply) # forces replacement
        # (1 unchanged attribute hidden)
    }

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

Steps to Reproduce

  1. terraform apply
  2. terraform plan - this will show the diagnostic settings updating, even though this is not desired/required.

Important Factoids

I’ve purposely made the app_setting ‘SOME_KEY’ update each time to get this behaviour as this is where we’re seeing it in our code. It is creating LOTS of noise the plan and making actual changes harder to spot.

If we comment the random_id timestamp to stop it changing everytime, like this:

resource "random_id" "main" {
#  keepers = {
#    first = "${timestamp()}"
#  }     
  byte_length = 8
}

then run terraform apply & terraform plan, we won’t see any changes, which is great. But the noise seems to come when we’re updating the app service in some way and I don’t want to see these diagnostic settings updating (because they don’t).

If anyone knows why this is happening and/or how to workaround it, it would be much apprecaited.

Hi @guywood13! The problem here is straight-forward. As random_id is calculated upon creation ((known after apply), thus not known at the moment of the plan or apply, every subsequent resource will struggle to calculate the result of its own plan/apply as it has a dependency on something unknown.

You can fix this by providing a value which is known upon plan/apply, making this chain of updates go away iirc. Thus using a variable (which may change though, but has a known value already) or maybe even "SOME_KEY" = timestamp() (not sure) makes it already easier for Terraform to deal with the consequences of your actions.

Hi @aristosvo, I think you have the wrong end of the stick! I’m purposely updating the app_setting “SOME_KEY” on each plan/apply to highlight the issue of, at the point the app service changes, the diagnostic settings need to be updated.

I know this is because the data source for the diagnostic setting categories is dependent on the app service and if that changes, the data source wants to re-read and thus wants to change the category to (known after apply).

Think the only way round this is to either loop through a fixed list of the diagnostic logs. Or perhaps the azurerm Terraform provider will start making use of diagnostic setting log category groups (Ability to create azurerm_monitor_diagnostic_setting logs by category GROUP · Issue #14333 · hashicorp/terraform-provider-azurerm · GitHub).

I just thought somebody else might have another solution.

I know you’re doing that purposely, but the way you do it specifically triggers specific behaviour, while if you do it differently the behaviour you complaining about should be gone.