Skip to content

Commit f88d1b4

Browse files
authored
Azure: Sample apps: Terraform tests (#32)
1 parent 287c0c3 commit f88d1b4

23 files changed

Lines changed: 401 additions & 79 deletions

File tree

.github/workflows/run-samples.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ jobs:
2323
strategy:
2424
fail-fast: false
2525
matrix:
26-
shard: [1, 2]
27-
splits: [2]
26+
shard: [1, 2, 3, 4]
27+
splits: [4]
2828
runs-on: ubuntu-latest
2929

3030
env:
@@ -59,6 +59,12 @@ jobs:
5959
sudo apt-get install -y jq zip unixodbc-dev libsnappy-dev
6060
find . -name "*.sh" -exec chmod +x {} +
6161
62+
- name: Install Terraform
63+
uses: hashicorp/setup-terraform@v3
64+
with:
65+
terraform_version: "1.5.0"
66+
terraform_wrapper: false
67+
6268
- name: Install test dependencies
6369
# Mirroring the localstack-pro approach: install all Python dependencies
6470
# (including the localstack CLI) into a virtual environment to avoid system-level conflicts.

requirements-runtime.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,3 @@ azure-core
99
python-dotenv
1010
localstack
1111
azlocal
12-
terraform-local

run-samples.sh

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set -euo pipefail
99
# - Node.js & npm
1010
# - Azure CLI (az)
1111
# - LocalStack CLI
12+
# - Terraform CLI
1213
# - azlocal & terraform-local (pip install azlocal terraform-local)
1314
# - funclocal (pip install funclocal)
1415
# - Azure Functions Core Tools (func)
@@ -32,6 +33,7 @@ command -v az >/dev/null 2>&1 || { echo >&2 "az CLI is required but not installe
3233
command -v azlocal >/dev/null 2>&1 || { echo >&2 "azlocal is required but not installed. Run 'pip install azlocal'. Aborting."; exit 1; }
3334
command -v funclocal >/dev/null 2>&1 || { echo >&2 "funclocal is required but not installed. Run 'pip install azlocal'. Aborting."; exit 1; }
3435
command -v tflocal >/dev/null 2>&1 || { echo >&2 "tflocal is required but not installed. Run 'pip install terraform-local'. Aborting."; exit 1; }
36+
command -v terraform >/dev/null 2>&1 || { echo >&2 "terraform CLI is required but not installed. Aborting."; exit 1; }
3537
command -v func >/dev/null 2>&1 || { echo >&2 "Azure Functions Core Tools (func) is required but not installed. Aborting."; exit 1; }
3638

3739
if [ -z "${LOCALSTACK_AUTH_TOKEN:-}" ]; then
@@ -55,10 +57,19 @@ if [ -n "${AZURE_CONFIG_DIR:-}" ]; then
5557
fi
5658

5759
if command -v azlocal >/dev/null 2>&1; then
60+
echo "[DEBUG] azlocal command found, attempting login..."
5861
azlocal login || true
62+
echo "[DEBUG] Starting azlocal interception..."
5963
azlocal start_interception
64+
echo "[DEBUG] Setting default subscription..."
65+
azlocal account set --subscription "00000000-0000-0000-0000-000000000000" || true
66+
echo "[DEBUG] Checking azlocal account status..."
67+
azlocal account show --query "{Environment:environmentName, Subscription:id}" --output json 2>&1 || echo "[DEBUG] azlocal account show failed"
6068
else
69+
echo "[DEBUG] azlocal not found, using standard az login with service principal..."
6170
az login --service-principal -u any-app -p any-pass --tenant any-tenant || true
71+
echo "[DEBUG] Checking az account status..."
72+
az account show --query "{Environment:environmentName, Subscription:id}" --output json 2>&1 || echo "[DEBUG] az account show failed"
6273
fi
6374

6475

@@ -72,8 +83,19 @@ SAMPLES=(
7283
"samples/web-app-sql-database/python|bash scripts/deploy.sh|bash scripts/validate.sh && bash scripts/get-web-app-url.sh"
7384
)
7485

86+
# 3a. Define Terraform Samples
87+
TERRAFORM_SAMPLES=(
88+
"samples/function-app-managed-identity/python/terraform|bash deploy.sh"
89+
"samples/function-app-storage-http/dotnet/terraform|bash deploy.sh"
90+
"samples/web-app-cosmosdb-mongodb-api/python/terraform|bash deploy.sh"
91+
"samples/web-app-managed-identity/python/terraform|bash deploy.sh"
92+
"samples/web-app-sql-database/python/terraform|bash deploy.sh"
93+
)
94+
7595
# 4. Calculate Shard
76-
TOTAL=${#SAMPLES[@]}
96+
# Combine both script-based and Terraform samples into one array
97+
ALL_SAMPLES=("${SAMPLES[@]}" "${TERRAFORM_SAMPLES[@]}")
98+
TOTAL=${#ALL_SAMPLES[@]}
7799
SHARD=${1:-1}
78100
SPLITS=${2:-1}
79101

@@ -85,28 +107,35 @@ if [ "$SHARD" -eq "$SPLITS" ]; then
85107
fi
86108

87109
echo "Running samples shard $SHARD of $SPLITS (index $START, count $COUNT)"
110+
echo "Total samples (scripts + terraform): $TOTAL"
88111

89112
# 5. Run Samples
90113
for (( i=START; i<START+COUNT; i++ )); do
91-
item="${SAMPLES[$i]}"
114+
item="${ALL_SAMPLES[$i]}"
92115
IFS='|' read -r path deploy test <<< "$item"
93116
echo "============================================================"
94117
echo "Testing Sample: $path"
95118
echo "============================================================"
96-
119+
97120
pushd "$path" > /dev/null
98-
121+
99122
echo "Deploying..."
100123
eval "$deploy"
101-
124+
102125
if [ -n "$test" ]; then
103126
echo "Testing..."
104127
eval "$test"
105128
fi
106-
129+
130+
# Cleanup Terraform state for terraform tests
131+
if [[ "$path" == *"/terraform" ]]; then
132+
echo "Cleaning up Terraform state..."
133+
rm -rf .terraform terraform.tfstate terraform.tfstate.backup .terraform.lock.hcl tfplan || true
134+
fi
135+
107136
popd > /dev/null
108137
echo "Completed: $path"
109-
138+
110139
# Cleanup Docker resources after each test to free up disk space
111140
echo "Cleaning up Docker resources..."
112141
docker system prune -af --volumes || true

samples/function-app-managed-identity/python/terraform/deploy.sh

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,62 @@
11
#!/bin/bash
22

33
# Variables
4-
PREFIX='local'
4+
PREFIX='funcmi'
55
SUFFIX='test'
66
LOCATION='westeurope'
77
MANAGED_IDENTITY_TYPE='UserAssigned' # SystemAssigned or UserAssigned
88
CURRENT_DIR="$(cd "$(dirname "$0")" && pwd)"
99
ZIPFILE="function_app.zip"
10-
ENVIRONMENT=$(az account show --query environmentName --output tsv)
1110

1211
# Change the current directory to the script's directory
1312
cd "$CURRENT_DIR" || exit
1413

14+
# Determine environment
15+
if command -v az >/dev/null 2>&1; then
16+
CLOUD_NAME=$(az cloud show --query name --output tsv 2>&1 || echo "")
17+
18+
if [[ "$CLOUD_NAME" == "LocalStack" ]]; then
19+
ENVIRONMENT="LocalStack"
20+
elif [[ "$CLOUD_NAME" == "AzureCloud" ]]; then
21+
ENVIRONMENT="AzureCloud"
22+
else
23+
ENVIRONMENT="AzureCloud"
24+
fi
25+
else
26+
ENVIRONMENT="AzureCloud"
27+
fi
28+
1529
# Run terraform init and apply
1630
if [[ $ENVIRONMENT == "LocalStack" ]]; then
17-
echo "Using tflocal and azlocal for LocalStack emulator environment and ."
31+
echo "Using tflocal and azlocal for LocalStack emulator environment."
1832
TERRAFORM="tflocal"
33+
34+
# Log Azure auth environment variables before unsetting
35+
echo "[DEBUG] Azure auth env vars before unsetting:"
36+
echo "[DEBUG] ARM_CLIENT_ID=${ARM_CLIENT_ID:-<not set>}"
37+
echo "[DEBUG] ARM_CLIENT_SECRET=${ARM_CLIENT_SECRET:+<set but hidden>}${ARM_CLIENT_SECRET:-<not set>}"
38+
echo "[DEBUG] ARM_TENANT_ID=${ARM_TENANT_ID:-<not set>}"
39+
echo "[DEBUG] ARM_SUBSCRIPTION_ID=${ARM_SUBSCRIPTION_ID:-<not set>}"
40+
echo "[DEBUG] AZURE_CLIENT_ID=${AZURE_CLIENT_ID:-<not set>}"
41+
echo "[DEBUG] AZURE_TENANT_ID=${AZURE_TENANT_ID:-<not set>}"
42+
43+
echo "[DEBUG] Azure auth env vars after unsetting: all cleared"
1944
AZ="azlocal"
2045
else
2146
echo "Using standard terraform and az for AzureCloud environment."
2247
TERRAFORM="terraform"
2348
AZ="az"
2449
fi
2550

51+
echo "[DEBUG] Cloud name: '$CLOUD_NAME', Environment: '$ENVIRONMENT', Tools: TERRAFORM=$TERRAFORM, AZ=$AZ"
52+
echo "[DEBUG] TERRAFORM command location: $(which $TERRAFORM 2>/dev/null || echo 'not found')"
53+
54+
# Enable Terraform debug logging
55+
export TF_LOG=DEBUG
56+
export TF_LOG_PATH="$CURRENT_DIR/terraform-debug.log"
57+
echo "[DEBUG] Checking what tflocal does..."echo "[DEBUG] tflocal version: $($TERRAFORM version 2>&1 | head -1)"echo "[DEBUG] Contents of current directory before init:"ls -la . 2>&1 | head -20
58+
echo "[DEBUG] Terraform debug logging enabled: TF_LOG=DEBUG, TF_LOG_PATH=$TF_LOG_PATH"
59+
2660
echo "Initializing Terraform..."
2761
$TERRAFORM init -upgrade
2862

@@ -36,6 +70,11 @@ $TERRAFORM plan -out=tfplan \
3670

3771
if [[ $? != 0 ]]; then
3872
echo "Terraform plan failed. Exiting."
73+
echo "============================================================"
74+
echo "Last 100 lines of Terraform debug log:"
75+
echo "============================================================"
76+
tail -100 "$TF_LOG_PATH" 2>/dev/null || echo "Debug log not found"
77+
echo "============================================================"
3978
exit 1
4079
fi
4180

samples/function-app-managed-identity/python/terraform/providers.tf

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,29 @@ terraform {
44
required_providers {
55
azurerm = {
66
source = "hashicorp/azurerm"
7-
version = "~>4.44.0"
7+
version = "=4.14.0"
88
}
99
}
1010
}
1111

1212
provider "azurerm" {
13-
features {}
13+
features {
14+
resource_group {
15+
prevent_deletion_if_contains_resources = false
16+
}
17+
}
18+
19+
# LocalStack Azure emulator configuration
20+
# Uses fixed credentials that tflocal intercepts via HTTPS proxy
1421
subscription_id = "00000000-0000-0000-0000-000000000000"
15-
}
22+
tenant_id = "00000000-0000-0000-0000-000000000000"
23+
client_id = "00000000-0000-0000-0000-000000000000"
24+
client_secret = "fake-secret"
25+
26+
# Skip provider registration - LocalStack doesn't support this API
27+
skip_provider_registration = true
28+
29+
# Disable CLI/MSI authentication - use static credentials instead
30+
use_cli = false
31+
use_msi = false
32+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
location = "westeurope"
22
runtime_name = "python"
3-
python_version = "3.13"
3+
python_version = "3.12"

samples/function-app-managed-identity/python/terraform/variables.tf

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
variable "prefix" {
22
description = "(Optional) Specifies the prefix for the name of the Azure resources."
33
type = string
4-
default = "local"
4+
default = "funcmi"
55

66
validation {
77
condition = var.prefix == null || length(var.prefix) >= 2
@@ -177,11 +177,10 @@ variable "runtime_name" {
177177
variable "python_version" {
178178
description = "(Optional) Specifies the Python version for the Azure Functions App."
179179
type = string
180-
default = "3.13"
180+
default = "3.12"
181181

182182
validation {
183183
condition = contains([
184-
"3.13",
185184
"3.12",
186185
"3.11",
187186
"3.10",

samples/function-app-storage-http/dotnet/terraform/deploy.sh

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,61 @@
11
#!/bin/bash
22

33
# Variables
4-
PREFIX='user' #system or user
4+
PREFIX='funchttp' #system or user
55
SUFFIX='test'
66
LOCATION='westeurope'
77
CURRENT_DIR="$(cd "$(dirname "$0")" && pwd)"
88
ZIPFILE="function_app.zip"
9-
ENVIRONMENT=$(az account show --query environmentName --output tsv)
109

1110
# Change the current directory to the script's directory
1211
cd "$CURRENT_DIR" || exit
1312

13+
# Determine environment
14+
if command -v az >/dev/null 2>&1; then
15+
CLOUD_NAME=$(az cloud show --query name --output tsv 2>&1 || echo "")
16+
17+
if [[ "$CLOUD_NAME" == "LocalStack" ]]; then
18+
ENVIRONMENT="LocalStack"
19+
elif [[ "$CLOUD_NAME" == "AzureCloud" ]]; then
20+
ENVIRONMENT="AzureCloud"
21+
else
22+
ENVIRONMENT="AzureCloud"
23+
fi
24+
else
25+
ENVIRONMENT="AzureCloud"
26+
fi
27+
1428
# Run terraform init and apply
1529
if [[ $ENVIRONMENT == "LocalStack" ]]; then
16-
echo "Using tflocal and azlocal for LocalStack emulator environment and ."
30+
echo "Using tflocal and azlocal for LocalStack emulator environment."
1731
TERRAFORM="tflocal"
32+
33+
# Log Azure auth environment variables before unsetting
34+
echo "[DEBUG] Azure auth env vars before unsetting:"
35+
echo "[DEBUG] ARM_CLIENT_ID=${ARM_CLIENT_ID:-<not set>}"
36+
echo "[DEBUG] ARM_CLIENT_SECRET=${ARM_CLIENT_SECRET:+<set but hidden>}${ARM_CLIENT_SECRET:-<not set>}"
37+
echo "[DEBUG] ARM_TENANT_ID=${ARM_TENANT_ID:-<not set>}"
38+
echo "[DEBUG] ARM_SUBSCRIPTION_ID=${ARM_SUBSCRIPTION_ID:-<not set>}"
39+
echo "[DEBUG] AZURE_CLIENT_ID=${AZURE_CLIENT_ID:-<not set>}"
40+
echo "[DEBUG] AZURE_TENANT_ID=${AZURE_TENANT_ID:-<not set>}"
41+
42+
echo "[DEBUG] Azure auth env vars after unsetting: all cleared"
1843
AZ="azlocal"
1944
else
2045
echo "Using standard terraform and az for AzureCloud environment."
2146
TERRAFORM="terraform"
2247
AZ="az"
2348
fi
2449

50+
echo "[DEBUG] Cloud name: '$CLOUD_NAME', Environment: '$ENVIRONMENT', Tools: TERRAFORM=$TERRAFORM, AZ=$AZ"
51+
echo "[DEBUG] TERRAFORM command location: $(which $TERRAFORM 2>/dev/null || echo 'not found')"
52+
53+
# Enable Terraform debug logging
54+
export TF_LOG=DEBUG
55+
export TF_LOG_PATH="$CURRENT_DIR/terraform-debug.log"
56+
echo "[DEBUG] Checking what tflocal does..."echo "[DEBUG] tflocal version: $($TERRAFORM version 2>&1 | head -1)"echo "[DEBUG] Contents of current directory before init:"ls -la . 2>&1 | head -20
57+
echo "[DEBUG] Terraform debug logging enabled: TF_LOG=DEBUG, TF_LOG_PATH=$TF_LOG_PATH"
58+
2559
echo "Initializing Terraform..."
2660
$TERRAFORM init -upgrade
2761

@@ -34,6 +68,11 @@ $TERRAFORM plan -out=tfplan \
3468

3569
if [[ $? != 0 ]]; then
3670
echo "Terraform plan failed. Exiting."
71+
echo "============================================================"
72+
echo "Last 100 lines of Terraform debug log:"
73+
echo "============================================================"
74+
tail -100 "$TF_LOG_PATH" 2>/dev/null || echo "Debug log not found"
75+
echo "============================================================"
3776
exit 1
3877
fi
3978

@@ -47,8 +86,8 @@ if [[ $? != 0 ]]; then
4786
fi
4887

4988
# Get the output values
50-
RESOURCE_GROUP_NAME=$(terraform output -raw resource_group_name)
51-
FUNCTION_APP_NAME=$(terraform output -raw function_app_name)
89+
RESOURCE_GROUP_NAME=$($TERRAFORM output -raw resource_group_name)
90+
FUNCTION_APP_NAME=$($TERRAFORM output -raw function_app_name)
5291

5392
# Print the variables
5493
echo "Resource Group: $RESOURCE_GROUP_NAME"
@@ -71,8 +110,12 @@ cd .. || exit
71110

72111
# Deploy the function app using the zip file
73112
echo "Deploying function app [$FUNCTION_APP_NAME]..."
74-
$AZ functionapp deploy \
113+
if $AZ functionapp deploy \
75114
--resource-group "$RESOURCE_GROUP_NAME" \
76115
--name "$FUNCTION_APP_NAME" \
77116
--src-path $ZIPFILE \
78-
--type zip 1> /dev/null
117+
--type zip 1> /dev/null; then
118+
echo "Function app [$FUNCTION_APP_NAME] deployed successfully."
119+
else
120+
echo "Warning: Failed to deploy function app [$FUNCTION_APP_NAME]."
121+
fi

samples/function-app-storage-http/dotnet/terraform/main.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Local Variables
22
locals {
3+
resource_group_name = "${var.prefix}-rg"
34
storage_account_name = "${var.prefix}storage${var.suffix}"
45
app_service_plan_name = "${var.prefix}-app-service-plan-${var.suffix}"
56
function_app_name = "${var.prefix}-functionapp-${var.suffix}"
@@ -8,7 +9,7 @@ locals {
89
# Create a resource group
910
resource "azurerm_resource_group" "example" {
1011
location = var.location
11-
name = var.resource_group_name
12+
name = local.resource_group_name
1213
tags = var.tags
1314
}
1415

0 commit comments

Comments
 (0)