AzureCAF Terraform Provider

repository·main·Indexed 41 days ago

https://github.com/aztfmod/terraform-provider-azurecaf

A Terraform provider that implements naming convention methodologies following the Microsoft Cloud Adoption Framework (CAF) for Azure. It enables developers to automatically generate compliant, sanitized, and unique Azure resource names using the azurecaf_name data source and resource.

Tokens
24.6K
Snippets
60
Records
100
Agent score
51%

What's inside AzureCAF

  1. Use the mock-azurerm test harness

    main

    The mock-azurerm harness validates every CAF-generated name against the corresponding azurerm_* resource schema using terraform test with mock_provider "azurerm" {}. This process requires no Azure credentials and ensures that generated names comply with the actual azurerm provider's schema validators.

    This harness sits between two other testing layers:

    1. Resource Matrix Tests: Validates names against the CAF validation_regex (self-check).
    2. E2E Tests: Validates a handful of hand-coded scenarios.
    3. Mock-azurerm (This harness): Validates names against the azurerm provider's schema validators.
  2. Overview of Azure CAF Provider components

    main

    The Azure CAF provider is a logical provider that operates within Terraform's logic to assist with Azure landing zone implementations. It consists of the following components:

    Resources

    • azurecaf_name: Generate Azure-compliant resource names (Note: Using the data source version is recommended).
    • azurecaf_naming_convention: Legacy naming convention resource.

    Data Sources

    • azurecaf_name: Generate names at plan time (Recommended approach).
    • azurecaf_environment_variable: Read environment variables securely.
  3. Validate existing names using passthrough mode

    main

    To check if an existing name is compliant with Azure's naming rules without modifying it, set passthrough = true. This is useful for validating names that were created outside of the current Terraform configuration.

    data "azurecaf_name" "existing_storage" {
      name          = "mystorageaccount123"
      resource_type = "azurerm_storage_account"
      passthrough   = true
    }
    
    # Validates that "mystorageaccount123" is compliant with storage account naming rules
  4. Understand the test file organization

    main

    Tests are categorized by their purpose and the level of the stack they verify. Use the file naming patterns to identify the type of test you are looking at.

    Test Categories

    1. Provider Tests: Basic configuration and initialization (provider_test.go).
    2. Resource Name Tests: String cleaning, concatenation, and slug retrieval (resource_name_test.go).
    3. Naming Convention Tests: Tests for specific naming styles like cafclassic, cafrandom, random, and passthrough.
    4. Data Source Tests: Validation of data source behavior vs resource behavior.
    5. Model Tests: Regex, length, and string processing validations for generated models (models_generated_test.go).
    6. Integration Tests: End-to-end Terraform lifecycle tests (prefixed with TestAcc).
    7. Coverage/Edge Case Tests: Specialized tests to hit untested code paths or error handling logic.

    File Naming Patterns

    • *_test.go: Standard unit tests.
    • integration_*_test.go: Integration tests with Terraform.
    • *_coverage_test.go: Tests specifically for coverage improvement.
    • enhanced_*_test.go: Comprehensive test suites.
  5. How azurecaf_name validation and error handling works

    main

    The azurecaf_name resource performs several layers of validation to ensure generated names are valid for Azure:

    1. Length Validation: Ensures names do not exceed maximum length after truncation and meet minimum requirements. Random length is validated against resource type constraints.
    2. Pattern Validation: After composition and truncation, names must match the specific validation pattern for the chosen resource_type.

    Warning on clean_input: If clean_input = false, the resource will not remove invalid characters from your input name. If the resulting composition contains characters disallowed by the resource_type pattern, validation will fail.

    resource "azurecaf_name" "example" {
      name          = "my-app_name"
      resource_type = "azurerm_storage_account"  # Only allows alphanumeric
      clean_input   = false  # Won't clean invalid characters
    }
    # Error: Pattern validation failed
  6. Understand validation and error handling in azurecaf_name

    main

    The azurecaf_name data source performs several layers of validation to ensure generated names comply with Azure requirements:

    • Length Validation: It checks that names do not exceed maximum length constraints after truncation and ensures random suffixes meet resource-specific length requirements. Minimum length requirements are also enforced.
    • Pattern Validation: After composition and truncation, the final name is validated against the specific regex pattern required by the resource_type. If clean_input is set to false, invalid characters in the input will cause a pattern validation error rather than being stripped.
    • Character Restrictions: It automatically filters invalid characters based on the specified resource_type.
    • Case Requirements: It handles the specific casing requirements (case-sensitive vs. case-insensitive) for different Azure resources.
  7. Compare `azurecaf_name` Data Source vs Resource

    main

    The provider offers two ways to generate names: a Data Source and a Resource. Choosing the right one depends on your lifecycle requirements.

    Use the data "azurecaf_name" block when you want names to be evaluated during the plan phase. This allows you to see the generated names in your Terraform plan before any resources are actually created.

    data "azurecaf_name" "storage" {
      name          = "mydata"
      resource_type = "azurerm_storage_account"
      prefixes      = ["prod"]
      random_length = 3
    }
    
    resource "azurerm_storage_account" "example" {
      name = data.azurecaf_name.storage.result
    }

    Resource

    Use the resource "azurecaf_name" block when you need to generate multiple related names for different resource types simultaneously. This ensures consistency across a group of resources.

    resource "azurecaf_name" "multi_res" {
      name           = "myapp"
      resource_type  = "azurerm_app_service"
      resource_types = [
        "azurerm_app_service_plan",
        "azurerm_application_insights"
      ]
      prefixes      = ["prod"]
      random_length = 3
    }
    
    # Accessing the names:
    # Primary name: azurecaf_name.multi_res.result
    # All generated names: azurecaf_name.multi_res.results
    # Data Source Example
    data "azurecaf_name" "storage" {
      name          = "mydata"
      resource_type = "azurerm_storage_account"
      prefixes      = ["prod"]
      random_length = 3
    }
    
    # Resource Example
    resource "azurecaf_name" "multi_res" {
      name           = "myapp"
      resource_type  = "azurerm_app_service"
      resource_types = [
        "azurerm_app_service_plan",
        "azurerm_application_insights"
      ]
      prefixes      = ["prod"]
      random_length = 3
    }
  8. How azurecaf_name composes resource names

    main

    The provider uses a name precedence algorithm to compose names. The order of components is:

    1. name: The base name.
    2. slug: The resource type abbreviation (if use_slug = true).
    3. random: Random characters (if random_length > 0).
    4. suffixes: Suffix strings (applied in order).
    5. prefixes: Prefix strings (applied in reverse order).

    Component Placement Order

    • Prefixes: Added to the beginning (last prefix first).
    • Slug: Added after prefixes.
    • Name: The core component.
    • Suffixes: Added to the end (first suffix first).
    • Random: Added to the very end after suffixes.

    Example Composition: For name="myapp", prefixes=["corp", "prod"], resource_type="azurerm_storage_account" (slug st), suffixes=["web", "001"], and random_length=3 with separator -:

    1. Prefixes (reverse): prod-corp
    2. Slug: st-prod-corp
    3. Name: st-prod-corp-myapp
    4. Suffixes (forward): st-prod-corp-myapp-web-001
    5. Random: st-prod-corp-myapp-web-001-abc

    Note: Final output is processed for lowercase and separator compliance (e.g., stprodcorpmyappweb001abc).

  9. How the E2E test suite works

    main

    The E2E test suite validates the terraform-provider-azurecaf through a four-step lifecycle:

    1. Build: The provider is built directly from the source code.
    2. Override: Terraform's dev_overrides feature is used to point Terraform to the locally built provider binary instead of downloading it from a registry.
    3. Execute: Actual Terraform commands (such as plan, init, and import) are executed against real Terraform configurations.
    4. Validate: The resulting state and outputs are inspected to ensure the provider behaves correctly.

    Each test runs in an isolated temporary directory and performs automatic cleanup after completion.

  10. How azurecaf_naming_convention name composition works

    main

    The legacy azurecaf_naming_convention resource follows a fixed composition order: [prefix, cafprefix, name, postfix] joined with -. The cafprefix is the resource-type slug (e.g., rg for Resource Group) defined by the provider.

    Convention Behaviors

    ConventionBehavior
    cafclassicJoins prefix, cafprefix, name, postfix. No padding.
    cafrandomJoins components, then pads with random alphanumeric characters up to max_length.
    randomDiscards name and postfix; emits a fully random alphanumeric string.
    passthroughJoins components without modification, but cleans invalid characters and validates length.

    Validation and Constraints

    • Character Filtering: The composed string is filtered through a resource-specific RegEx to remove invalid characters (e.g., dashes are stripped for Storage Accounts).
    • Length: The name is bounded by max_length, which is capped by the Azure resource's actual maximum limit.
    • Validation: The final output is checked against a ValidationRegExp. If it fails, the resource returns an error.
  11. How azurecaf_name handles length constraints and truncation

    main

    When a composed name exceeds the maximum length allowed by an Azure resource, the provider uses priority-based truncation. It attempts to fit as many components as possible based on their importance.

    Truncation Priority

    Components are added in this order. If a component cannot fit within the remaining character budget, it is skipped entirely:

    1. name (Highest priority - always preserved if possible)
    2. slug
    3. random
    4. suffixes
    5. prefixes (Lowest priority - first to be dropped)

    Examples

    Prefix Truncation: If a storage account (max 24 chars) has a name "verylongapplicationname" (23 chars) and a prefix "corporate", the prefix and slug will be skipped to ensure the core name fits. Result: "verylongapplicationname"

    Suffix Truncation: If a name is "myapp" (5 chars), slug is "st" (2 chars), and random is 8 chars, but a suffix "production" (10 chars) would push the total over the limit, the provider will skip "production" and move to the next suffix in the list (e.g., "web").

  12. Understand the different types of tests

    main

    The provider uses three main categories of tests to ensure reliability:

    1. Unit Tests (*_test.go):

      • Test individual components in isolation.
      • Located alongside their corresponding source files.
      • Use standard Go testing patterns.
    2. Integration Tests (integration_*_test.go):

      • Test interactions between multiple components.
      • Use the Terraform Plugin SDK's resource.UnitTest framework.
      • Requirement: You must set the TF_ACC=1 environment variable to run these.
    3. Coverage Tests (*_coverage_test.go and *_edge_cases_test.go):

      • Target specific untested code paths, edge cases, and error conditions.
      • Often involve temporary modifications to resource definitions to validate error handling.