terraform-provider-upgrade

SKILL.md

Terraform Provider Upgrade Skill

This skill provides a comprehensive workflow for safely upgrading Terraform providers with automatic resource migration, breaking change detection, and proper state management.

When to Use This Skill

  • Upgrading provider versions (especially major versions)
  • Handling removed or deprecated resources
  • Migrating between resource types (e.g., azurerm_sql_*azurerm_mssql_*)
  • Detecting and resolving breaking changes
  • Replacing deprecated provider properties
  • Managing Terraform state during upgrades

Determining Breaking vs Non-Breaking Changes

Version Change Analysis

Use MCP tools to understand the scope:

# Get current and latest versions
get_latest_provider_version(namespace="hashicorp", name="azurerm")
# Current: 3.117.0, Latest: 4.51.0 → Major version change (likely breaking)
# Current: 3.117.0, Latest: 3.118.0 → Minor version change (likely non-breaking)
# Current: 3.117.0, Latest: 3.117.1 → Patch version (non-breaking)

# Get upgrade guide to confirm
resolveProviderDocID(...serviceSlug="4.0-upgrade-guide", providerDataType="guides"...)
getProviderDocs(providerDocID="<id>")

Non-Breaking Changes (Auto-Apply)

Characteristics:

  • Minor or patch version updates (e.g., 3.117.03.118.0 or 3.117.1)
  • No removed resources
  • No required argument changes
  • Backward-compatible deprecations with drop-in replacements
  • New optional arguments or bug fixes

Action:

  1. Update version constraints in versions.tf
  2. Apply backward-compatible deprecation replacements if any
  3. Commit changes without detailed documentation
  4. Brief commit message: chore: upgrade azurerm provider to v3.118.0

Breaking Changes (Apply + Document)

Characteristics:

  • Major version updates (e.g., 3.x4.x)
  • Removed resources requiring code migration
  • Required argument changes (renames, type changes)
  • Default value changes affecting behavior
  • Authentication or provider configuration changes

Action:

  1. Apply ALL code changes (resource migrations, moved blocks, argument updates)
  2. Create comprehensive documentation at repository root: TERRAFORM_UPGRADE_BREAKING_CHANGES.md
  3. Document what was done (not what needs to be done)
  4. Detailed commit message referencing documentation

Using MCP Tools to Identify Breaking Changes

Key indicators from upgrade guide:

  • Sections titled "Removed Resources", "Breaking Changes", "Behavior Changes"
  • Resources listed as "removed" or "superseded by"
  • Arguments marked as "renamed", "removed", or "type changed"
  • Default value changes that affect existing behavior

Core Workflow

1. Inventory Current State

Objective: Find all provider references and document current versions

# Search for all Terraform files
find . -name "*.tf"

# Search for provider version constraints
grep -r "required_providers" --include="*.tf"
grep -r "version.*=" --include="versions.tf"

Document:

  • Current provider versions across all modules/environments
  • Location of all provider version constraints
  • Environments using the provider

2. Check Latest Versions

Use MCP Tool:

get_latest_provider_version(namespace="hashicorp", name="azurerm")

Compare:

  • Current version: 3.117.1
  • Latest version: 4.51.0
  • Gap: Major version upgrade (3.x → 4.x)

3. Research Breaking Changes

Step 1: Find Upgrade Guide

resolveProviderDocID(
  providerNamespace="hashicorp",
  providerName="azurerm",
  serviceSlug="4.0-upgrade-guide",
  providerDataType="guides",
  providerVersion="latest"
)

Step 2: Get Documentation

getProviderDocs(providerDocID="<id-from-previous-call>")

Analyze upgrade guide for:

  • Removed resources (resources that no longer exist)
  • Deprecated resources (warnings only)
  • Breaking argument changes (required fields, renamed fields, type changes)
  • New provider features (changes to features {} block)
  • Authentication changes

4. Scan Codebase for Removed Resources

Critical Step: Search for usage of removed resources

# Example: Search for removed SQL resources in Azure v4.0
grep -r "azurerm_sql_server" --include="*.tf"
grep -r "azurerm_sql_firewall_rule" --include="*.tf"
grep -r "azurerm_sql_virtual_network_rule" --include="*.tf"

Document findings:

  • Which files use removed resources
  • Which environments are affected
  • Dependencies between resources

5. Validate Argument Changes

For each removed resource found:

Step 1: Get old resource documentation

resolveProviderDocID(
  providerNamespace="hashicorp",
  providerName="azurerm",
  serviceSlug="sql_server",
  providerDataType="resources",
  providerVersion="3.117.1"
)
getProviderDocs(providerDocID="<id>")

Step 2: Get new resource documentation

resolveProviderDocID(
  providerNamespace="hashicorp",
  providerName="azurerm",
  serviceSlug="mssql_server",
  providerDataType="resources",
  providerVersion="latest"
)
getProviderDocs(providerDocID="<id>")

Step 3: Compare schemas

  • Required arguments (new required fields?)
  • Renamed arguments (e.g., administrator_loginadmin_login)
  • Type changes (name → ID references)
  • Removed arguments
  • New arguments with defaults

Step 4: Check default values

  • Document if new resource has different defaults than old resource
  • Example: New resource might enable features by default that old resource didn't

6. Apply Code Migrations

Update resource types:

# Before
resource "azurerm_sql_server" "sql_server" {
  name                         = "example-sqlserver"
  resource_group_name          = azurerm_resource_group.rg.name
  location                     = azurerm_resource_group.rg.location
  version                      = "12.0"
  administrator_login          = "sqladmin"
  administrator_login_password = var.sql_password
}

# After
resource "azurerm_mssql_server" "sql_server" {
  name                         = "example-sqlserver"
  resource_group_name          = azurerm_resource_group.rg.name
  location                     = azurerm_resource_group.rg.location
  version                      = "12.0"
  administrator_login          = "sqladmin"
  administrator_login_password = var.sql_password
}

Add moved block for state migration:

moved {
  from = azurerm_sql_server.sql_server
  to   = azurerm_mssql_server.sql_server
}

Update argument changes:

# Firewall rule arguments changed from name-based to ID-based
# Before (v3.x)
resource "azurerm_sql_firewall_rule" "allow_azure" {
  name                = "allow-azure-services"
  resource_group_name = azurerm_resource_group.rg.name
  server_name         = azurerm_sql_server.sql_server.name
  start_ip_address    = "0.0.0.0"
  end_ip_address      = "0.0.0.0"
}

# After (v4.x)
resource "azurerm_mssql_firewall_rule" "allow_azure" {
  name             = "allow-azure-services"
  server_id        = azurerm_mssql_server.sql_server.id  # Changed from name to ID
  start_ip_address = "0.0.0.0"
  end_ip_address   = "0.0.0.0"
}

moved {
  from = azurerm_sql_firewall_rule.allow_azure
  to   = azurerm_mssql_firewall_rule.allow_azure
}

Update dependent resources:

# Search for resources that reference the migrated resource
grep -r "azurerm_sql_server.sql_server" --include="*.tf"

Update references to use correct attributes (e.g., .id instead of .name where needed).

Replace deprecated provider properties:

# Before
provider "azurerm" {
  features {}
  skip_provider_registration = true  # Deprecated
}

# After
provider "azurerm" {
  features {}
  resource_provider_registrations = "none"  # Modern equivalent
}

Update version constraints:

terraform {
  required_version = ">= 1.5.0"
  
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "4.51.0"  # Updated from 3.117.1
    }
  }
}

7. Document Changes

Only create documentation for breaking changes.

Create TERRAFORM_UPGRADE_BREAKING_CHANGES.md at repository root (not in .github/ or subdirectories):

File Location:

your-terraform-repo/
├── TERRAFORM_UPGRADE_BREAKING_CHANGES.md  ← Place here
├── infra/
├── .github/
└── README.md
# Terraform Provider Upgrade: AzureRM v3.117.1 → v4.51.0

**Date:** 2026-01-27

## Summary

Upgraded HashiCorp AzureRM provider from v3.117.1 to v4.51.0. This major version upgrade included automatic migration of removed SQL resources to their modern MSSQL equivalents.

## What Changed

- Updated `required_providers` version constraint to `4.51.0`
- Migrated removed resources: `azurerm_sql_*``azurerm_mssql_*`
- Replaced deprecated `skip_provider_registration` with `resource_provider_registrations`
- Updated argument references from name-based to ID-based

## Breaking Changes Handled

### ✅ Removed Resources Migrated

**1. azurerm_sql_server → azurerm_mssql_server**
- **Files Modified:** `infra/modules/database/main.tf`
- **Changes Applied:**
  - Updated resource type
  - Added `moved` block for automatic state migration
  - All arguments remain compatible
- **Argument Mappings:** No changes required (schema compatible)
- **Default Values:** No new default value changes
- **Documentation:** [azurerm_mssql_server](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server)

**2. azurerm_sql_firewall_rule → azurerm_mssql_firewall_rule**
- **Files Modified:** `infra/modules/database/main.tf`
- **Changes Applied:**
  - Updated resource type
  - Changed `server_name` argument to `server_id`
  - Updated reference from `.name` to `.id`
  - Added `moved` block for automatic state migration
- **Argument Mappings:**
  - `resource_group_name` (removed) + `server_name``server_id`
  - Now uses: `azurerm_mssql_server.sql_server.id`
- **Default Values:** No new default value changes
- **Documentation:** [azurerm_mssql_firewall_rule](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_firewall_rule)

**State Migration:** Terraform will automatically migrate state using `moved` blocks on next plan/apply.

## Notes

- All changes are backward compatible with existing state
- `moved` blocks enable automatic state migration
- No manual `terraform state mv` commands required
- Provider block retained with updated `resource_provider_registrations` argument

## Next Steps

1. **Commit these changes** to a feature branch
2. **Run your Terraform workflow** via CI/CD pipeline to validate
3. **Review plan output** to confirm state migrations
4. **Verify no unexpected changes** before merging

## References

- [AzureRM Provider 4.0 Upgrade Guide](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/4.0-upgrade-guide)
- [AzureRM Provider v4.51.0 Release Notes](https://github.com/hashicorp/terraform-provider-azurerm/releases/tag/v4.51.0)
- [Terraform Moved Blocks](https://developer.hashicorp.com/terraform/language/modules/develop/refactoring)
- [Resource Provider Registrations](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/4.0-upgrade-guide#resource-provider-registrations)

Best Practices

✅ DO:

  • Distinguish upgrade types - Check if major (breaking) vs minor/patch (non-breaking)
  • Auto-apply non-breaking - Minor/patch updates don't need detailed documentation
  • Document breaking only - Create TERRAFORM_UPGRADE_BREAKING_CHANGES.md for major versions
  • Place docs at root - Repository root for visibility, not in subdirectories
  • Use moved blocks for resource type changes (automatic state migration)
  • Validate arguments against official docs for both old and new resources
  • Check default values - document if new resource has different defaults
  • Update dependent resources that reference migrated resources
  • Document what was done - show code changes applied
  • Include resource documentation links for transparency
  • Use pipeline validation - let CI/CD handle terraform commands

❌ DON'T:

  • Document non-breaking changes - Minor/patch versions don't need TERRAFORM_UPGRADE_BREAKING_CHANGES.md
  • Provide manual migration steps - code should handle everything
  • Assume arguments stayed the same - always validate schemas
  • Forget dependent resources - search and update references
  • Miss attribute changes - update .name to .id where needed
  • Remove provider blocks - only update deprecated arguments
  • Suggest terraform commands - users validate via pipeline

Workflow Examples

Example 1: Non-Breaking Upgrade (Minor Version)

Scenario: Upgrading AzureRM from 3.117.0 to 3.118.0

# 1. Check version
get_latest_provider_version(namespace="hashicorp", name="azurerm")
# Result: 3.118.0 (minor version bump)

# 2. Check for breaking changes
resolveProviderDocID(...serviceSlug="3.118.0", providerDataType="guides"...)
getProviderDocs(providerDocID="<id>")
# Review: No removed resources, no breaking changes

# 3. Update version
# versions.tf: version = "3.118.0"

# 4. Commit
# Message: "chore: upgrade azurerm provider to v3.118.0"
# NO TERRAFORM_UPGRADE_BREAKING_CHANGES.md needed

Example 2: Breaking Upgrade (Major Version)

Scenario: Upgrading AzureRM from 3.117.0 to 4.51.0

# 1. Check version  
get_latest_provider_version(namespace="hashicorp", name="azurerm")
# Result: 4.51.0 (major version bump)

# 2. Get upgrade guide
resolveProviderDocID(...serviceSlug="4.0-upgrade-guide"...)
getProviderDocs(providerDocID="<id>")
# Review: azurerm_sql_* resources removed

# 3. Scan codebase
grep -r "azurerm_sql_server" --include="*.tf"

# 4. Migrate resources (fetch old + new docs)
# 5. Add moved blocks
# 6. Update arguments
# 7. Create TERRAFORM_UPGRADE_BREAKING_CHANGES.md at repository root
# 8. Commit with detailed message referencing documentation

Best Practices

✅ DO:

  • Use moved blocks for resource type changes (automatic state migration)
  • Validate arguments against official docs for both old and new resources
  • Check default values - document if new resource has different defaults
  • Update dependent resources that reference migrated resources
  • Document what was done - show code changes applied
  • Include resource documentation links for transparency
  • Use pipeline validation - let CI/CD handle terraform commands

❌ DON'T:

  • Provide manual migration steps - code should handle everything
  • Assume arguments stayed the same - always validate schemas
  • Forget dependent resources - search and update references
  • Miss attribute changes - update .name to .id where needed
  • Remove provider blocks - only update deprecated arguments
  • Suggest terraform commands - users validate via pipeline

Additional Resources

For detailed examples, common patterns, and troubleshooting, see the reference guide.

Weekly Installs
1
GitHub Stars
13
First Seen
12 days ago
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1