Skip to content

Commit eb0761f

Browse files
authored
Merge pull request #45 from MicrosoftCloudEssentials-LearningHub/fabric
Fabric
2 parents c6c8219 + a232c34 commit eb0761f

File tree

8 files changed

+362
-2
lines changed

8 files changed

+362
-2
lines changed

5_analytics-bigdata/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Costa Rica
55
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
66
[brown9804](https://github.com/brown9804)
77

8-
Last updated: 2026-02-12
8+
Last updated: 2026-02-16
99

1010
------------------------------------------
1111

@@ -16,6 +16,8 @@ Last updated: 2026-02-12
1616

1717
- [Azure Data Factory](./data-factory)
1818
- [Azure Databricks (Workspace)](./databricks)
19+
- [Azure Event Hubs](./event-hub)
20+
- [Microsoft Fabric (Capacity)](./fabric)
1921
- [Azure Synapse Analytics (Workspace)](./synapse-analytics)
2022

2123
<!-- START BADGE -->
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Terraform Template - Microsoft Fabric (Capacity)
2+
3+
Costa Rica
4+
5+
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
6+
[brown9804](https://github.com/brown9804)
7+
8+
Last updated: 2026-02-16
9+
10+
------------------------------------------
11+
12+
> This template contains Terraform configurations to create a Microsoft Fabric capacity in Azure.
13+
14+
> [!IMPORTANT]
15+
> Fabric capacity creation requires at least one admin member.
16+
>
17+
> - Option A (recommended): set `use_current_user_as_admin = true` and let Terraform resolve the current user UPN.
18+
> - Option B: set `admin_members` explicitly to one or more UPNs like `user@domain.com`.
19+
> To avoid committing identities, prefer environment variables:
20+
> - PowerShell: `$env:TF_VAR_admin_members='["user@domain.com"]'`
21+
> - PowerShell (auto): keep `use_current_user_as_admin = true` and omit `admin_members`.
22+
23+
> [!NOTE]
24+
>
25+
> - The Fabric capacity resource is created via the AzAPI provider using the ARM resource type `Microsoft.Fabric/capacities@2023-11-01`.
26+
> - The Resource Group is created via AzAPI (idempotent ARM PUT) to align with other templates in this repository.
27+
28+
<img width="650" alt="image" src="https://github.com/user-attachments/assets/fb74b695-b13d-4ca1-aae6-d5386e67660a" />
29+
30+
<img width="650" alt="image" src="https://github.com/user-attachments/assets/8bb7c264-8a8f-4c8e-b7d3-62e54d464b62" />
31+
32+
<img width="650" alt="image" src="https://github.com/user-attachments/assets/799fc378-a49a-4c0d-bc6d-3fde6361f5d7" />
33+
34+
## File Descriptions
35+
36+
- **main.tf**: Creates the Resource Group and the Fabric capacity (AzAPI).
37+
- **variables.tf**: Defines the input variables used in the Terraform configuration.
38+
- **provider.tf**: Configures the AzureRM + AzAPI providers.
39+
- **terraform.tfvars**: Example values for the variables defined in `variables.tf`.
40+
- **output.tf**: Defines outputs such as Fabric capacity resource ID.
41+
42+
## Variables
43+
44+
| Variable Name | Description | Type | Example Value |
45+
| --- | --- | --- | --- |
46+
| `resource_group_name` | Resource Group name to create/deploy into. | string | `"rg-analytics-dev-fabric"` |
47+
| `location` | Azure region for the deployment. | string | `"eastus"` |
48+
| `capacity_name` | Base capacity name. If suffix enabled, final is `<base>-<suffix>`. | string | `"fabric-capacity-dev"` |
49+
| `use_current_user_as_admin` | Auto-resolve current user as admin when `admin_members` is empty. | bool | `true` |
50+
| `admin_members` | Optional explicit Fabric capacity admins (UPNs). Overrides auto mode. | list(string) | `[]` |
51+
| `sku_name` | Capacity SKU (for example `F2`, `F4`, `F8`, ...). | string | `"F2"` |
52+
| `sku_tier` | Capacity SKU tier. | string | `"Fabric"` |
53+
| `append_random_suffix` | Append a random suffix to avoid collisions. | bool | `true` |
54+
| `random_suffix_length` | Length of the random suffix when enabled. | number | `6` |
55+
| `tags` | Tags applied to resources. | map(string) | `{ "env": "dev" }` |
56+
57+
## Usage
58+
59+
1. Authenticate:
60+
61+
```sh
62+
az login
63+
az account show
64+
# If needed:
65+
az account set --subscription "<subscription-id-or-name>"
66+
```
67+
68+
2. Initialize:
69+
70+
```sh
71+
terraform init -upgrade
72+
```
73+
74+
3. Validate and plan:
75+
76+
```sh
77+
terraform validate
78+
terraform plan
79+
```
80+
81+
4. Apply:
82+
83+
```sh
84+
terraform apply -auto-approve
85+
```

5_analytics-bigdata/fabric/main.tf

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
data "azurerm_client_config" "current" {}
2+
3+
data "azuread_client_config" "current" {}
4+
5+
data "azuread_user" "current" {
6+
object_id = data.azuread_client_config.current.object_id
7+
}
8+
9+
# Resource group creation is idempotent in ARM (PUT). This will create the RG if it doesn't exist,
10+
# or update tags if it already exists.
11+
resource "azapi_resource" "resource_group" {
12+
type = "Microsoft.Resources/resourceGroups@2022-09-01"
13+
name = var.resource_group_name
14+
location = var.location
15+
parent_id = "/subscriptions/${data.azurerm_client_config.current.subscription_id}"
16+
17+
body = jsonencode({
18+
tags = var.tags
19+
})
20+
21+
response_export_values = [
22+
"id",
23+
"name"
24+
]
25+
}
26+
27+
resource "random_string" "suffix" {
28+
length = var.random_suffix_length
29+
upper = false
30+
special = false
31+
numeric = true
32+
33+
keepers = {
34+
resource_group_name = var.resource_group_name
35+
location = var.location
36+
capacity_base = var.capacity_name
37+
sku_name = var.sku_name
38+
sku_tier = var.sku_tier
39+
}
40+
}
41+
42+
locals {
43+
rg_id = azapi_resource.resource_group.id
44+
suffix = var.append_random_suffix ? random_string.suffix.result : ""
45+
capacity_name = var.append_random_suffix ? "${var.capacity_name}-${local.suffix}" : var.capacity_name
46+
47+
# AzAPI schema validation for Microsoft.Fabric/capacities currently enforces a strict name pattern:
48+
# ^[a-z][a-z0-9]*$
49+
# To keep tfvars friendly (allowing '-' etc.), we sanitize the requested name for the ARM resource name.
50+
capacity_name_sanitized_raw = join("", regexall("[a-z0-9]", lower(local.capacity_name)))
51+
capacity_name_sanitized = can(regex("^[a-z]", local.capacity_name_sanitized_raw)) ? local.capacity_name_sanitized_raw : "fc${local.capacity_name_sanitized_raw}"
52+
53+
admin_members_effective = (
54+
length(var.admin_members) > 0
55+
? var.admin_members
56+
: (var.use_current_user_as_admin ? [data.azuread_user.current.user_principal_name] : [])
57+
)
58+
}
59+
60+
# Microsoft Fabric capacity (ARM resource provider: Microsoft.Fabric)
61+
# API version reference: https://learn.microsoft.com/azure/templates/Microsoft.Fabric/2023-11-01/capacities
62+
resource "azapi_resource" "fabric_capacity" {
63+
type = "Microsoft.Fabric/capacities@2023-11-01"
64+
name = local.capacity_name_sanitized
65+
location = var.location
66+
parent_id = local.rg_id
67+
68+
lifecycle {
69+
precondition {
70+
condition = length(local.admin_members_effective) > 0
71+
error_message = "No Fabric admins configured. Set admin_members (list of UPNs) or enable use_current_user_as_admin to auto-resolve the current user."
72+
}
73+
}
74+
75+
body = jsonencode({
76+
sku = {
77+
name = var.sku_name
78+
tier = var.sku_tier
79+
}
80+
properties = {
81+
administration = {
82+
members = local.admin_members_effective
83+
}
84+
}
85+
tags = var.tags
86+
})
87+
88+
response_export_values = [
89+
"id",
90+
"name"
91+
]
92+
93+
depends_on = [
94+
azapi_resource.resource_group
95+
]
96+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
output "resource_group_id" {
2+
description = "The resource ID of the Resource Group."
3+
value = azapi_resource.resource_group.id
4+
}
5+
6+
output "fabric_capacity_id" {
7+
description = "The resource ID of the Fabric capacity."
8+
value = azapi_resource.fabric_capacity.id
9+
}
10+
11+
output "fabric_capacity_name" {
12+
description = "The name of the Fabric capacity (sanitized ARM resource name)."
13+
value = azapi_resource.fabric_capacity.name
14+
}
15+
16+
output "fabric_capacity_name_requested" {
17+
description = "The requested capacity_name value after suffixing (before sanitization)."
18+
value = local.capacity_name
19+
}
20+
21+
output "fabric_capacity_location" {
22+
description = "The Azure region the Fabric capacity is deployed into."
23+
value = var.location
24+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# provider.tf
2+
# This file configures the Azure provider to interact with Azure resources.
3+
# It specifies the required provider and its version, along with provider-specific configurations.
4+
5+
terraform {
6+
required_version = ">= 1.8, < 2.0"
7+
8+
required_providers {
9+
azurerm = {
10+
source = "hashicorp/azurerm"
11+
version = "~> 3.116"
12+
}
13+
14+
azapi = {
15+
source = "Azure/azapi"
16+
version = "~> 1.13"
17+
}
18+
19+
random = {
20+
source = "hashicorp/random"
21+
version = "~> 3.6"
22+
}
23+
24+
azuread = {
25+
source = "hashicorp/azuread"
26+
version = "~> 3.0"
27+
}
28+
}
29+
}
30+
31+
provider "azurerm" {
32+
features {
33+
resource_group {
34+
prevent_deletion_if_contains_resources = false
35+
}
36+
}
37+
38+
# Uses the current Azure CLI context (az login + az account set)
39+
skip_provider_registration = false
40+
}
41+
42+
provider "azapi" {
43+
# Uses the current Azure CLI context (az login + az account set)
44+
}
45+
46+
provider "azuread" {
47+
# Uses the current Azure CLI context (az login + az account set)
48+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
resource_group_name = "rg-analytics-dev-fabric"
2+
location = "eastus"
3+
4+
append_random_suffix = true
5+
random_suffix_length = 6
6+
7+
capacity_name = "fabric-capacity-dev"
8+
9+
use_current_user_as_admin = true
10+
11+
# Optional override (UPNs):
12+
# admin_members = [
13+
# "user@domain.com"
14+
# ]
15+
16+
sku_name = "F2"
17+
sku_tier = "Fabric"
18+
19+
tags = {
20+
env = "dev"
21+
area = "analytics-bigdata"
22+
iac = "terraform"
23+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
variable "resource_group_name" {
2+
description = "The name of the Azure Resource Group to deploy into. This template will create the RG if it does not exist (idempotent ARM PUT)."
3+
type = string
4+
5+
validation {
6+
condition = length(trimspace(var.resource_group_name)) > 0
7+
error_message = "resource_group_name must not be empty."
8+
}
9+
}
10+
11+
variable "location" {
12+
description = "The Azure region where the Resource Group and Fabric capacity will be created."
13+
type = string
14+
15+
validation {
16+
condition = length(trimspace(var.location)) > 0
17+
error_message = "location must not be empty."
18+
}
19+
}
20+
21+
variable "append_random_suffix" {
22+
description = "Whether to append a random suffix to the capacity name to avoid collisions."
23+
type = bool
24+
default = true
25+
}
26+
27+
variable "random_suffix_length" {
28+
description = "Length of the random suffix appended when append_random_suffix is true."
29+
type = number
30+
default = 6
31+
32+
validation {
33+
condition = var.random_suffix_length >= 4 && var.random_suffix_length <= 16
34+
error_message = "random_suffix_length must be between 4 and 16."
35+
}
36+
}
37+
38+
variable "capacity_name" {
39+
description = "Base name of the Fabric capacity. If append_random_suffix is true, the final name will be '<base>-<suffix>'."
40+
type = string
41+
42+
validation {
43+
condition = (
44+
length(trimspace(var.capacity_name)) > 0
45+
&& length(var.capacity_name) <= (var.append_random_suffix ? (63 - 1 - var.random_suffix_length) : 63)
46+
&& length(join("", regexall("[a-z0-9]", lower(var.capacity_name)))) > 0
47+
)
48+
error_message = "capacity_name must be 1-63 chars and must contain at least one letter or digit (Terraform will sanitize the name to meet Azure resource naming constraints)."
49+
}
50+
}
51+
52+
variable "admin_members" {
53+
description = "Optional list of Fabric capacity admin members (UPNs). If empty and use_current_user_as_admin is true, Terraform will resolve the current user and use that UPN."
54+
type = list(string)
55+
default = []
56+
}
57+
58+
variable "use_current_user_as_admin" {
59+
description = "When true and admin_members is empty, resolve the currently authenticated Entra ID user and set them as the Fabric capacity admin. Requires AzureAD (Microsoft Graph) read permissions to resolve the UPN."
60+
type = bool
61+
default = true
62+
}
63+
64+
variable "sku_name" {
65+
description = "SKU name for the Fabric capacity (for example: F2, F4, F8, F16, F32, F64, F128, F256, F512, F1024, F2048)."
66+
type = string
67+
default = "F2"
68+
}
69+
70+
variable "sku_tier" {
71+
description = "SKU tier for the Fabric capacity."
72+
type = string
73+
default = "Fabric"
74+
}
75+
76+
variable "tags" {
77+
description = "A map of tags to assign to the resources."
78+
type = map(string)
79+
default = {}
80+
}

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Costa Rica
55
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
66
[brown9804](https://github.com/brown9804)
77

8-
Last updated: 2026-02-12
8+
Last updated: 2026-02-16
99

1010
----------
1111

@@ -107,6 +107,8 @@ Last updated: 2026-02-12
107107
- [Analytics and Big Data](./5_analytics-bigdata)
108108
- [Azure Data Factory](./5_analytics-bigdata/data-factory)
109109
- [Azure Databricks (Workspace)](./5_analytics-bigdata/databricks)
110+
- [Azure Event Hubs](./5_analytics-bigdata/event-hub)
111+
- [Microsoft Fabric (Capacity)](./5_analytics-bigdata/fabric)
110112
- [Azure Synapse Analytics (Workspace)](./5_analytics-bigdata/synapse-analytics)
111113

112114
</details>

0 commit comments

Comments
 (0)