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...
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:
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}"