Skip to content
This repository was archived by the owner on Sep 12, 2025. It is now read-only.

Commit b5474b3

Browse files
committed
Simplify function app terraform
We only have one region across all environments so remove the loop over regions. We can address adding another region when the time comes. We only have once function app now, so remove the additional configuration needed to loop over multiple function configs.
1 parent ce8fda8 commit b5474b3

File tree

3 files changed

+84
-131
lines changed

3 files changed

+84
-131
lines changed

infrastructure/tf-core/data.tf

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,22 @@ data "azurerm_subnet" "subnet_audit_pep" {
4646
data "azurerm_container_registry" "acr" {
4747
provider = azurerm.hub
4848

49-
name = var.function_apps.acr_name
50-
resource_group_name = var.function_apps.acr_rg_name
49+
name = var.function_app.acr_name
50+
resource_group_name = var.function_app.acr_rg_name
5151
}
5252

5353
data "azurerm_user_assigned_identity" "acr_mi" {
5454
provider = azurerm.hub
5555

56-
name = var.function_apps.acr_mi_name
57-
resource_group_name = var.function_apps.acr_rg_name
56+
name = var.function_app.acr_mi_name
57+
resource_group_name = var.function_app.acr_rg_name
5858
}
5959

6060
data "azurerm_application_insights" "ai" {
6161
provider = azurerm.audit
6262

63-
name = var.function_apps.app_insights_name
64-
resource_group_name = var.function_apps.app_insights_rg_name
63+
name = var.function_app.app_insights_name
64+
resource_group_name = var.function_app.app_insights_rg_name
6565
}
6666

6767
data "azurerm_key_vault_secret" "application_id" {
Lines changed: 55 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,53 @@
11
module "functionapp" {
2-
for_each = local.function_app_map
3-
42
source = "../../../dtos-devops-templates/infrastructure/modules/function-app"
53

6-
function_app_name = "${module.regions_config[each.value.region].names.function-app}-${lower(each.value.name_suffix)}"
7-
resource_group_name = azurerm_resource_group.core[each.value.region].name
8-
location = each.value.region
4+
function_app_name = "${module.regions_config[local.primary_region].names.function-app}-${local.name_suffix}"
5+
resource_group_name = azurerm_resource_group.core[local.primary_region].name
6+
location = local.primary_region
97

10-
app_settings = each.value.app_settings
8+
app_settings = local.app_settings
119

1210
log_analytics_workspace_id = data.terraform_remote_state.audit.outputs.log_analytics_workspace_id[local.primary_region]
1311
monitor_diagnostic_setting_function_app_enabled_logs = local.monitor_diagnostic_setting_function_app_enabled_logs
1412
monitor_diagnostic_setting_function_app_metrics = local.monitor_diagnostic_setting_function_app_metrics
1513

1614
public_network_access_enabled = var.features.public_network_access_enabled
17-
vnet_integration_subnet_id = module.subnets["${module.regions_config[each.value.region].names.subnet}-apps"].id
15+
vnet_integration_subnet_id = module.subnets["${module.regions_config[local.primary_region].names.subnet}-apps"].id
1816

19-
rbac_role_assignments = each.value.rbac_role_assignments
17+
rbac_role_assignments = local.rbac_role_assignments
2018

21-
asp_id = module.app-service-plan["${each.value.app_service_plan_key}-${each.value.region}"].app_service_plan_id
19+
asp_id = module.app-service-plan["${var.app_service_plan_key}-${local.primary_region}"].app_service_plan_id
2220

2321
# Use the storage account assigned identity for the Function Apps:
24-
storage_account_name = module.storage["fnapp-${each.value.region}"].storage_account_name
25-
storage_account_access_key = var.function_apps.storage_uses_managed_identity == true ? null : module.storage["fnapp-${each.value.region}"].storage_account_primary_access_key
26-
storage_uses_managed_identity = var.function_apps.storage_uses_managed_identity
22+
storage_account_name = module.storage["fnapp-${local.primary_region}"].storage_account_name
23+
storage_account_access_key = var.function_app.storage_uses_managed_identity == true ? null : module.storage["fnapp-${local.primary_region}"].storage_account_primary_access_key
24+
storage_uses_managed_identity = var.function_app.storage_uses_managed_identity
2725

2826
# Connection string for Application Insights:
2927
ai_connstring = data.azurerm_application_insights.ai.connection_string
3028

3129
# Use the ACR assigned identity for the Function Apps:
32-
cont_registry_use_mi = var.function_apps.cont_registry_use_mi
30+
cont_registry_use_mi = var.function_app.cont_registry_use_mi
3331

3432
# Other Function App configuration settings:
35-
always_on = var.function_apps.always_on
36-
worker_32bit = var.function_apps.worker_32bit
33+
always_on = var.function_app.always_on
34+
worker_32bit = var.function_app.worker_32bit
3735

3836
acr_mi_client_id = data.azurerm_user_assigned_identity.acr_mi.client_id
3937
acr_login_server = data.azurerm_container_registry.acr.login_server
4038

4139
# Use the ACR assigned identity for the Function Apps too:
42-
assigned_identity_ids = var.function_apps.cont_registry_use_mi ? [data.azurerm_user_assigned_identity.acr_mi.id] : []
40+
assigned_identity_ids = var.function_app.cont_registry_use_mi ? [data.azurerm_user_assigned_identity.acr_mi.id] : []
4341

44-
image_tag = var.function_apps.docker_env_tag
45-
image_name = "${var.function_apps.docker_img_prefix}-${lower(each.value.name_suffix)}"
42+
image_tag = var.function_app.docker_env_tag
43+
image_name = "${var.function_app.docker_img_prefix}-${lower(local.name_suffix)}"
4644

4745
# Private Endpoint Configuration if enabled
4846
private_endpoint_properties = var.features.private_endpoints_enabled ? {
49-
private_dns_zone_ids = [data.terraform_remote_state.hub.outputs.private_dns_zones["${each.value.region}-app_services"].id]
47+
private_dns_zone_ids = [data.terraform_remote_state.hub.outputs.private_dns_zones["${local.primary_region}-app_services"].id]
5048
private_endpoint_enabled = var.features.private_endpoints_enabled
51-
private_endpoint_subnet_id = module.subnets["${module.regions_config[each.value.region].names.subnet}-pep"].id
52-
private_endpoint_resource_group_name = azurerm_resource_group.rg_private_endpoints[each.value.region].name
49+
private_endpoint_subnet_id = module.subnets["${module.regions_config[local.primary_region].names.subnet}-pep"].id
50+
private_endpoint_resource_group_name = azurerm_resource_group.rg_private_endpoints[local.primary_region].name
5351
private_service_connection_is_manual = var.features.private_service_connection_is_manual
5452
} : null
5553

@@ -60,95 +58,44 @@ module "functionapp" {
6058

6159

6260
locals {
61+
name_suffix = "communication_management"
6362
primary_region = [for k, v in var.regions : k if v.is_primary_region][0]
64-
65-
app_settings_common = {
66-
DOCKER_ENABLE_CI = var.function_apps.docker_CI_enable
67-
REMOTE_DEBUGGING_ENABLED = var.function_apps.remote_debugging_enabled
68-
WEBSITES_ENABLE_APP_SERVICE_STORAGE = var.function_apps.enable_appsrv_storage
69-
WEBSITE_PULL_IMAGE_OVER_VNET = var.features.private_endpoints_enabled
70-
FUNCTIONS_WORKER_RUNTIME = "python"
71-
}
72-
73-
# There are multiple Function Apps and possibly multiple regions.
74-
# We cannot nest for loops inside a map, so first iterate all permutations of both as a list of objects...
75-
function_app_config_object_list = flatten([
76-
for region in keys(var.regions) : [
77-
for function, config in var.function_apps.fa_config : merge(
78-
{
79-
region = region # 1st iterator
80-
function = function # 2nd iterator
81-
},
82-
config, # the rest of the key/value pairs for a specific function
83-
{
84-
app_settings = merge(
85-
local.app_settings_common,
86-
config.env_vars_static,
87-
88-
# Dynamic env vars which cannot be stored in tfvars file
89-
function == "message-status" ? {
90-
APPLICATION_ID = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.application_id[region].versionless_id})"
91-
NOTIFY_API_KEY = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.notify_api_key[region].versionless_id})"
92-
} : {},
93-
function == "notify" ? {
94-
OAUTH2_API_KID = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.oauth2_api_kid[region].versionless_id})"
95-
OAUTH2_API_KEY = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.oauth2_api_key[region].versionless_id})"
96-
PRIVATE_KEY = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_key.private_key[region].versionless_id})"
97-
} : {},
98-
function == "process-pilot-data" ? {
99-
AzureWebJobsStorage__accountName = module.storage["fnapp-${region}"].storage_account_name
100-
NOTIFY_FUNCTION_URL = format(
101-
"https://%s-%s.azurewebsites.net/api/%s/message/send",
102-
module.regions_config[region].names["function-app"],
103-
var.function_apps.fa_config["notify"].name_suffix,
104-
lower(var.function_apps.fa_config["notify"].function_endpoint_name)
105-
)
106-
} : {},
107-
108-
# Dynamic reference to Key Vault
109-
length(config.key_vault_url) > 0 ? {
110-
(config.key_vault_url) = module.key_vault[region].key_vault_url
111-
} : {},
112-
113-
# Database
114-
config.database_required ? {
115-
DATABASE_NAME = "communication_management"
116-
DATABASE_HOST = "${module.regions_config[region].names.postgres-sql-server}.postgres.database.azure.com"
117-
DATABASE_USER = "commgt_db_user"
118-
DATABASE_PASSWORD = "@Microsoft.KeyVault(SecretUri=${module.postgresql_flexible_db[region].db_admin_pwd_keyvault_secret})"
119-
# DATABASE_USER = var.postgresql.postgres_sql_admin_group
120-
} : {}
121-
122-
)
123-
124-
# These RBAC assignments are for the Function Apps only
125-
rbac_role_assignments = flatten([
126-
127-
# Key Vault
128-
var.key_vault != {} ? [
129-
for role in local.rbac_roles_key_vault_user : {
130-
role_definition_name = role
131-
scope = module.key_vault[region].key_vault_id
132-
}
133-
] : [],
134-
135-
# Storage Accounts
136-
[
137-
for account in keys(var.storage_accounts) : [
138-
for role in local.rbac_roles_storage : {
139-
role_definition_name = role
140-
scope = module.storage["${account}-${region}"].storage_account_id
141-
}
142-
]
143-
]
144-
])
63+
app_settings = merge(
64+
var.function_app.env_vars_static,
65+
{
66+
DOCKER_ENABLE_CI = var.function_app.docker_CI_enable
67+
FUNCTIONS_WORKER_RUNTIME = "python"
68+
REMOTE_DEBUGGING_ENABLED = var.function_app.remote_debugging_enabled
69+
WEBSITES_ENABLE_APP_SERVICE_STORAGE = var.function_app.enable_appsrv_storage
70+
WEBSITE_PULL_IMAGE_OVER_VNET = var.features.private_endpoints_enabled
71+
72+
DATABASE_NAME = "communication_management"
73+
DATABASE_HOST = "${module.regions_config[var.regions.keys[0]].names.postgres-sql-server}.postgres.database.azure.com"
74+
DATABASE_USER = "commgt_db_user"
75+
DATABASE_PASSWORD = "@Microsoft.KeyVault(SecretUri=${module.postgresql_flexible_db[var.regions.keys[0]].db_admin_pwd_keyvault_secret})"
76+
77+
APPLICATION_ID = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.application_id[var.regions.keys[0]].versionless_id})"
78+
NOTIFY_API_KEY = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.notify_api_key[var.regions.keys[0]].versionless_id})"
79+
OAUTH2_API_KID = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.oauth2_api_kid[var.regions.keys[0]].versionless_id})"
80+
OAUTH2_API_KEY = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.oauth2_api_key[var.regions.keys[0]].versionless_id})"
81+
PRIVATE_KEY = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_key.private_key[var.regions.keys[0]].versionless_id})"
82+
}
83+
)
84+
85+
rbac_role_assignments = flatten([
86+
var.key_vault != {} ? [
87+
for role in local.rbac_roles_key_vault_user : {
88+
role_definition_name = role
89+
scope = module.key_vault[var.regions.keys[0]].key_vault_id
90+
}
91+
] : [],
92+
[
93+
for account in keys(var.storage_accounts) : [
94+
for role in local.rbac_roles_storage : {
95+
role_definition_name = role
96+
scope = module.storage["${account}-${var.regions.keys[0]}"].storage_account_id
14597
}
146-
)
98+
]
14799
]
148100
])
149-
150-
# ...then project the list of objects into a map with unique keys (combining the iterators), for consumption by a for_each meta argument
151-
function_app_map = {
152-
for object in local.function_app_config_object_list : "${object.function}-${object.region}" => object
153-
}
154101
}

infrastructure/tf-core/variables.tf

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ variable "app_service_plan" {
162162
})
163163
}
164164

165-
variable "function_apps" {
165+
variable "function_app" {
166166
description = "Configuration for function apps"
167167
type = object({
168168
acr_mi_name = string
@@ -185,22 +185,23 @@ variable "function_apps" {
185185
name = string
186186
slot_enabled = optional(bool, false)
187187
})))
188-
fa_config = map(object({
189-
name_suffix = string
190-
function_endpoint_name = string
191-
app_service_plan_key = string
192-
storage_containers = optional(list(object({
193-
env_var_name = string
194-
container_name = string
195-
})), [])
196-
database_required = optional(bool, false)
197-
key_vault_url = optional(string, "")
198-
app_urls = optional(list(object({
199-
env_var_name = string
200-
function_app_key = string
201-
})), [])
202-
env_vars_static = optional(map(string), {})
203-
}))
188+
189+
name_suffix = string
190+
function_endpoint_name = string
191+
app_service_plan_key = string
192+
193+
storage_containers = optional(list(object({
194+
env_var_name = string
195+
container_name = string
196+
})), [])
197+
198+
key_vault_url = optional(string, "")
199+
200+
app_urls = optional(list(object({
201+
env_var_name = string
202+
function_app_key = string
203+
})), [])
204+
env_vars_static = optional(map(string), {})
204205
})
205206
}
206207

@@ -363,3 +364,8 @@ variable "function_app_slots" {
363364
function_app_slot_enabled = optional(bool, false)
364365
}))
365366
}
367+
368+
variable "app_service_plan_key" {
369+
description = "The key for the app service plan"
370+
type = string
371+
}

0 commit comments

Comments
 (0)