Skip to content

Commit

Permalink
breaking: DEVOPS-868 Azurerm_function_app resource replacement (#65)
Browse files Browse the repository at this point in the history
* add "azurerm_service_plan"

* added azurerm_service_plan

* fix README.md

* add test for function_app

* add a working test

* add variables

* file rename

* minor changes

* working test

* working test

* add new resources

* raw migration completed

* working

* app_service_plan_info/sku_tier variable removed

* modify README.md

* modify README.md

* remove linux_fx_version variable

* modify README.md

* update azurerm version

* fix(function_app): Always on default to null

* fix: remove azurerm provider

* fix: Remove azurerm provider

* fix: terraform fmt

* fix: Add README.md to the test folder

* fix: modify README.md

* fix: README.md change

* add random provider to the function name

* testing different functions

* terraform fmt

* pre-commit check

* terraform docs hook

* .

* fix: README.md

* fix: README.md

* completed script

* add health_check_eviction_time_in_min and sticky_settings

* pre-commit test passed

* remove migrate.sh script

---------

Co-authored-by: Flisco <{ID}+{username}@users.noreply.github.com>
  • Loading branch information
fmlisco and Flisco authored Feb 22, 2023
1 parent ddcfdc5 commit 6d19f25
Show file tree
Hide file tree
Showing 9 changed files with 380 additions and 196 deletions.
178 changes: 81 additions & 97 deletions function_app/README.md

Large diffs are not rendered by default.

177 changes: 100 additions & 77 deletions function_app/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -156,27 +156,6 @@ resource "azurerm_private_endpoint" "table" {
tags = var.tags
}

resource "azurerm_app_service_plan" "this" {
count = var.app_service_plan_id == null ? 1 : 0

name = var.app_service_plan_name != null ? var.app_service_plan_name : format("%s-plan", var.name)
location = var.location
resource_group_name = var.resource_group_name
kind = var.app_service_plan_info.kind

sku {
tier = var.app_service_plan_info.sku_tier
size = var.app_service_plan_info.sku_size
# capacity is only for isolated envs
}

maximum_elastic_worker_count = var.app_service_plan_info.kind == "elastic" ? var.app_service_plan_info.maximum_elastic_worker_count : null
reserved = var.app_service_plan_info.kind == "Linux" ? true : null
per_site_scaling = false

tags = var.tags
}

locals {
allowed_ips = [for ip in var.allowed_ips : { ip_address = ip, virtual_network_subnet_id = null }]
allowed_subnets = [for s in var.allowed_subnets : { ip_address = null, virtual_network_subnet_id = s }]
Expand All @@ -187,27 +166,107 @@ locals {
internal_containers = var.internal_storage.enable ? var.internal_storage.containers : []
}

resource "azurerm_function_app" "this" {
# this datasource has been introduced within version 2.27.0
data "azurerm_function_app_host_keys" "this" {
count = var.export_keys ? 1 : 0

name = var.name
resource_group_name = var.resource_group_name
depends_on = [azurerm_linux_function_app.this]
}

# Manages an App Service Virtual Network Association
resource "azurerm_app_service_virtual_network_swift_connection" "this" {
count = var.vnet_integration ? 1 : 0

app_service_id = azurerm_linux_function_app.this.id
subnet_id = var.subnet_id
}

resource "azurerm_monitor_metric_alert" "function_app_health_check" {
count = var.enable_healthcheck ? 1 : 0

name = "[${var.domain != null ? "${var.domain} | " : ""}${azurerm_linux_function_app.this.name}] Health Check Failed"
resource_group_name = var.resource_group_name
scopes = [azurerm_linux_function_app.this.id]
description = "Function availability is under threshold level. Runbook: -"
severity = 1
frequency = "PT5M"
auto_mitigate = false
enabled = true

criteria {
metric_namespace = "Microsoft.Web/sites"
metric_name = "HealthCheckStatus"
aggregation = "Average"
operator = "LessThan"
threshold = var.healthcheck_threshold
}

dynamic "action" {
for_each = var.action
content {
action_group_id = action.value["action_group_id"]
webhook_properties = action.value["webhook_properties"]
}
}
}

resource "azurerm_service_plan" "this" {
count = var.app_service_plan_id == null ? 1 : 0

name = var.app_service_plan_name != null ? var.app_service_plan_name : format("%s-plan", var.name)
location = var.location
version = var.runtime_version
app_service_plan_id = var.app_service_plan_id != null ? var.app_service_plan_id : azurerm_app_service_plan.this[0].id
resource_group_name = var.resource_group_name
os_type = "Linux"
sku_name = var.app_service_plan_info.sku_size

per_site_scaling_enabled = false

tags = var.tags
}

resource "azurerm_linux_function_app" "this" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
functions_extension_version = var.runtime_version
service_plan_id = var.app_service_plan_id != null ? var.app_service_plan_id : azurerm_service_plan.this[0].id
# The backend storage account name which will be used by this Function App (such as the dashboard, logs)
storage_account_name = module.storage_account.name
storage_account_access_key = module.storage_account.primary_access_key
https_only = var.https_only
os_type = var.os_type
client_certificate_enabled = var.client_certificate_enabled

site_config {
min_tls_version = "1.2"
minimum_tls_version = "1.2"
ftps_state = "Disabled"
http2_enabled = true
always_on = var.always_on
pre_warmed_instance_count = var.pre_warmed_instance_count
vnet_route_all_enabled = var.subnet_id == null ? false : true
use_32_bit_worker_process = var.use_32_bit_worker_process
linux_fx_version = var.linux_fx_version
use_32_bit_worker = var.use_32_bit_worker_process
application_insights_key = var.application_insights_instrumentation_key

application_stack {
dotnet_version = var.dotnet_version
use_dotnet_isolated_runtime = var.use_dotnet_isolated_runtime
java_version = var.java_version
python_version = var.python_version
node_version = var.node_version
powershell_core_version = var.powershell_core_version
use_custom_runtime = var.use_custom_runtime
dynamic "docker" {
for_each = length(var.docker) > 0 ? [1] : []
content {
registry_url = var.docker.registry_url
image_name = var.docker.image_name
image_tag = var.docker.image_tag
registry_username = var.docker.registry_username
registry_password = var.docker.registry_password
}
}
}

dynamic "ip_restriction" {
for_each = local.ip_restrictions
Expand Down Expand Up @@ -238,7 +297,6 @@ resource "azurerm_function_app" "this" {
# https://docs.microsoft.com/en-us/azure/azure-functions/functions-app-settings
app_settings = merge(
{
APPINSIGHTS_INSTRUMENTATIONKEY = var.application_insights_instrumentation_key
# No downtime on slots swap
WEBSITE_ADD_SITENAME_BINDINGS_IN_APPHOST_CONFIG = 1
# default value for health_check_path, override it in var.app_settings if needed
Expand All @@ -256,7 +314,7 @@ resource "azurerm_function_app" "this" {
var.app_settings,
)

enable_builtin_logging = false
builtin_logging_enabled = false

dynamic "identity" {
for_each = var.system_identity_enabled ? [1] : []
Expand All @@ -265,53 +323,18 @@ resource "azurerm_function_app" "this" {
}
}

tags = var.tags
}

# this datasource has been introduced within version 2.27.0
data "azurerm_function_app_host_keys" "this" {
count = var.export_keys ? 1 : 0

name = var.name
resource_group_name = var.resource_group_name
depends_on = [azurerm_function_app.this]
}

# Manages an App Service Virtual Network Association
resource "azurerm_app_service_virtual_network_swift_connection" "this" {
count = var.vnet_integration ? 1 : 0

app_service_id = azurerm_function_app.this.id
subnet_id = var.subnet_id
}



resource "azurerm_monitor_metric_alert" "function_app_health_check" {
count = var.enable_healthcheck ? 1 : 0

name = "[${var.domain != null ? "${var.domain} | " : ""}${azurerm_function_app.this.name}] Health Check Failed"
resource_group_name = var.resource_group_name
scopes = [azurerm_function_app.this.id]
description = "Function availability is under threshold level. Runbook: -"
severity = 1
frequency = "PT5M"
auto_mitigate = false
enabled = true

criteria {
metric_namespace = "Microsoft.Web/sites"
metric_name = "HealthCheckStatus"
aggregation = "Average"
operator = "LessThan"
threshold = var.healthcheck_threshold
lifecycle {
ignore_changes = [
virtual_network_subnet_id
]
}

dynamic "action" {
for_each = var.action
content {
action_group_id = action.value["action_group_id"]
webhook_properties = action.value["webhook_properties"]
}
sticky_settings {
app_setting_names = concat(
["SLOT_TASK_HUBNAME"],
var.sticky_settings,
)
}
}

tags = var.tags
}
12 changes: 6 additions & 6 deletions function_app/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
output "id" {
value = azurerm_function_app.this.id
value = azurerm_linux_function_app.this.id
}

output "name" {
value = var.name
}

output "default_hostname" {
value = azurerm_function_app.this.default_hostname
value = azurerm_linux_function_app.this.default_hostname
sensitive = true
}

output "possible_outbound_ip_addresses" {
value = azurerm_function_app.this.possible_outbound_ip_addresses
value = azurerm_linux_function_app.this.possible_outbound_ip_addresses
}

output "default_key" {
Expand All @@ -31,11 +31,11 @@ output "primary_key" {
}

output "app_service_plan_id" {
value = var.app_service_plan_id != null ? var.app_service_plan_id : azurerm_app_service_plan.this[0].id
value = var.app_service_plan_id != null ? var.app_service_plan_id : azurerm_service_plan.this[0].id
}

output "app_service_plan_name" {
value = var.app_service_plan_id != null ? var.app_service_plan_name : azurerm_app_service_plan.this[0].name
value = var.app_service_plan_id != null ? var.app_service_plan_name : azurerm_service_plan.this[0].name
}

output "storage_account_name" {
Expand Down Expand Up @@ -67,6 +67,6 @@ output "storage_account_internal_function" {
}

output "system_identity_principal" {
value = var.system_identity_enabled ? azurerm_function_app.this.identity[0].principal_id : null
value = var.system_identity_enabled ? azurerm_linux_function_app.this.identity[0].principal_id : null
description = "Service Principal of the System Identity generated by Azure."
}
9 changes: 9 additions & 0 deletions function_app/tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Test for Azure the function_app module

Terraform template to test the Azure function_app module


## How to use it
- terraform init
- terraform plan
- terraform apply
90 changes: 90 additions & 0 deletions function_app/tests/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#
# APP CONFIGURATION
#

resource "random_id" "function_id" {
byte_length = 4
}

resource "azurerm_application_insights" "example" {
name = "${var.project}-${random_id.function_id.hex}-appinsights"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
application_type = "web"
}

resource "azurerm_resource_group" "example" {
name = "${var.project}-${random_id.function_id.hex}-rg"
location = var.location
}

resource "azurerm_virtual_network" "example" {
name = "${var.project}-${random_id.function_id.hex}-vn"
address_space = var.address_space
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
}

resource "azurerm_subnet" "example" {
name = "${var.project}-${random_id.function_id.hex}-subnet"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = var.address_prefixes

delegation {
name = "${var.project}-${random_id.function_id.hex}-delegation"

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

locals {
function_app = {
app_settings_common = {
FUNCTIONS_WORKER_PROCESS_COUNT = 4
}
app_settings_1 = {
}
app_settings_2 = {
}
}

func_python = {
app_settings_common = local.function_app.app_settings_common
app_settings_1 = {
}
app_settings_2 = {
}
}
}

# #tfsec:ignore:azure-storage-queue-services-logging-enabled:exp:2022-05-01 # already ignored, maybe a bug in tfsec
module "func_python" {
source = "../../function_app"

resource_group_name = azurerm_resource_group.example.name
name = "${var.project}-${random_id.function_id.hex}-fn-py"
location = var.location
health_check_path = "/api/v1/info"
python_version = "3.9"
runtime_version = "~4"

always_on = true
application_insights_instrumentation_key = azurerm_application_insights.example.instrumentation_key

app_settings = merge(
local.func_python.app_settings_common, {}
)

subnet_id = azurerm_subnet.example.id

allowed_subnets = [
azurerm_subnet.example.id,
]

tags = merge(var.tags,
{ Name = "${var.project}-${random_id.function_id.hex}_function_app" })
}
Loading

0 comments on commit 6d19f25

Please sign in to comment.