Skip to content

Commit 9bbf4de

Browse files
lonegunmanbCopilotjaredfholgateCopilot
authored
fix: add missing principal_type and description to role_assignment resource block (#125)
* fix: add missing principal_type and description to role_assignment resource block The role_assignments variable defines principal_type and description attributes, but the azurerm_role_assignment resource block did not reference them. This caused the specified principal_type and description to be silently ignored. Fixes #101 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: avm pre-commit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * pre commit and provider version Co-authored-by: Copilot <copilot@github.com> * fix tests and update complete example Co-authored-by: Copilot <copilot@github.com> * migrate to azapi and solve lock dependency issues Co-authored-by: Copilot <copilot@github.com> * bug fix Co-authored-by: Copilot <copilot@github.com> * pre commit * tidy * update util module and add role def id Co-authored-by: Copilot <copilot@github.com> * fix: support subscription-scoped role definition IDs in role_assignments - Update validation regex to optionally accept '/subscriptions/<sub_id>' prefix on role_definition_id_or_name to match Azure's canonical form and avoid idempotency drift.- Switch role_assignment3 in the complete example to the subscription-scoped form (Storage Blob Data Contributor). * migration testing fixes Co-authored-by: Copilot <copilot@github.com> * add managed by support Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jared Holgate <jaredholgate@microsoft.com> Co-authored-by: Copilot <copilot@github.com>
1 parent 6e3f803 commit 9bbf4de

41 files changed

Lines changed: 2541 additions & 678 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
name: avm-terraform-module-development
3+
description: Azure Verified Modules (AVM) Terraform development workflow for fixing issues and adding features
4+
glob: "**/*.terraform,**/*.tf,**/*.tfvars,**/*.tfstate,**/*.tflint.hcl,**/*.tf.json,**/*.tfvars.json"
5+
---
6+
7+
# Azure Verified Modules (AVM) Terraform
8+
9+
Azure Verified Modules (AVM) are pre-built, tested, and validated Terraform and Bicep modules that follow Azure best practices. Use these modules to create, update, or review Azure Infrastructure as Code (IaC) with confidence.
10+
11+
## Development Workflow
12+
13+
Follow these steps in order when fixing an issue or adding a feature.
14+
15+
### Step 1: Start from a clean main branch
16+
17+
```bash
18+
git checkout main
19+
git pull
20+
```
21+
22+
### Step 2: Create and checkout a feature/issue branch
23+
24+
```bash
25+
git checkout -b feature/<short-description>
26+
# or
27+
git checkout -b fix/<issue-number>-<short-description>
28+
```
29+
30+
### Step 3: Implement the change
31+
32+
All Azure resources MUST be deployed using the **AzAPI provider** (`Azure/azapi`). For AzAPI resource patterns, schema lookups, and the `azure-schema` CLI tool, read [AzAPI.md](references/AzAPI.md).
33+
34+
To query Terraform provider schemas (resources, data sources, functions, ephemeral resources), use the `tfpluginschema` CLI. See [tfpluginschema.md](references/tfpluginschema.md).
35+
36+
Make the necessary code changes to add the feature or fix the issue.
37+
38+
### Step 4: Add unit tests (if justified)
39+
40+
Unit tests use **provider mocking** and live in the `tests/unit` directory. Add or update unit tests when your change introduces new logic, variables, or outputs that can be validated without deploying real infrastructure. For test writing guidance, syntax, and patterns, read [terraform-test.md](references/terraform-test.md).
41+
42+
```bash
43+
PORCH_NO_TUI=1 ./avm tf-test-unit
44+
```
45+
46+
### Step 5: Add integration tests (if justified)
47+
48+
Integration tests do **not** use provider mocking and live in the `tests/integration` directory. Add or update integration tests when your change requires validation against real Azure infrastructure. For test writing guidance, syntax, and patterns, read [terraform-test.md](references/terraform-test.md).
49+
50+
```bash
51+
PORCH_NO_TUI=1 ./avm tf-test-integration
52+
```
53+
54+
### Step 6: Add or update examples (if justified)
55+
56+
If your change affects module usage or introduces new functionality, add or update examples in the `examples/` directory. Test only the pertinent example:
57+
58+
```bash
59+
PORCH_NO_TUI=1 AVM_EXAMPLE="<ExampleDir>" ./avm test-examples
60+
```
61+
62+
When running on Windows, distributing tests across multiple Azure subscriptions, or retaining deployed resources for manual validation, see [example-test.md](references/example-test.md) for manual local testing of examples (init, plan, apply, idempotency check, and optional destroy).
63+
64+
### Step 7: Update documentation (if justified)
65+
66+
If documentation changes are needed, edit `_header.md`. **NEVER edit README.md directly** -- it is auto-generated and will be overwritten.
67+
68+
### Step 8: Run pre-commit checks (MANDATORY)
69+
70+
This must **always** be run before committing:
71+
72+
```bash
73+
PORCH_NO_TUI=1 ./avm pre-commit
74+
```
75+
76+
### Step 9: Commit changes
77+
78+
```bash
79+
git add .
80+
git commit -m "<type>: <meaningful description>"
81+
```
82+
83+
### Step 10: Run PR checks (MANDATORY)
84+
85+
This must **always** be run after committing:
86+
87+
```bash
88+
PORCH_NO_TUI=1 ./avm pr-check
89+
```
90+
91+
### Step 11: Push and open a PR
92+
93+
Push the branch to remote and open a pull request with a meaningful description. Reference any issues that should be closed.
94+
95+
```bash
96+
git push -u origin HEAD
97+
```
98+
99+
When creating the PR, include:
100+
101+
- A clear description of what was changed and why
102+
- References to related issues (e.g., `Closes #123`)
103+
104+
## Troubleshooting Test Failures
105+
106+
If any issues arise during testing or PR checks, refer to the official AVM testing documentation:
107+
108+
<https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/refs/heads/main/docs/content/contributing/terraform/testing.md>
109+
110+
## Reference
111+
112+
### Code Quality
113+
114+
- Always run `terraform fmt` after making changes
115+
- Always run `terraform validate` after making changes
116+
- Use meaningful variable names and descriptions
117+
- Use snake_case
118+
- Add proper tags and metadata
119+
- Document complex configurations
120+
121+
### Tool Integration
122+
123+
- **AzAPI Provider & Schema Lookup**: See [AzAPI.md](references/AzAPI.md) for resource patterns and the `azure-schema` CLI tool
124+
- **Terraform Provider Schemas**: See [tfpluginschema.md](references/tfpluginschema.md) for querying resource, data source, function, and ephemeral schemas from any provider
125+
- **Terraform Tests**: See [terraform-test.md](references/terraform-test.md) for writing unit and integration tests
126+
- **Example Testing**: See [example-test.md](references/example-test.md) for manually testing examples against real Azure infrastructure
127+
- **Deployment Guidance**: Use `azure_get_deployment_best_practices` tool
128+
- **Service Documentation**: Use `microsoft.docs.mcp` tool for Azure service-specific guidance
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# AzAPI Provider
2+
3+
All Azure resources in AVM modules MUST be deployed using the **AzAPI provider** (`Azure/azapi`).
4+
5+
## Provider Configuration
6+
7+
```hcl
8+
terraform {
9+
required_providers {
10+
azapi = {
11+
source = "Azure/azapi"
12+
version = "~> 2.8"
13+
}
14+
}
15+
}
16+
```
17+
18+
## Resource Pattern
19+
20+
AzAPI resources use ARM resource types with explicit API versions:
21+
22+
```hcl
23+
resource "azapi_resource" "example" {
24+
type = "<ResourceProvider>/<ResourceType>@<ApiVersion>"
25+
parent_id = "<parent resource ID>"
26+
name = "<resource name>"
27+
location = "<Azure region>"
28+
29+
body = {
30+
properties = {
31+
# Resource-specific properties (HCL object, NOT JSON string)
32+
}
33+
}
34+
35+
# MUST include this, set to empty list if no exports are needed.
36+
response_export_values = [
37+
"properties.<field>",
38+
]
39+
}
40+
```
41+
42+
### Key attributes
43+
44+
| Attribute | Description |
45+
| ------------------------ | ----------------------------------------------------------------------------------------------------- |
46+
| `type` | ARM resource type with API version (e.g., `Microsoft.Storage/storageAccounts@2023-01-01`) |
47+
| `parent_id` | ID of the parent resource. For top-level resources: `/subscriptions/{sub}/resourceGroups/{rg}` |
48+
| `name` | Resource name |
49+
| `location` | Azure region |
50+
| `body` | Resource properties as an **HCL object** (not a JSON string) |
51+
| `response_export_values` | List of ARM property paths to export set to empty list if not used (e.g., `"properties.principalId"`) |
52+
| `locks` | A mutex. List of resource IDs to lock on to prevent concurrent operations |
53+
54+
### Accessing outputs
55+
56+
Use `.output` to access exported values:
57+
58+
```hcl
59+
azapi_resource.example.output.properties.principalId
60+
```
61+
62+
## Data sources
63+
64+
```hcl
65+
# Get current client context (subscription, tenant)
66+
data "azapi_client_config" "current" {}
67+
68+
# Use in expressions:
69+
data.azapi_client_config.current.subscription_id
70+
data.azapi_client_config.current.subscription_resource_id
71+
data.azapi_client_config.current.tenant_id
72+
```
73+
74+
## Unit test mocking
75+
76+
```hcl
77+
mock_provider "azapi" {}
78+
```
79+
80+
## Azure Resource Schema Lookup
81+
82+
Use the `azure-schema` CLI tool to look up resource type schemas, properties, constraints, and available API versions. This is essential for knowing the correct `type` and `body` structure for `azapi_resource`.
83+
84+
- **Bash**: `.agents/skills/avm-terraform-module-development/scripts/azure-schema`
85+
- **PowerShell**: `.agents/skills/avm-terraform-module-development/scripts/azure-schema.ps1`
86+
87+
### List available API versions
88+
89+
```bash
90+
.agents/skills/avm-terraform-module-development/scripts/azure-schema versions Microsoft.Storage
91+
```
92+
93+
```powershell
94+
.agents/skills/avm-terraform-module-development/scripts/azure-schema.ps1 versions Microsoft.Storage
95+
```
96+
97+
### Get a resource schema (human-readable)
98+
99+
```bash
100+
.agents/skills/avm-terraform-module-development/scripts/azure-schema get Microsoft.Storage/storageAccounts 2023-01-01
101+
```
102+
103+
```powershell
104+
.agents/skills/avm-terraform-module-development/scripts/azure-schema.ps1 get Microsoft.Storage/storageAccounts 2023-01-01
105+
```
106+
107+
### Get a resource schema (resolved JSON)
108+
109+
```bash
110+
.agents/skills/avm-terraform-module-development/scripts/azure-schema get Microsoft.Storage/storageAccounts 2023-01-01 --json
111+
```
112+
113+
```powershell
114+
.agents/skills/avm-terraform-module-development/scripts/azure-schema.ps1 get Microsoft.Storage/storageAccounts 2023-01-01 -Json
115+
```
116+
117+
### Control depth
118+
119+
```bash
120+
# Shallow view (top-level properties only)
121+
.agents/skills/avm-terraform-module-development/scripts/azure-schema get Microsoft.Storage/storageAccounts 2023-01-01 --depth 2
122+
123+
# Deep view (default is 5)
124+
.agents/skills/avm-terraform-module-development/scripts/azure-schema get Microsoft.Storage/storageAccounts 2023-01-01 --depth 8
125+
```
126+
127+
```powershell
128+
# Shallow view (top-level properties only)
129+
.agents/skills/avm-terraform-module-development/scripts/azure-schema.ps1 get Microsoft.Storage/storageAccounts 2023-01-01 -Depth 2
130+
131+
# Deep view (default is 5)
132+
.agents/skills/avm-terraform-module-development/scripts/azure-schema.ps1 get Microsoft.Storage/storageAccounts 2023-01-01 -Depth 8
133+
```
134+
135+
## Sensitive attributes
136+
137+
- Passwords, keys, etc should be passed in using the `sensitive_body` attribute. This object is merged with the `body` at runtime.
138+
- All sensitive values MUST be ephemeral.
139+
- Use `sensitive_body_version` as a map to track the JSON properties that are set via `sensitive_body`. This allows Terraform to know when the sensitive value has changed, e.g. `sensitive_body_version = { "properties.key1" = "1" }`."
140+
- Reference each sensitive body version as a variable.
141+
142+
### Workflow
143+
144+
1. Find the API version: `azure-schema versions <Provider>`
145+
2. Get the schema: `azure-schema get <ResourceType> <ApiVersion>`
146+
3. Map the schema properties into the `body` block of your `azapi_resource`
147+
4. Properties marked `[READ-ONLY]` should not be set in `body` -- use `response_export_values` to read them if required
148+
5. Properties marked `[REQUIRED]` must be included in `body`
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Testing Examples Manually
2+
3+
> **When to use this reference:**
4+
>
5+
> - You are running on **Windows** (on non-Windows systems, use the `avm` command instead).
6+
> - You want to **distribute tests across multiple Azure subscriptions**.
7+
> - You want to **retain deployed resources** after testing for manual validation (skip destroy).
8+
9+
Each subfolder under `examples/` is a standalone Terraform root module. Test each one independently.
10+
11+
## Testing Workflow
12+
13+
For each example directory, run these steps in order. Stop and fix any errors before proceeding.
14+
15+
1. Run Terraform init
16+
2. Run Terraform plan
17+
3. Run Terraform apply
18+
4. Run Terraform plan again (idempotency check)
19+
20+
The idempotency check (step 4) must show **"No changes"**. If it reports drift, that is a bug - fix it. Common causes:
21+
22+
- **Server-side defaults**: A property not set in config gets a default from Azure. Set it explicitly. Use `ignore_changes` only as a last resort.
23+
- **Computed attributes**: An output or reference that changes on every read.
24+
- **Provider bugs**: Check for known issues in the provider repository.
25+
26+
### Destroy
27+
28+
**Ask the user before destroying.** They may want to inspect resources in the Azure portal or keep them for debugging.
29+
30+
```powershell
31+
terraform destroy
32+
```
33+
34+
Some resources (e.g., soft-delete enabled Key Vaults) may require manual purging.
35+
36+
## Distributing Examples Across Subscriptions
37+
38+
To avoid quota limits or reduce blast radius, distribute examples across multiple subscriptions.
39+
40+
**Always ask the user before changing the subscription.**
41+
42+
Set `ARM_SUBSCRIPTION_ID` before running each example:
43+
44+
```powershell
45+
$env:ARM_SUBSCRIPTION_ID = "<subscription-id>"
46+
```
47+
48+
### Round-Robin Example
49+
50+
```powershell
51+
$subscriptions = @(
52+
"00000000-0000-0000-0000-000000000001"
53+
"00000000-0000-0000-0000-000000000002"
54+
"00000000-0000-0000-0000-000000000003"
55+
)
56+
57+
$i = 0
58+
foreach ($dir in Get-ChildItem -Path examples -Directory) {
59+
$env:ARM_SUBSCRIPTION_ID = $subscriptions[$i % $subscriptions.Count]
60+
Write-Host "=== Testing $($dir.Name) on subscription $env:ARM_SUBSCRIPTION_ID ==="
61+
Push-Location $dir.FullName
62+
terraform init -upgrade
63+
terraform plan -out=tfplan
64+
terraform apply tfplan
65+
terraform plan # idempotency check
66+
Pop-Location
67+
$i++
68+
}
69+
```

0 commit comments

Comments
 (0)