Search code examples
azureterraformazure-functionshcl

Encountered an error (ServiceUnavailable) from host runtime on Azure Function App


I'm deploying a zip package as an Azure function with the use of Terraform. The relevant code fragments below:

resource "azurerm_storage_account" "mtr_storage" {
  name                     = "mtrstorage${random_string.random_storage_account_suffix.result}"
  resource_group_name      = azurerm_resource_group.mtr_rg.name
  location                 = azurerm_resource_group.mtr_rg.location
  account_kind             = "BlobStorage"
  account_tier             = "Standard"
  account_replication_type = "LRS"

  network_rules {
    default_action             = "Deny"
    ip_rules                   = ["127.0.0.1", "my.id.addr.here"]
    virtual_network_subnet_ids = [azurerm_subnet.mtr_subnet.id]
    bypass                     = ["AzureServices", "Metrics"]
  }

  tags = {
    environment = "local"
  }
}

resource "azurerm_storage_blob" "mtr_hello_function_blob" {
  name                   = "MTR.ListBlobsFunction.publish.zip"
  storage_account_name   = azurerm_storage_account.mtr_storage.name
  storage_container_name = azurerm_storage_container.mtr_hello_function_container.name
  type                   = "Block"
  source                 = "./example_code/MTR.ListBlobsFunction/MTR.ListBlobsFunction.publish.zip"
}

resource "azurerm_service_plan" "mtr_hello_function_svc_plan" {
  name                = "mtr-hello-function-svc-plan"
  location            = azurerm_resource_group.mtr_rg.location
  resource_group_name = azurerm_resource_group.mtr_rg.name
  os_type             = "Linux"
  sku_name            = "B1"

  tags = {
    environment = "local"
  }
}

data "azurerm_storage_account_blob_container_sas" "storage_account_blob_container_sas_for_hello" {
  connection_string = azurerm_storage_account.mtr_storage.primary_connection_string
  container_name    = azurerm_storage_container.mtr_hello_function_container.name

  start  = timeadd(timestamp(), "-5m")
  expiry = timeadd(timestamp(), "5m")

  permissions {
    read   = true
    add    = false
    create = false
    write  = false
    delete = false
    list   = false
  }
}

resource "azurerm_linux_function_app" "mtr_hello_function" {
  name                       = "mtr-hello-function"
  location                   = azurerm_resource_group.mtr_rg.location
  resource_group_name        = azurerm_resource_group.mtr_rg.name
  service_plan_id            = azurerm_service_plan.mtr_hello_function_svc_plan.id
  storage_account_name       = azurerm_storage_account.mtr_storage.name
  storage_account_access_key = azurerm_storage_account.mtr_storage.primary_access_key

  app_settings = {
    "FUNCTIONS_WORKER_RUNTIME"    = "dotnet"
    "WEBSITE_RUN_FROM_PACKAGE"    = "https://${azurerm_storage_account.mtr_storage.name}.blob.core.windows.net/${azurerm_storage_container.mtr_hello_function_container.name}/${azurerm_storage_blob.mtr_hello_function_blob.name}${data.azurerm_storage_account_blob_container_sas.storage_account_blob_container_sas_for_hello.sas}"
    "AzureWebJobsStorage"         = azurerm_storage_account.mtr_storage.primary_connection_string
    "AzureWebJobsDisableHomepage" = "true"
  }

  site_config {
    always_on                              = true
    application_insights_connection_string = azurerm_application_insights.mtr_ai.connection_string

    application_stack {
      dotnet_version              = "8.0"
      use_dotnet_isolated_runtime = true
    }

    cors {
      allowed_origins = ["*"]
    }
  }

  tags = {
    environment = "local"
  }
}

The zip file is uploaded to the storage account, it is downloadable and has the correct structure (or so I think). Function App is created as well, however when I scroll down to see the functions, it tells me there was an error loading functions: Encountered an error (ServiceUnavailable) from host runtime. It's probably some configuration error, but I just can't see it. Also I went to the advanced tools tab and in wwwroot there's only one file named run_from_package_failure.log. Its contents are:

RunFromPackage> Failed to download package from https://mtrstorageqbr56n79h4.blob.core.windows.net/hello-function-releases/MTR.ListBlobsFunction.publish.zip?sv=2018-11-09&sr=c&st=2024-03-31T12:09:08Z&se=2024-03-31T12:19:08Z&sp=r&spr=https&sig=c6dhOCRPL%2BEQujbuq0589D2MXFN5eXfBmhow1QWSfHU%3D. Return code: 1 - (this URL is malformed, I swapped some characters ;) ). However when I go to the url the log contains, the zip file gets downloaded successfully...


Solution

  • Firstly, to deploy required code as an Azure function within a function app, you need to use azurerm_function_app_function resource provider. This will ensure that the function becomes visible and accessible within the function app as a separate code.

    Simply adding code in the way you're attempting will only make it visible under app files, but it won't be recognized as a distinct function.

    I tried similar code as you in my environment and the deployment was successful as shown below.

    terraform {
      required_providers {
        azurerm = {
          source = "hashicorp/azurerm"
          version = "3.97.1"
        }
      }
    }
    provider "azurerm" {
      features {}
    }
    data "azurerm_resource_group" "mtr_rg" {
      name = "Jahnavi"
    }
    
    resource "azurerm_storage_account" "mtr_storage" {
      name                     = "mtrstoragej"
      resource_group_name      = data.azurerm_resource_group.mtr_rg.name
      location                 = data.azurerm_resource_group.mtr_rg.location
      account_kind             = "BlobStorage"
      account_tier             = "Standard"
      account_replication_type = "LRS"
    
    }
    resource "azurerm_storage_container" "mtr_hello_function_container" {
      name                  = "vhds"
      storage_account_name  = azurerm_storage_account.mtr_storage.name
      container_access_type = "private"
    }
    
    resource "azurerm_storage_blob" "mtr_hello_function_blob" {
      name                   = "MTR.ListBlobsFunction.publish.zip"
      storage_account_name   = azurerm_storage_account.mtr_storage.name
      storage_container_name = azurerm_storage_container.mtr_hello_function_container.name
      type                   = "Block"
      source                 = "/home/xx/Console-Application-Examples-for-.Net-Core-master.zip"
    }
    
    resource "azurerm_service_plan" "mtr_hello_function_svc_plan" {
      name                = "mtr-hello-function-svc-plan"
      location            = data.azurerm_resource_group.mtr_rg.location
      resource_group_name = data.azurerm_resource_group.mtr_rg.name
      os_type             = "Linux"
      sku_name            = "B1"
    }
    
    data "azurerm_storage_account_blob_container_sas" "storage_account_blob_container_sas_for_hello" {
      connection_string = azurerm_storage_account.mtr_storage.primary_connection_string
      container_name    = azurerm_storage_container.mtr_hello_function_container.name
    
      start  = timeadd(timestamp(), "-5m")
      expiry = timeadd(timestamp(), "5m")
    
      permissions {
        read   = true
        add    = false
        create = false
        write  = false
        delete = false
        list   = false
      }
    }
    
    resource "azurerm_linux_function_app" "mtr_hello_function" {
      name                       = "jahfuncchoc"
      location                   = data.azurerm_resource_group.mtr_rg.location
      resource_group_name        = data.azurerm_resource_group.mtr_rg.name
      service_plan_id            = azurerm_service_plan.mtr_hello_function_svc_plan.id
      storage_account_name       = azurerm_storage_account.mtr_storage.name
      storage_account_access_key = azurerm_storage_account.mtr_storage.primary_access_key
    
      app_settings = {
        "FUNCTIONS_WORKER_RUNTIME"    = "dotnet"
        "WEBSITE_RUN_FROM_PACKAGE"    = "https://${azurerm_storage_account.mtr_storage.name}.blob.core.windows.net/${azurerm_storage_container.mtr_hello_function_container.name}/${azurerm_storage_blob.mtr_hello_function_blob.name}${data.azurerm_storage_account_blob_container_sas.storage_account_blob_container_sas_for_hello.sas}"
        "AzureWebJobsStorage"         = azurerm_storage_account.mtr_storage.primary_connection_string
        "AzureWebJobsDisableHomepage" = "true"
        "SCM_DO_BUILD_DURING_DEPLOYMENT" = "true"
      }
    
      site_config {
        always_on                              = true
        #application_insights_connection_string = azurerm_application_insights.mtr_ai.connection_string
    
        application_stack {
          dotnet_version              = "8.0"
          use_dotnet_isolated_runtime = true
        }
    
      }
    }
    

    Output:

    enter image description here

    enter image description here

    Function trigger code:

    resource "azurerm_function_app_function" "example" {
      name            = "examplejahfunction"
      function_app_id = azurerm_linux_function_app.mtr_hello_function.id
      language        = "CSharp"
    
      file {
        name    = "Console-Application-Examples-for-.Net-Core-master.zip"
        content = file("/home/xx/Console-Application-Examples-for-.Net-Core-master.zip")
      }
    
      test_data = jsonencode({
        "name" = "Azure"
      })
    
      config_json = jsonencode({
        "bindings" = [
          {
            "authLevel" = "function"
            "direction" = "in"
            "methods" = [
              "get",
              "post",
            ]
            "name" = "req"
            "type" = "httpTrigger"
          },
          {
            "direction" = "out"
            "name"      = "$return"
            "type"      = "http"
          },
        ]
      })
    }
    

    Coming to the issue you are facing now; it might be due to the value of "WEBSITE_RUN_FROM_PACKAGE" under app_setting block. Modify it as below and check the URL again.

    "WEBSITE_RUN_FROM_PACKAGE" = "${azurerm_storage_blob.mtr_hello_function_blob.url}${data.azurerm_storage_account_blob_container_sas.storage_account_blob_container_sas_for_hello.sas}"