terraformazure-functionsterraform-provider-azuresubnetvnet

Terraform keeps removing virtual_network_subnet_id and in a subsequent run re-adding the vnet integration for an azurerm_linux_function_app


I've created a terraform script with an azurerm_linux_function_app with vnet integration (using azurerm_app_service_virtual_network_swift_connection). If I run the Terraform script everything works as expected, but if I run Terraform again it proposes to update the function app in-place by removing the virtual_network_subnet_id, which then breaks the vnet integration. If I run terraform again it proposes to create azurerm_app_service_virtual_network_swift_connection again and everything works and this loop continues.

resource "azurerm_subnet" "this" {
  name                 = "name"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.5.128/26"]
  service_endpoints    = ["Microsoft.AzureCosmosDB"]
  delegation {
    name = "name-delegation"

    service_delegation {
      name    = "Microsoft.Web/serverFarms"
      actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
    }
  }
}

resource "azurerm_linux_function_app" "this" {
  name                       = "name"
  resource_group_name        = azurerm_resource_group.rg.name
  location                   = azurerm_resource_group.rg.location
  storage_account_name       = azurerm_storage_account.this.name
  storage_account_access_key = azurerm_storage_account.this.primary_access_key
  service_plan_id            = azurerm_service_plan.this.id
  https_only                 = true
  site_config {
    vnet_route_all_enabled = true
    cors {
      allowed_origins = ["https://portal.azure.com"]
    }
    application_stack {
      node_version = "18"
    }
  }
  app_settings = {
  }
  depends_on = [azurerm_cosmosdb_account.db]
}

resource "azurerm_app_service_virtual_network_swift_connection" "this" {
  app_service_id = azurerm_linux_function_app.this.id
  subnet_id      = azurerm_subnet.this.id
}

Solution

  • Glad the problem was solved As a workaround instead of removing swift connection

    You can make use of lifecycle block as mentioned in this SO thread in your terraform code to avoid your swift connection from updating again, Refer below:-

    My Terraform code:-

    I have referred the below terraform code from this Official Terraform document and modified the code by adding Depends on and lifecycle block.

    
    # We strongly recommend using the required_providers block to set the
    # Azure Provider source and version being used
    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "=3.58.0"
        }
      }
    }
    
    # Configure the Microsoft Azure Provider
    provider "azurerm" {
      
    subscription_id = "subid"
    tenant_id = "tenantid"
    client_id = "clientid"
    client_secret = "clientsecret"
    features {
      resource_group {
        prevent_deletion_if_contains_resources = false
      }
    }
    
    }
    
    resource "azurerm_resource_group" "example" {
      name     = "example-resources"
      location = "West Europe"
    }
    
    resource "azurerm_virtual_network" "example" {
      name                = "example-virtual-network"
      address_space       = ["10.0.0.0/16"]
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
      depends_on = [ azurerm_resource_group.example ]
    }
    
    resource "azurerm_subnet" "example" {
      name                 = "example-subnet"
      resource_group_name  = azurerm_resource_group.example.name
      virtual_network_name = azurerm_virtual_network.example.name
      address_prefixes     = ["10.0.1.0/24"]
      
    
      delegation {
        name = "example-delegation"
    
        service_delegation {
          name    = "Microsoft.Web/serverFarms"
          actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
        }
      }
      depends_on = [ azurerm_virtual_network.example ]
    }
    
    resource "azurerm_app_service_plan" "example" {
      name                = "example-app-service-plan"
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
      depends_on = [ azurerm_resource_group.example ]
    
      sku {
        tier = "Standard"
        size = "S1"
      }
    }
    
    resource "azurerm_storage_account" "example" {
      name                     = "siliconstrg54332"
      resource_group_name      = azurerm_resource_group.example.name
      location                 = azurerm_resource_group.example.location
      account_tier             = "Standard"
      account_replication_type = "LRS"
      depends_on = [ azurerm_resource_group.example ]
    }
    
    resource "azurerm_function_app" "example" {
      name                       = "siliconfunc-0987"
      location                   = azurerm_resource_group.example.location
      resource_group_name        = azurerm_resource_group.example.name
      app_service_plan_id        = azurerm_app_service_plan.example.id
      storage_account_name       = azurerm_storage_account.example.name
      storage_account_access_key = azurerm_storage_account.example.primary_access_key
      depends_on = [azurerm_app_service_plan.example]
    }
    resource "azurerm_app_service_virtual_network_swift_connection" "this" {
      app_service_id = azurerm_function_app.example.id
      subnet_id      = azurerm_subnet.example.id
    
    depends_on = [azurerm_subnet.example, azurerm_function_app.example]
      lifecycle {
        ignore_changes = [
          subnet_id,
        ]
      }
    }
    

    lifecycle block:-

    resource "azurerm_app_service_virtual_network_swift_connection" "this" {
      app_service_id = azurerm_function_app.example.id
      subnet_id      = azurerm_subnet.example.id
    
    depends_on = [azurerm_subnet.example, azurerm_function_app.example]
      lifecycle {
        ignore_changes = [
          subnet_id,
        ]
      }
    }
    

    Output:-

    enter image description here

    enter image description here

    When I ran the Plan again it did not ask me to update Swift connection or Function app except for asking me to add the tag as cost center refer below:-

    enter image description here

    You can add the tags by adding this

    tags = { costCenter = "My Cost Center" } 
    

    in your resource block after tadding this in my resource block when I ran the plan I got the desired state refer below:-

    enter image description here

    Complete code with tag referred from this Official Terraform Document modified with Depends on and lifecycle block.

    # We strongly recommend using the required_providers block to set the
    # Azure Provider source and version being used
    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "=3.58.0"
        }
      }
    }
    
    # Configure the Microsoft Azure Provider
    provider "azurerm" {
      
    subscription_id = "subid"
    tenant_id = "tenantid"
    client_id = "clientid"
    client_secret = "clientsecret"
    features {
      resource_group {
        prevent_deletion_if_contains_resources = false
      }
    }
    
    }
    
    resource "azurerm_resource_group" "example" {
      name     = "example-resources"
      location = "West Europe"
    }
    
    resource "azurerm_virtual_network" "example" {
      name                = "example-virtual-network"
      address_space       = ["10.0.0.0/16"]
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
      tags = {
        costCenter = "My Cost Center"
      }
      depends_on = [ azurerm_resource_group.example ]
    }
    
    resource "azurerm_subnet" "example" {
      name                 = "example-subnet"
      resource_group_name  = azurerm_resource_group.example.name
      virtual_network_name = azurerm_virtual_network.example.name
      address_prefixes     = ["10.0.1.0/24"]
      
    
      delegation {
        name = "example-delegation"
    
        service_delegation {
          name    = "Microsoft.Web/serverFarms"
          actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
        }
      }
      depends_on = [ azurerm_virtual_network.example ]
    }
    
    resource "azurerm_app_service_plan" "example" {
      name                = "example-app-service-plan"
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
      depends_on = [ azurerm_resource_group.example ]
    
      sku {
        tier = "Standard"
        size = "S1"
      }
      tags = {
        costCenter = "My Cost Center"
    }
    }
    
    resource "azurerm_storage_account" "example" {
      name                     = "siliconstrg54332"
      resource_group_name      = azurerm_resource_group.example.name
      location                 = azurerm_resource_group.example.location
      account_tier             = "Standard"
      account_replication_type = "LRS"
      
      tags = {
        costCenter = "My Cost Center"
      }
      depends_on = [ azurerm_resource_group.example ]
    }
    
    resource "azurerm_function_app" "example" {
      name                       = "siliconfunc-0987"
      location                   = azurerm_resource_group.example.location
      resource_group_name        = azurerm_resource_group.example.name
      app_service_plan_id        = azurerm_app_service_plan.example.id
      storage_account_name       = azurerm_storage_account.example.name
      storage_account_access_key = azurerm_storage_account.example.primary_access_key
      tags = {
        costCenter = "My Cost Center"
      }
      depends_on = [azurerm_app_service_plan.example]
    }
    resource "azurerm_app_service_virtual_network_swift_connection" "this" {
      app_service_id = azurerm_function_app.example.id
      subnet_id      = azurerm_subnet.example.id
    
    depends_on = [azurerm_subnet.example, azurerm_function_app.example]
      lifecycle {
        ignore_changes = [
          subnet_id,
        ]
      }
    }