From 42eaa689eda756fa795a69a941e584f67351e1bc Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:58:06 -0600 Subject: [PATCH 01/11] Add provider configuration for Azure in Terraform - approach 2 --- .../terraform-infrastructure/provider.tf | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 scenario2-optimized/terraform-infrastructure/provider.tf diff --git a/scenario2-optimized/terraform-infrastructure/provider.tf b/scenario2-optimized/terraform-infrastructure/provider.tf new file mode 100644 index 0000000..6dfce2e --- /dev/null +++ b/scenario2-optimized/terraform-infrastructure/provider.tf @@ -0,0 +1,25 @@ +# provider.tf +# This file configures the Azure provider to interact with Azure resources. +# It specifies the required provider and its version, along with provider-specific configurations. + +terraform { + required_version = ">= 1.8, < 2.0" + # Specify the required provider and its version + required_providers { + azurerm = { + source = "hashicorp/azurerm" # Source of the AzureRM provider + version = "~> 4.16.0" # Version of the AzureRM provider + } + } +} + +provider "azurerm" { + features { # Enable features for the AzureRM provider + key_vault { + recover_soft_deleted_key_vaults = false + purge_soft_delete_on_destroy = true + } + } + + subscription_id = var.subscription_id +} From dcb1a42d933725fe90f941b1978faeff968f1491 Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:22:22 -0600 Subject: [PATCH 02/11] Add Random provider to Terraform configuration --- scenario2-optimized/terraform-infrastructure/provider.tf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scenario2-optimized/terraform-infrastructure/provider.tf b/scenario2-optimized/terraform-infrastructure/provider.tf index 6dfce2e..a67ce60 100644 --- a/scenario2-optimized/terraform-infrastructure/provider.tf +++ b/scenario2-optimized/terraform-infrastructure/provider.tf @@ -10,6 +10,10 @@ terraform { source = "hashicorp/azurerm" # Source of the AzureRM provider version = "~> 4.16.0" # Version of the AzureRM provider } + random = { + source = "hashicorp/random" # Source of the Random provider + version = "~> 3.5.0" # Version of the Random provider + } } } From f76a0d3cc9f2d39a9f615c54a909d098b589e5f3 Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:23:04 -0600 Subject: [PATCH 03/11] Add outputs for Terraform deployment This file defines various outputs for the Terraform deployment, including resource group name, function app name, and storage account names. --- .../terraform-infrastructure/outputs.tf | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 scenario2-optimized/terraform-infrastructure/outputs.tf diff --git a/scenario2-optimized/terraform-infrastructure/outputs.tf b/scenario2-optimized/terraform-infrastructure/outputs.tf new file mode 100644 index 0000000..c8a75d9 --- /dev/null +++ b/scenario2-optimized/terraform-infrastructure/outputs.tf @@ -0,0 +1,68 @@ +# outputs.tf +# This file contains the outputs from the Terraform deployment for the optimized scenario + +output "resource_group_name" { + value = azurerm_resource_group.rg.name + description = "The name of the resource group" +} + +output "function_app_name" { + value = azurerm_windows_function_app.function_app.name + description = "The name of the function app" +} + +output "function_app_default_hostname" { + value = azurerm_windows_function_app.function_app.default_hostname + description = "The default hostname of the function app" +} + +output "runtime_storage_account_name" { + value = data.azurerm_storage_account.runtime.name + description = "The name of the runtime storage account" +} + +output "data_storage_account_name" { + value = data.azurerm_storage_account.storage.name + description = "The name of the data storage account" +} + +output "application_insights_name" { + value = azurerm_application_insights.appinsights.name + description = "The name of the Application Insights instance" +} + +output "application_insights_instrumentation_key" { + value = azurerm_application_insights.appinsights.instrumentation_key + description = "The instrumentation key of the Application Insights instance" + sensitive = true +} + +output "sql_server_name" { + value = azurerm_mssql_server.sql_server.name + description = "The name of the SQL server" +} + +output "sql_server_fqdn" { + value = azurerm_mssql_server.sql_server.fully_qualified_domain_name + description = "The fully qualified domain name of the SQL server" +} + +output "sql_database_name" { + value = azurerm_mssql_database.sql_db.name + description = "The name of the SQL database" +} + +output "key_vault_name" { + value = azurerm_key_vault.kv.name + description = "The name of the Key Vault" +} + +output "key_vault_uri" { + value = azurerm_key_vault.kv.vault_uri + description = "The URI of the Key Vault" +} + +output "log_analytics_workspace_name" { + value = azurerm_log_analytics_workspace.loganalytics.name + description = "The name of the Log Analytics Workspace" +} From adfc6ddfefe9f43b61effdf290be3f4dd09560d2 Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:27:21 -0600 Subject: [PATCH 04/11] Add Terraform configuration for optimized Azure setup This Terraform configuration sets up an optimized Azure infrastructure, including resource groups, storage accounts, function apps, SQL databases, and access policies, with a focus on minimal disk write access and efficient performance. --- .../terraform-infrastructure/main.tf | 391 ++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100644 scenario2-optimized/terraform-infrastructure/main.tf diff --git a/scenario2-optimized/terraform-infrastructure/main.tf b/scenario2-optimized/terraform-infrastructure/main.tf new file mode 100644 index 0000000..f8d54ac --- /dev/null +++ b/scenario2-optimized/terraform-infrastructure/main.tf @@ -0,0 +1,391 @@ +# main.tf +# Scenario 2: Optimized Mounted Deployment with Minimal Disk Write Access +# Test best practices for efficient disk usage and performance + +# Get current client configuration +data "azurerm_client_config" "current" {} + +# Resource Group +resource "azurerm_resource_group" "rg" { + name = var.resource_group_name + location = var.location + tags = { + Environment = var.environment + Scenario = "Optimized" + } + + # Output the resource group name + provisioner "local-exec" { + command = "echo Resource Group: ${self.name}" + } +} + +# Storage Account for Function App Runtime using Azure CLI +locals { + runtime_storage_name = "struntime${var.resource_suffix}" +} + +resource "null_resource" "runtime_storage_account" { + # Create storage account using Azure CLI + provisioner "local-exec" { + command = "az storage account create --name ${local.runtime_storage_name} --resource-group ${azurerm_resource_group.rg.name} --location eastus2 --sku Standard_LRS --https-only true --min-tls-version TLS1_2" + } + + depends_on = [azurerm_resource_group.rg] +} + +# Use data source to get info about the created storage account +data "azurerm_storage_account" "runtime" { + name = local.runtime_storage_name + resource_group_name = azurerm_resource_group.rg.name + + depends_on = [null_resource.runtime_storage_account] +} + +# Storage Account for Data using Azure CLI +locals { + data_storage_name = "${var.base_data_storage_name}${var.resource_suffix}" +} + +resource "null_resource" "data_storage_account" { + # Create storage account using Azure CLI + provisioner "local-exec" { + command = "az storage account create --name ${local.data_storage_name} --resource-group ${azurerm_resource_group.rg.name} --location eastus2 --sku Standard_LRS --https-only true --min-tls-version TLS1_2" + } + + depends_on = [azurerm_resource_group.rg] +} + +# Use data source to get info about the created storage account +data "azurerm_storage_account" "storage" { + name = local.data_storage_name + resource_group_name = azurerm_resource_group.rg.name + + depends_on = [null_resource.data_storage_account] +} + +# Blob Container for Output Files - create with Azure CLI +resource "null_resource" "output_container" { + # Create blob container using Azure CLI + provisioner "local-exec" { + command = "az storage container create --name output --account-name ${local.data_storage_name} --auth-mode login" + } + + depends_on = [null_resource.data_storage_account, data.azurerm_storage_account.storage] +} + +# Service Plan +resource "azurerm_service_plan" "asp" { + name = "${var.base_service_plan_name}${var.resource_suffix}" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + os_type = "Windows" + sku_name = "P1v3" + + depends_on = [azurerm_resource_group.rg] + + # Output the service plan name + provisioner "local-exec" { + command = "echo Service Plan: ${self.name}" + } +} + +# Log Analytics Workspace +resource "azurerm_log_analytics_workspace" "loganalytics" { + name = "${var.base_log_analytics_name}${var.resource_suffix}" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + sku = "PerGB2018" + retention_in_days = 30 + + depends_on = [azurerm_resource_group.rg] + + # Output the log analytics workspace name + provisioner "local-exec" { + command = "echo Log Analytics Workspace: ${self.name}" + } +} + +# Application Insights - With sampling enabled for optimized scenario +resource "azurerm_application_insights" "appinsights" { + name = "${var.base_app_insights_name}${var.resource_suffix}" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + application_type = "web" + sampling_percentage = 5 # Enable sampling - optimized for low disk usage + workspace_id = azurerm_log_analytics_workspace.loganalytics.id + + depends_on = [azurerm_log_analytics_workspace.loganalytics] + + provisioner "local-exec" { + command = "echo Application Insights: ${self.name}" + } +} + +# Key Vault +resource "azurerm_key_vault" "kv" { + name = "${var.base_key_vault_name}${var.resource_suffix}" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "standard" + soft_delete_retention_days = 7 + purge_protection_enabled = false + + access_policy { + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id + + secret_permissions = [ + "Get", "List", "Set", "Delete", "Purge" + ] + } + + depends_on = [azurerm_resource_group.rg] + + # Output the key vault name + provisioner "local-exec" { + command = "echo Key Vault: ${self.name}" + } +} + +# Generate a random SQL admin password +resource "random_password" "sql_admin_password" { + length = var.sql_password_length + special = true + override_special = "!#$%&*()-_=+[]{}<>:?" + min_lower = 1 + min_upper = 1 + min_numeric = 1 + min_special = 1 +} + +# Store SQL admin password in Key Vault +resource "azurerm_key_vault_secret" "sql_admin_password" { + name = "sql-admin-password" + value = random_password.sql_admin_password.result + key_vault_id = azurerm_key_vault.kv.id + + depends_on = [ + azurerm_key_vault.kv, + random_password.sql_admin_password + ] +} + +# SQL Server +resource "azurerm_mssql_server" "sql_server" { + name = "${var.base_sql_server_name}${var.resource_suffix}" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + version = "12.0" + administrator_login = var.sql_server_admin_login + administrator_login_password = random_password.sql_admin_password.result + + tags = { + Environment = var.environment + Scenario = "Optimized" + } + + depends_on = [ + random_password.sql_admin_password + ] +} + +# SQL Database +resource "azurerm_mssql_database" "sql_db" { + name = var.sql_database_name + server_id = azurerm_mssql_server.sql_server.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "Basic" + max_size_gb = 2 + + tags = { + Environment = var.environment + Scenario = "Optimized" + } +} + +# Store SQL connection string in Key Vault +resource "azurerm_key_vault_secret" "sql_connection_string" { + name = "sql-connection-string" + value = "Server=tcp:${azurerm_mssql_server.sql_server.fully_qualified_domain_name},1433;Initial Catalog=${azurerm_mssql_database.sql_db.name};Persist Security Info=False;User ID=${var.sql_server_admin_login};Password=${random_password.sql_admin_password.result};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;" + key_vault_id = azurerm_key_vault.kv.id + + depends_on = [ + azurerm_mssql_server.sql_server, + azurerm_mssql_database.sql_db, + random_password.sql_admin_password + ] +} + +# SQL Firewall rule to allow Azure services +resource "azurerm_mssql_firewall_rule" "allow_azure_services" { + name = "AllowAzureServices" + server_id = azurerm_mssql_server.sql_server.id + start_ip_address = "0.0.0.0" + end_ip_address = "0.0.0.0" +} + +# Windows Function App - Optimized for mounted package deployment +resource "azurerm_windows_function_app" "function_app" { + name = "${var.base_function_app_name}${var.resource_suffix}" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.asp.id + + # Use the runtime storage account for Function App requirements + storage_account_name = data.azurerm_storage_account.runtime.name + storage_uses_managed_identity = true + + identity { + type = "SystemAssigned" + } + + site_config { + application_stack { + dotnet_version = "v6.0" # .NET 6 + } + + ftps_state = "FtpsOnly" + + # Health check path with eviction time + health_check_path = "/api/health" + health_check_eviction_time_in_min = 10 + + # Pre-warmed instance count + pre_warmed_instance_count = 1 + } + + # App settings for optimized scenario + app_settings = { + "FUNCTIONS_WORKER_RUNTIME" = "dotnet" + "FUNCTIONS_EXTENSION_VERSION" = "~4" + + # Use mounted package deployment for optimized disk usage + "WEBSITE_RUN_FROM_PACKAGE" = "1" + + # Disable detailed diagnostics for better performance + "WEBSITE_ENABLE_DETAILED_DIAGNOSTICS" = "false" + + # Set minimal logging + "AzureFunctionsJobHost__logging__LogLevel__Default" = "Warning" + + # Use managed identity for storage access + "AzureWebJobsStorage__accountName" = data.azurerm_storage_account.runtime.name + + # Disable dashboard logging to storage + "AzureWebJobsDashboard" = "" + + # SQL connection string - Reference to Key Vault + "SqlConnectionString" = "@Microsoft.KeyVault(SecretUri=${azurerm_key_vault_secret.sql_connection_string.id})" + + # Application Insights settings + "APPINSIGHTS_INSTRUMENTATIONKEY" = azurerm_application_insights.appinsights.instrumentation_key + "APPLICATIONINSIGHTS_CONNECTION_STRING" = azurerm_application_insights.appinsights.connection_string + "ApplicationInsights:SamplingTelemetry" = "true" + "ApplicationInsights:SamplingPercentage" = "5" + + # Disable SCM separation for better performance + "WEBSITE_DISABLE_SCM_SEPARATION" = "true" + + # Disable temp file access for better performance + "WEBSITE_ENABLE_TEMP_ACCESS" = "false" + + # Key Vault reference + "AZURE_KEY_VAULT_ENDPOINT" = azurerm_key_vault.kv.vault_uri + + # Data storage connection settings + "DataStorageConnection__accountName" = data.azurerm_storage_account.storage.name + } + + # Ensure dependent resources are provisioned before the function app + depends_on = [ + azurerm_resource_group.rg, + null_resource.runtime_storage_account, + data.azurerm_storage_account.runtime, + null_resource.data_storage_account, + data.azurerm_storage_account.storage, + azurerm_service_plan.asp, + azurerm_application_insights.appinsights, + azurerm_key_vault.kv + ] + + # Allow WEBSITE_RUN_FROM_PACKAGE to be updated after creation + lifecycle { + ignore_changes = [] + } +} + +# Grant the Function App's managed identity access to Key Vault +resource "azurerm_key_vault_access_policy" "function_app_policy" { + key_vault_id = azurerm_key_vault.kv.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = azurerm_windows_function_app.function_app.identity[0].principal_id + + secret_permissions = [ + "Get", "List" + ] + + depends_on = [ + azurerm_windows_function_app.function_app, + azurerm_key_vault.kv + ] +} + +# Grant the Function App's managed identity access to Runtime Storage +resource "azurerm_role_assignment" "function_runtime_storage_blob_data" { + scope = data.azurerm_storage_account.runtime.id + role_definition_name = "Storage Blob Data Contributor" + principal_id = azurerm_windows_function_app.function_app.identity[0].principal_id + + depends_on = [ + azurerm_windows_function_app.function_app, + data.azurerm_storage_account.runtime + ] +} + +resource "azurerm_role_assignment" "function_runtime_storage_queue_data" { + scope = data.azurerm_storage_account.runtime.id + role_definition_name = "Storage Queue Data Contributor" + principal_id = azurerm_windows_function_app.function_app.identity[0].principal_id + + depends_on = [ + azurerm_windows_function_app.function_app, + data.azurerm_storage_account.runtime + ] +} + +resource "azurerm_role_assignment" "function_runtime_storage_table_data" { + scope = data.azurerm_storage_account.runtime.id + role_definition_name = "Storage Table Data Contributor" + principal_id = azurerm_windows_function_app.function_app.identity[0].principal_id + + depends_on = [ + azurerm_windows_function_app.function_app, + data.azurerm_storage_account.runtime + ] +} + +# Grant the Function App's managed identity access to Data Storage +resource "azurerm_role_assignment" "function_data_storage_blob_data" { + scope = data.azurerm_storage_account.storage.id + role_definition_name = "Storage Blob Data Contributor" + principal_id = azurerm_windows_function_app.function_app.identity[0].principal_id + + depends_on = [ + azurerm_windows_function_app.function_app, + data.azurerm_storage_account.storage + ] +} + +resource "azurerm_role_assignment" "function_data_storage_queue_data" { + scope = data.azurerm_storage_account.storage.id + role_definition_name = "Storage Queue Data Contributor" + principal_id = azurerm_windows_function_app.function_app.identity[0].principal_id + + depends_on = [ + azurerm_windows_function_app.function_app, + data.azurerm_storage_account.storage + ] +} + From 8d09dd962a2d5803929b69df2d69fb104c149904 Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:28:49 -0600 Subject: [PATCH 05/11] Add variables for Azure infrastructure setup Defines various variables for Azure infrastructure configuration, including subscription ID, resource group name, location, and storage account settings. --- .../terraform-infrastructure/variables.tf | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 scenario2-optimized/terraform-infrastructure/variables.tf diff --git a/scenario2-optimized/terraform-infrastructure/variables.tf b/scenario2-optimized/terraform-infrastructure/variables.tf new file mode 100644 index 0000000..933f95c --- /dev/null +++ b/scenario2-optimized/terraform-infrastructure/variables.tf @@ -0,0 +1,130 @@ +variable "subscription_id" { + type = string + description = "Azure subscription ID" +} + +variable "resource_group_name" { + type = string + description = "Name of the resource group" + default = "rg-func-optimized" +} + +variable "location" { + type = string + description = "Azure region for resources" + default = "West US" +} + +variable "environment" { + type = string + description = "Environment name" + default = "dev" +} + +variable "storage_account_tier" { + type = string + description = "Storage account tier" + default = "Standard" +} + +variable "storage_account_replication_type" { + type = string + description = "Storage account replication type" + default = "LRS" +} + +variable "app_service_plan_tier" { + type = string + description = "App Service Plan tier (PremiumV3 tier for high performance)" + default = "P1v3" +} + +variable "app_service_plan_size" { + type = string + description = "App Service Plan size (PremiumV3 tier for high performance)" + default = "P1v3" +} + +variable "sql_server_admin_login" { + type = string + description = "SQL Server admin login" + default = "sqladmin" +} + +# Configuration for auto-generated SQL password +variable "sql_password_length" { + type = number + description = "Length of the automatically generated SQL password" + default = 24 +} + +variable "sql_database_name" { + type = string + description = "SQL Database name" + default = "funcdb" +} + +# Optional: provide an existing storage account name to avoid creating a new one +variable "override_storage_account_name" { + type = string + description = "If set, use this existing storage account name instead of creating a new one" + default = "" +} + +# Optional: provide the access key for the existing storage account (sensitive) +variable "override_storage_account_key" { + type = string + description = "If set, use this storage account access key instead of the created account's key" + sensitive = true + default = "" +} + +# Optional: if you already have an App Service Plan in-region, set its resource id here to avoid creating one +variable "existing_service_plan_id" { + type = string + description = "Resource ID of an existing App Service Plan to use instead of creating a new one" + default = "" +} + +# Resource name suffix for demo environments +variable "resource_suffix" { + description = "Suffix to append to all resource names for uniqueness." + type = string +} + +# Base names for resources (optional, for further flexibility) +variable "base_service_plan_name" { + description = "Base name for the service plan." + type = string + default = "asp-optimized" +} +variable "base_app_insights_name" { + description = "Base name for Application Insights." + type = string + default = "appi-optimized" +} +variable "base_log_analytics_name" { + description = "Base name for Log Analytics Workspace." + type = string + default = "log-optimized" +} +variable "base_key_vault_name" { + description = "Base name for Key Vault." + type = string + default = "kv-optimized" +} +variable "base_sql_server_name" { + description = "Base name for SQL Server." + type = string + default = "sql-optimized" +} +variable "base_function_app_name" { + description = "Base name for Function App." + type = string + default = "func-optimized" +} +variable "base_data_storage_name" { + description = "Base name for Data Storage Account." + type = string + default = "stoptimized" +} From 2b0318a91be14de777f4c47cd7a5a26ef7629b24 Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:29:46 -0600 Subject: [PATCH 06/11] Add terraform.tfvars for variable configuration This file contains variable values for Terraform configuration, including subscription ID, resource group name, location, environment, and resource suffix. --- .../terraform-infrastructure/terraform.tfvars | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 scenario2-optimized/terraform-infrastructure/terraform.tfvars diff --git a/scenario2-optimized/terraform-infrastructure/terraform.tfvars b/scenario2-optimized/terraform-infrastructure/terraform.tfvars new file mode 100644 index 0000000..ea49cdf --- /dev/null +++ b/scenario2-optimized/terraform-infrastructure/terraform.tfvars @@ -0,0 +1,10 @@ +# terraform.tfvars +# This file contains the values for the variables defined in variables.tf +# Sample values +subscription_id = "your-subscription-id" # Replace with your actual subscription ID +resource_group_name = "RG-FA-optimizedx3" # Desired resource group name +location = "West US 2" # Desired location +environment = "dev" # Desired environment tag +# SQL credentials are automatically generated and stored in Key Vault +# SQL password is auto-generated securely and stored in Key Vault secret "sql-admin-password" +resource_suffix = "x3x" # Unique suffix for resource names to avoid conflicts (used for demos) From 49b6849ffe2a87a47b5f25d66b0aef8ea1e10ab2 Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:31:40 -0600 Subject: [PATCH 07/11] Add README for Azure Infrastructure Terraform setup Added a comprehensive README for Azure Infrastructure Terraform template, covering prerequisites, overview, and execution steps. --- .../terraform-infrastructure/README.md | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 scenario2-optimized/terraform-infrastructure/README.md diff --git a/scenario2-optimized/terraform-infrastructure/README.md b/scenario2-optimized/terraform-infrastructure/README.md new file mode 100644 index 0000000..96d6ae2 --- /dev/null +++ b/scenario2-optimized/terraform-infrastructure/README.md @@ -0,0 +1,132 @@ +# Azure Infrastructure Terraform Template + +Costa Rica + +[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/) +[brown9804](https://github.com/brown9804) + +Last updated: 2025-06-04 + +---------- + +
+Table of content (Click to expand) + +- [Prerequisites](#prerequisites) +- [Overview](#overview) +- [How to execute it](#how-to-execute-it) + +
+ +## Prerequisites + +- An `Azure subscription is required`. All other resources, including instructions for creating a Resource Group, are provided in this workshop. +- `Contributor role assigned or any custom role that allows`: access to manage all resources, and the ability to deploy resources within subscription. +- If you choose to use the Terraform approach, please ensure that: + - [Terraform is installed on your local machine](https://developer.hashicorp.com/terraform/tutorials/azure-get-started/install-cli#install-terraform). + - [Install the Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) to work with both Terraform and Azure commands. + +## Overview + +
+ Centered Image +
+ +
+ Centered Image +
+ +> Templates structure: + +``` +. +├── README.md +├────── main.tf +├────── variables.tf +├────── provider.tf +├────── terraform.tfvars +├────── outputs.tf +``` + +- main.tf `(Main Terraform configuration file)`: This file contains the core infrastructure code. It defines the resources you want to create, such as virtual machines, networks, and storage. It's the primary file where you describe your infrastructure in a declarative manner. +- variables.tf `(Variable definitions)`: This file is used to define variables that can be used throughout your Terraform configuration. By using variables, you can make your configuration more flexible and reusable. For example, you can define variables for resource names, sizes, and other parameters that might change between environments. +- provider.tf `(Provider configurations)`: Providers are plugins that Terraform uses to interact with cloud providers, SaaS providers, and other APIs. This file specifies which providers (e.g., AWS, Azure, Google Cloud) you are using and any necessary configuration for them, such as authentication details. +- terraform.tfvars `(Variable values)`: This file contains the actual values for the variables defined in `variables.tf`. By separating variable definitions and values, you can easily switch between different sets of values for different environments (e.g., development, staging, production) without changing the main configuration files. +- outputs.tf `(Output values)`: This file defines the output values that Terraform should return after applying the configuration. Outputs are useful for displaying information about the resources created, such as IP addresses, resource IDs, and other important details. They can also be used as inputs for other Terraform configurations or scripts. + +## How to execute it + +```mermaid +graph TD; + A[az login] --> B(terraform init) + B --> C{Terraform provisioning stage} + C -->|Review| D[terraform plan] + C -->|Order Now| E[terraform apply] + C -->|Delete Resource if needed| F[terraform destroy] +``` + +> [!IMPORTANT] +> Please modify `terraform.tfvars` with your information, then run the following flow. If you need more visual guidance, please check the video that illustrates the provisioning steps. + +1. **Login to Azure**: This command logs you into your Azure account. It opens a browser window where you can enter your Azure credentials. Once logged in, you can manage your Azure resources from the command line. + + > Go to the path where Terraform files are located: + + ```sh + cd scenario1-high-decay/terraform-infrastructure + ``` + + ```sh + az login + ``` + + img + + img + +2. **Initialize Terraform**: Initializes the working directory containing the Terraform configuration files. It downloads the necessary provider plugins and sets up the backend for storing the state. + + ``` sh + terraform init + ``` + + img + +3. **Terraform Provisioning Stage**: + + - **Review**: Creates an execution plan, showing what actions Terraform will take to achieve the desired state defined in your configuration files. It uses the variable values specified in `terraform.tfvars`. + + ```sh + terraform plan -var-file terraform.tfvars + ``` + + > At the end, you will see a message in green if everything was executed successfully: + + Screenshot 2025-03-18 145143 + + - **Order Now**: Applies the changes required to reach the desired state of the configuration. It prompts for confirmation before making any changes. It also uses the variable values specified in `terraform.tfvars`. + + ```sh + terraform apply -var-file terraform.tfvars + ``` + + > At the end, you will see a message in green if everything was executed successfully: + + image + + - **Remove**: Destroys the infrastructure managed by Terraform. It prompts for confirmation before deleting any resources. It also uses the variable values specified in `terraform.tfvars`. + + ```sh + terraform destroy -var-file terraform.tfvars + ``` + + > At the end, you will see a message in green if everything was executed successfully: + + image + + +
+ Total views +

Refresh Date: 2025-09-05

+
+ From 9a76a24eaf186f7fabc7a8066b9e87916a2041af Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:35:47 -0600 Subject: [PATCH 08/11] Fix image links and update Terraform directory path Updated image sources in README and corrected directory path for Terraform files. --- scenario2-optimized/terraform-infrastructure/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scenario2-optimized/terraform-infrastructure/README.md b/scenario2-optimized/terraform-infrastructure/README.md index 96d6ae2..05242d9 100644 --- a/scenario2-optimized/terraform-infrastructure/README.md +++ b/scenario2-optimized/terraform-infrastructure/README.md @@ -29,11 +29,11 @@ Last updated: 2025-06-04 ## Overview
- Centered Image + Centered Image
- Centered Image + Centered Image
> Templates structure: @@ -73,7 +73,7 @@ graph TD; > Go to the path where Terraform files are located: ```sh - cd scenario1-high-decay/terraform-infrastructure + cd scenario2-optimized/terraform-infrastructure ``` ```sh From d06a8396e342dd89714e5f303200a5bbf67d6a06 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 5 Sep 2025 21:37:23 +0000 Subject: [PATCH 09/11] Update last modified date in Markdown files --- scenario2-optimized/terraform-infrastructure/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scenario2-optimized/terraform-infrastructure/README.md b/scenario2-optimized/terraform-infrastructure/README.md index 05242d9..afbee97 100644 --- a/scenario2-optimized/terraform-infrastructure/README.md +++ b/scenario2-optimized/terraform-infrastructure/README.md @@ -5,7 +5,7 @@ Costa Rica [![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/) [brown9804](https://github.com/brown9804) -Last updated: 2025-06-04 +Last updated: 2025-09-05 ---------- From ecbbca8db8dc6a547f7ddeed5a3ae2808c81c7f4 Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:38:57 -0600 Subject: [PATCH 10/11] Refactor visitor counter GitHub Actions workflow Refactor commit and push logic for visitor counter updates to handle both PR and non-PR events more efficiently. --- .github/workflows/use-visitor-counter.yml | 42 ++++++++++------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/.github/workflows/use-visitor-counter.yml b/.github/workflows/use-visitor-counter.yml index b865948..973fb24 100644 --- a/.github/workflows/use-visitor-counter.yml +++ b/.github/workflows/use-visitor-counter.yml @@ -21,6 +21,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + ref: ${{ github.head_ref || github.ref_name }} - name: Shallow clone visitor counter logic run: git clone --depth=1 https://github.com/brown9804/github-visitor-counter.git @@ -57,30 +58,23 @@ jobs: git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" - # Commit and push logic for PR events (merge, not rebase) - - name: Commit and push changes (PR) - if: github.event_name == 'pull_request' + - name: Commit and merge changes env: - TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_BRANCH: ${{ github.head_ref || github.ref_name }} + GIT_AUTHOR_NAME: github-actions[bot] + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com run: | - git fetch origin - git checkout ${{ github.head_ref }} - git pull origin ${{ github.head_ref }} || echo "No merge needed" + # Ensure we're on the correct branch + git switch -c "$PR_BRANCH" || git switch "$PR_BRANCH" + + # Stage and commit changes if any git add -A - git commit -m "Update visitor count" || echo "No changes to commit" - git remote set-url origin https://x-access-token:${TOKEN}@github.com/${{ github.repository }} - git push origin HEAD:${{ github.head_ref }} - - # Commit and push logic for non-PR events (merge, not rebase) - - name: Commit and push changes (non-PR) - if: github.event_name != 'pull_request' - env: - TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git fetch origin - git checkout ${{ github.ref_name }} || git checkout -b ${{ github.ref_name }} origin/${{ github.ref_name }} - git pull origin ${{ github.ref_name }} || echo "No merge needed" - git add -A - git commit -m "Update visitor count" || echo "No changes to commit" - git remote set-url origin https://x-access-token:${TOKEN}@github.com/${{ github.repository }} - git push origin HEAD:${{ github.ref_name }} + git diff --staged --quiet || git commit -m "Update visitor count" + + # Pull and merge existing changes + git pull origin "$PR_BRANCH" --no-rebase + + # Push all changes + git push origin "$PR_BRANCH" From 4117cfd9b1c84057aa83e037258fa638ae1f12b1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 5 Sep 2025 21:39:16 +0000 Subject: [PATCH 11/11] Update visitor count --- README.md | 2 +- scenario1-high-decay/README.md | 2 +- scenario1-high-decay/terraform-infrastructure/README.md | 2 +- scenario2-optimized/terraform-infrastructure/README.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8ce7337..15180fe 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ Last updated: 2025-08-27
- Total views + Total views

Refresh Date: 2025-09-05

diff --git a/scenario1-high-decay/README.md b/scenario1-high-decay/README.md index 804a108..291a365 100644 --- a/scenario1-high-decay/README.md +++ b/scenario1-high-decay/README.md @@ -135,7 +135,7 @@ Last updated: 2025-08-27
- Total views + Total views

Refresh Date: 2025-09-05

diff --git a/scenario1-high-decay/terraform-infrastructure/README.md b/scenario1-high-decay/terraform-infrastructure/README.md index bddd5de..1d037bc 100644 --- a/scenario1-high-decay/terraform-infrastructure/README.md +++ b/scenario1-high-decay/terraform-infrastructure/README.md @@ -126,7 +126,7 @@ graph TD;
- Total views + Total views

Refresh Date: 2025-09-05

diff --git a/scenario2-optimized/terraform-infrastructure/README.md b/scenario2-optimized/terraform-infrastructure/README.md index afbee97..2d11ce4 100644 --- a/scenario2-optimized/terraform-infrastructure/README.md +++ b/scenario2-optimized/terraform-infrastructure/README.md @@ -126,7 +126,7 @@ graph TD;
- Total views + Total views

Refresh Date: 2025-09-05