diff --git a/README.md b/README.md
index 3f9e9f9..8e9218c 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Costa Rica
[](https://github.com/)
[brown9804](https://github.com/brown9804)
-Last updated: 2025-02-21
+Last updated: 2025-04-15
------------------------------------------
@@ -27,6 +27,80 @@ Last updated: 2025-02-21
+## 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 a 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.
+
+## Infrastructure as Code (IaC)
+
+> Is crucial for modern cloud-based solutions and applications. Here is why:
+
+
+1. Consistency and Reproducibility
+
+ - **Consistent Environments**: IaC ensures that your development, testing, and production environments are consistent. `This reduces the it works on my machine problem` and ensures that applications run reliably across different environments.
+ - **Reproducibility**: With IaC, you can `recreate your infrastructure from scratch in a consistent manner.` This is particularly useful for `disaster recovery and scaling`.
+
+
+
+
+2. Version Control
+
+ - **Source Control**: By storing IaC configurations in version control systems like GitHub, you `can track changes, collaborate with team members, and roll back to previous versions if needed.`
+ - **Change Management**: Version control `provides a history of changes, making it easier to understand what changes were made, who made them, and why.`
+
+
+
+
+3. Flexibility and Options
+
+
+> Microsoft provides several IaC tools, including Terraform, Bicep, and ARM templates. Each tool offers different features and benefits, allowing you to choose the one that best fits your needs.
+
+ - **Terraform**: A popular IaC tool that uses a high-level configuration language to define and provision infrastructure. It `supports multiple cloud providers, making it a versatile choice.`
+ - **Bicep**: A domain-specific language that uses declarative syntax to deploy Azure resources. It offers a `concise and easy-to-read alternative to JSON-based ARM templates.`
+ - **ARM Templates**: JSON files that` define the infrastructure and configuration for your Azure solution.` They provide a detailed and flexible way to manage Azure resources.
+
+
+
+
+4. Enhanced Security
+
+- **Automated Security Policies**: IaC allows you to `define and enforce security policies automatically.` This ensures that security best practices are `consistently applied across all environments.`
+- **Compliance**: IaC helps maintain compliance with `regulatory requirements by providing a clear and auditable trail of infrastructure changes.`
+
+
+
+
+5. Scalability
+
+- **Dynamic Scaling**: IaC enables `dynamic scaling of resources based on demand.` This ensures that your infrastructure can handle varying workloads efficiently.
+- **Resource Optimization**: By automating the `provisioning and de-provisioning of resources,` IaC helps optimize resource usage and reduce costs.
+
+
+
+
+6. Automation
+
+- **Automated Provisioning**: IaC allows you to `automate the provisioning of infrastructure. This reduces manual errors, speeds up deployments, and ensures that infrastructure changes are applied consistently.`
+- **CI/CD Integration**: Integrating IaC with `Continuous Integration/Continuous Deployment (CI/CD) pipelines automates the deployment process, ensuring that infrastructure changes are tested and deployed alongside application code.`
+
+
+
+
+> [!TIP]
+> Just in case, find here some [additional Terraform templates for different Azure resources across different areas](https://github.com/MicrosoftCloudEssentials-LearningHub/AzureTerraformTemplates-v0.0.0).
+
+> E.g [Demonstration: Deploying Azure Resources for a Data Platform](./Terraform)
+
+
Total Visitors
diff --git a/Terraform/README.md b/Terraform/README.md
index 0e7f439..843cc90 100644
--- a/Terraform/README.md
+++ b/Terraform/README.md
@@ -5,7 +5,7 @@ Costa Rica
[](https://github.com/)
[brown9804](https://github.com/brown9804)
-Last updated: 2025-03-13
+Last updated: 2025-04-15
------------------------------------------
@@ -34,6 +34,7 @@ Last updated: 2025-03-13
- [Overview](#overview)
- [Finding admin_principal_id Using Azure CLI](#finding-admin_principal_id-using-azure-cli)
+- [Configure Remote Storage for a Terraform deployment](#configure-remote-storage-for-a-terraform-deployment)
- [How to execute it](#how-to-execute-it)
@@ -78,6 +79,16 @@ Here is an example value for `admin_principal_id` which is Object ID you retriev
admin_principal_id = "12345678-1234-1234-1234-1234567890ab"
```
+## Configure Remote Storage for a Terraform deployment
+
+> To configure remote storage for a Terraform deployment, you need to set up a backend configuration in your Terraform files. This backend configuration specifies where Terraform should store the state file, which keeps track of the resources it manages.
+
+> 1. Create an Azure Storage Account:
+> - Go to the Azure portal and create a new storage account (if you don't have one already).
+> - Note down the storage account name and the access key.
+> 2. Create a Storage Container: Within the storage account, create a new container to store the Terraform state file.
+> 3. Configure Terraform Backend: In your Terraform configuration file (e.g., [remote-storage.tf](./src/remote-storage.tf), add the backend configuration for Azure Blob Storage.
+
## How to execute it
```mermaid
diff --git a/Terraform/microsoft-fabric-basic-resources.drawio b/Terraform/docs/microsoft-fabric-basic-resources.drawio
similarity index 100%
rename from Terraform/microsoft-fabric-basic-resources.drawio
rename to Terraform/docs/microsoft-fabric-basic-resources.drawio
diff --git a/Terraform/src/main.tf b/Terraform/src/main.tf
new file mode 100644
index 0000000..a2be097
--- /dev/null
+++ b/Terraform/src/main.tf
@@ -0,0 +1,104 @@
+# Retrieve the client configuration of the AzureRM provider
+data "azurerm_client_config" "example" {}
+
+# Check the directory object type
+data "azuread_directory_object" "example" {
+ object_id = data.azurerm_client_config.example.object_id
+}
+
+# Get information about the Entra user
+data "azuread_user" "example" {
+ object_id = data.azurerm_client_config.example.object_id
+}
+
+# Local value to determine if the client is a user or not
+locals {
+ fabric_admin = can(data.azuread_directory_object.example.type == "User") ? data.azuread_user.example.user_principal_name : data.azurerm_client_config.example.object_id
+}
+
+# Create a resource group
+resource "azurerm_resource_group" "example" {
+ name = var.resource_group_name # Name of the resource group
+ location = var.location # Location of the resource group
+}
+
+# Create a storage account for remote state
+resource "azurerm_storage_account" "example" {
+ name = var.storage_account_name
+ resource_group_name = azurerm_resource_group.example.name
+ location = azurerm_resource_group.example.location
+ account_tier = "Standard"
+ account_replication_type = "LRS"
+ depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
+}
+
+# Create a storage container for remote state
+resource "azurerm_storage_container" "example" {
+ name = var.container_name
+ storage_account_name = azurerm_storage_account.example.name
+ container_access_type = "private"
+ depends_on = [azurerm_storage_account.example] # Ensure storage account is created first
+}
+
+# Create an MSSQL Server
+resource "azurerm_mssql_server" "example" {
+ name = var.sql_server_name # Name of the SQL Server
+ resource_group_name = azurerm_resource_group.example.name # Resource group name
+ location = azurerm_resource_group.example.location # Location of the SQL Server
+ version = "12.0" # SQL Server version
+ administrator_login = var.admin_username # Administrator username
+ administrator_login_password = var.admin_password # Administrator password
+ depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
+}
+
+# Add a null resource to introduce a delay
+resource "null_resource" "wait_for_sql_server" {
+ depends_on = [azurerm_mssql_server.example]
+
+ provisioner "local-exec" {
+ command = "Start-Sleep -Seconds 60"
+ interpreter = ["PowerShell", "-Command"]
+ }
+}
+
+# Create an MSSQL Database
+resource "azurerm_mssql_database" "example" {
+ name = var.sql_database_name # Name of the SQL Database
+ server_id = azurerm_mssql_server.example.id # ID of the SQL Server
+ sku_name = "Basic" # SKU name for the SQL Database
+ depends_on = [null_resource.wait_for_sql_server] # Ensure SQL Server is fully provisioned first
+}
+
+# Create Microsoft Fabric Capacity
+resource "azurerm_fabric_capacity" "example" {
+ name = "fc${var.solution_name}"
+ resource_group_name = azurerm_resource_group.example.name
+ location = var.location
+
+ administration_members = setunion([local.fabric_admin], var.fabric_capacity_admin_upns)
+
+ sku {
+ name = var.fabric_capacity_sku
+ tier = "Fabric"
+ }
+ depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
+}
+
+# Get the Fabric Capacity details
+data "fabric_capacity" "example" {
+ display_name = azurerm_fabric_capacity.example.name
+
+ lifecycle {
+ postcondition {
+ condition = self.state == "Active"
+ error_message = "Fabric Capacity is not in Active state. Please check the Fabric Capacity status."
+ }
+ }
+}
+
+# Create a Fabric Workspace
+resource "fabric_workspace" "example" {
+ capacity_id = data.fabric_capacity.example.id
+ display_name = "ws-${var.solution_name}"
+ depends_on = [data.fabric_capacity.example] # Ensure Fabric Capacity data source is available first
+}
diff --git a/Terraform/src/outputs.tf b/Terraform/src/outputs.tf
new file mode 100644
index 0000000..41bc404
--- /dev/null
+++ b/Terraform/src/outputs.tf
@@ -0,0 +1,33 @@
+# Output the name of the resource group
+output "resource_group_name" {
+ value = azurerm_resource_group.example.name # The name of the resource group
+}
+
+# Output the name of the storage account
+output "storage_account_name" {
+ value = azurerm_storage_account.example.name # The name of the storage account
+}
+
+# Output the name of the storage container
+output "storage_container_name" {
+ value = azurerm_storage_container.example.name # The name of the storage container
+}
+
+# Output the name of the MSSQL Server
+output "sql_server_name" {
+ value = azurerm_mssql_server.example.name # The name of the SQL Server
+}
+
+# Output the name of the MSSQL Database
+output "sql_database_name" {
+ value = azurerm_mssql_database.example.name # The name of the SQL Database
+}
+
+# Output the name of the Microsoft Fabric Capacity
+output "fabric_capacity_name" {
+ value = azurerm_fabric_capacity.example.name
+}
+
+output "fabric_workspace_name" {
+ value = fabric_workspace.example.display_name
+}
diff --git a/Terraform/src/provider.tf b/Terraform/src/provider.tf
new file mode 100644
index 0000000..b06d72d
--- /dev/null
+++ b/Terraform/src/provider.tf
@@ -0,0 +1,21 @@
+terraform {
+ required_version = ">= 1.8, < 2.0"
+ # Specify the required providers and their versions
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm" # Source of the AzureRM provider
+ version = "~> 4.16.0" # Version of the AzureRM provider
+ }
+ fabric = {
+ source = "microsoft/fabric"
+ version = "0.1.0-beta.7"
+ }
+ }
+}
+
+provider "azurerm" {
+ features {} # Enable all features for the AzureRM provider
+ subscription_id = var.subscription_id # Add your subscription ID here
+}
+
+provider "fabric" {}
diff --git a/Terraform/src/remote-storage.tf b/Terraform/src/remote-storage.tf
new file mode 100644
index 0000000..49c8931
--- /dev/null
+++ b/Terraform/src/remote-storage.tf
@@ -0,0 +1,8 @@
+terraform {
+ backend "azurerm" {
+ resource_group_name = "RGWorkshopUserName" # The name of the resource group for remote state storage
+ storage_account_name = "examplestorageacctworkshop" # The name of the storage account for remote state storage
+ container_name = "tfstate" # The name of the container for remote state storage
+ key = "terraform.tfstate" # The key for the remote state file
+ }
+}
diff --git a/Terraform/src/terraform.tfvars b/Terraform/src/terraform.tfvars
new file mode 100644
index 0000000..0a2575a
--- /dev/null
+++ b/Terraform/src/terraform.tfvars
@@ -0,0 +1,32 @@
+# ----------------------------------
+### Here is some sample data. Please make any necessary modifications.
+# ----------------------------------
+
+# Variable for subscription ID
+subscription_id = "" # Add your subscription id number
+
+# Resource group name
+resource_group_name = "" # Add your desired RG name
+
+# Location of the resources
+location = "Central US"
+
+# SQL Server configuration
+sql_server_name = "usernamesqlserver" # replace username with your name
+admin_username = "adminuser" # replace with your desired user name
+admin_password = "P@ssw0rd1234" # Make sure to use a strong password
+
+# SQL Database name
+sql_database_name = "workshopdbusername" # replace username with your name
+
+# Variables for remote state storage
+storage_account_name = "storageacctworkshop01"
+container_name = "tfstate"
+
+# Variable for administrator principal ID
+admin_principal_id = ""
+
+# Microsoft Fabric Capacity configuration
+solution_name = "capacitynamews" # choose your capacity name
+fabric_capacity_admin_upns = ["user-email-here", "another-user-email-here"]
+fabric_capacity_sku = "F64" # Choose your SKU like F64
diff --git a/Terraform/src/variables.tf b/Terraform/src/variables.tf
new file mode 100644
index 0000000..cc9f6ea
--- /dev/null
+++ b/Terraform/src/variables.tf
@@ -0,0 +1,80 @@
+# Variable for the resource group name
+variable "resource_group_name" {
+ description = "The name of the resource group"
+ type = string
+}
+
+# Variable for the location of the resources
+variable "location" {
+ description = "The location of the resources"
+ type = string
+ default = "East US" # Default location
+}
+
+# Variable for the SQL Server name
+variable "sql_server_name" {
+ description = "The name of the SQL Server"
+ type = string
+}
+
+# Variable for the administrator username for the SQL Server
+variable "admin_username" {
+ description = "The administrator username for the SQL Server"
+ type = string
+}
+
+# Variable for the administrator password for the SQL Server
+variable "admin_password" {
+ description = "The administrator password for the SQL Server"
+ type = string
+ sensitive = true # Mark this variable as sensitive
+}
+
+# Variable for the SQL Database name
+variable "sql_database_name" {
+ description = "The name of the SQL Database"
+ type = string
+}
+
+# Variable for the storage account name
+variable "storage_account_name" {
+ description = "The name of the storage account for remote state storage"
+ type = string
+}
+
+# Variable for the container name
+variable "container_name" {
+ description = "The name of the container for remote state storage"
+ type = string
+}
+
+# Variable for the subscription ID
+variable "subscription_id" {
+ description = "The subscription ID for the Azure account"
+ type = string
+}
+
+# Variable for the administrator principal ID
+variable "admin_principal_id" {
+ description = "The principal ID of the capacity administrator"
+ type = string
+}
+
+# Variable for the SKU name for the Microsoft Fabric Capacity
+variable "fabric_capacity_sku" {
+ description = "The SKU for the Fabric Capacity."
+ type = string
+}
+
+# Variable for the solution name
+variable "solution_name" {
+ description = "The name of the solution."
+ type = string
+}
+
+# Variable for additional UPNs to be added as Fabric Capacity administrators
+variable "fabric_capacity_admin_upns" {
+ description = "Additional UPNs to be added as Fabric Capacity administrators."
+ type = list(string)
+ default = []
+}
diff --git a/Terraform/troubleshooting.md b/Terraform/troubleshooting.md
new file mode 100644
index 0000000..a0182ee
--- /dev/null
+++ b/Terraform/troubleshooting.md
@@ -0,0 +1,180 @@
+# Troubleshooting: Known Errors
+
+Costa Rica
+
+[](https://github.com/)
+[brown9804](https://github.com/brown9804)
+
+Last updated: 2025-04-15
+
+------------------------------------------
+
+## Content
+
+- [Terraform is not recognized](#terraform-is-not-recognized)
+ - [Step 1: Download Terraform](#step-1-download-terraform)
+ - [Step 2: Install Terraform](#step-2-install-terraform)
+ - [For Windows:](#for-windows)
+ - [For macOS:](#for-macos)
+ - [For Linux:](#for-linux)
+ - [Step 3: Verify the Installation](#step-3-verify-the-installation)
+ - [Step 4: Initialize Terraform](#step-4-initialize-terraform)
+- [Resource Group Not Found](#resource-group-not-found)
+- [Resource Not Found](#resource-not-found)
+
+## Terraform is not recognized
+
+> Terraform is not recognized because it's not installed or not added to your system's PATH
+
+```
+terraform : The term 'terraform' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
+spelling of the name, or if a path was included, verify that the path is correct and try again.
+At line:1 char:1
++ terraform init
++ ~~~~~~~~~
+ + CategoryInfo : ObjectNotFound: (terraform:String) [], CommandNotFoundException
+ + FullyQualifiedErrorId : CommandNotFoundException
+```
+
+
+
+
+
+
+### Step 1: Download Terraform
+
+> By command line:
+1. Open your command prompt.
+2. Use curl to download Terraform. Replace VERSION with the desired version number (e.g., 1.1.4):
+
+ ```
+ curl -o terraform.zip https://releases.hashicorp.com/terraform/VERSION/terraform_VERSION_windows_amd64.zip
+ ```
+
+

+
+3. Use tar to extract the ZIP file:
+
+ ```
+ tar -xvf terraform.zip
+ ```
+
+

+
+> By GUI:
+1. Go to the [Terraform download page](https://developer.hashicorp.com/terraform/install).
+2. Download the appropriate package for your operating system (e.g., Windows, macOS, Linux).
+
+

+
+### Step 2: Install Terraform
+
+#### For Windows:
+
+1. Extract the downloaded ZIP file to a directory of your choice (e.g., `C:\terraform`).
+
+

+
+2. Add the directory to your system's PATH:
+
+ > By command line:
`Assuming you have moved terraform.exe to C:\terraform, you can add this directory to the PATH using the following command`
+
+ ```
+ setx PATH "%PATH%;C:\terraform"
+ ```
+
+
+

+
+
+ > By GUI:
+ - Open the Start menu and search for `Environment Variables`.
+ - Click on `Edit the system environment variables`
+
+

+
+ - In the System Properties window, click on `Environment Variables`.
+
+

+
+ - Under `System variables`, find the `Path` variable and click `Edit`.
+ - Click `New` and add the path to the directory where you extracted Terraform (e.g., `C:\terraform`).
+ - Click `OK` to close all windows.
+
+#### For macOS:
+
+1. Open a terminal.
+2. Move the Terraform binary to a directory included in your PATH (e.g., `/usr/local/bin`):
+ ```sh
+ sudo mv ~/Downloads/terraform /usr/local/bin/
+ ```
+3. Ensure the directory is in your PATH by adding the following line to your `~/.bash_profile` or `~/.zshrc` file:
+ ```sh
+ export PATH=$PATH:/usr/local/bin
+ ```
+4. Reload your profile:
+ ```sh
+ source ~/.bash_profile # or source ~/.zshrc
+ ```
+
+#### For Linux:
+
+1. Open a terminal.
+2. Move the Terraform binary to a directory included in your PATH (e.g., `/usr/local/bin`):
+ ```sh
+ sudo mv ~/Downloads/terraform /usr/local/bin/
+ ```
+3. Ensure the directory is in your PATH by adding the following line to your `~/.bashrc` or `~/.profile` file:
+ ```sh
+ export PATH=$PATH:/usr/local/bin
+ ```
+4. Reload your profile:
+ ```sh
+ source ~/.bashrc # or source ~/.profile
+ ```
+
+### Step 3: Verify the Installation
+1. Open a new terminal or command prompt.
+2. Run the following command to verify the installation. You should see the installed version of Terraform.
+
+ ```sh
+ terraform -version
+ ```
+
+### Step 4: Initialize Terraform
+
+Now you can run the `terraform init` command in your project directory:
+
+```sh
+terraform init
+```
+
+## Resource Group Not Found
+
+> Please ensure you create your resource group before running the configuration and deployment. This error occurs because the specified resource group does not exist.
+
+```
+Error: Failed to get existing workspaces: Error retrieving keys for Storage Account "examplestorageacct": storage.AccountsClient#ListKeys: Failure responding to request: StatusCode=404 -- Original Error: autorest/azure: Service returned an error. Status=404 Code="ResourceGroupNotFound" Message="Resource group 'RGWorkshopUserName' could not be found." but I want to create it
+```
+
+
+
+
+
+## Resource Not Found
+
+> Please ensure you create your storage account and container for backend before running the configuration and deployment. This error occurs because the specified storage account does not exist.
+
+```
+Error: Failed to get existing workspaces: Error retrieving keys for Storage Account "examplestorageacct": storage.AccountsClient#ListKeys: Failure responding to request: StatusCode=404 -- Original Error: autorest/azure: Service returned an error. Status=404 Code="ResourceNotFound" Message="The Resource 'Microsoft.Storage/storageAccounts/examplestorageacct' under resource group 'RGWorkshopUserName' was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix"
+```
+
+
+
+
+
+
+
+
Total Visitors
+

+