Terraform

repository·main·Indexed 21 days ago

https://github.com/hashicorp/terraform

An Infrastructure as Code tool for defining, provisioning, and managing cloud and on-premise resources. This documentation covers the Terraform Core architecture, the gRPC-based plugin protocol and versioning strategy for SDK developers, and setup instructions for testing various backends including GCS, Kubernetes, and Postgres.

Tokens
56.5K
Snippets
122
Records
260
Agent score
87%

What's inside terraform

  1. Overview of Terraform core features

    main

    Terraform is an Infrastructure as Code (IaC) tool used to build, change, and version infrastructure safely. It uses a high-level configuration syntax to create blueprints of datacenters that can be versioned and reused.

    Key operational concepts include:

    • Execution Plans: A 'planning' step that generates a preview of changes before they are applied, preventing unexpected infrastructure modifications.
    • Resource Graph: Terraform constructs a dependency graph of all resources, allowing it to parallelize the creation and modification of non-dependent resources for maximum efficiency.
    • Change Automation: Automates complex changesets using the execution plan and resource graph to ensure changes occur in the correct order with minimal human error.
  2. Core components of the Terraform Stacks implementation

    main

    The Terraform Stacks functionality is implemented through several key Go packages, each handling a specific part of the orchestration lifecycle:

    • stackaddrs: Manages addressing within the stacks language and runtime. It is an extension of the standard addrs package, providing types to refer to objects within a stack and logic for navigating between different address types.
    • stackconfig: Responsible for loading, parsing, and static decoding of the stacks language (analogous to the configs package for Terraform modules).
    • stackplan and stackstate: Provide the models and the logic for marshalling and unmarshalling the Stacks-specific versions of Terraform's "plan" and "state" concepts.
    • stackruntime: Manages the dynamic behavior and runtime execution of stacks. This includes comparing desired state against actual state to create plans and executing those plans (applying them).
    • tfstackdata1: An internal Go representation of a protocol buffers schema used to persist plan and state data between runs.

    Note for Developers: tfstackdata1 is an internal implementation detail. External callers should not rely on these formats directly; instead, use the public interface provided via the Terraform Core RPC API (implemented in the rpcapi directory).

  3. What is Terraform Stacks?

    main
    Terraform Stacks is an orchestration layer designed to sit on top of zero or more trees of Terraform modules. It functions as a higher-level abstraction that manages multiple modules or module trees, providing a unified way to orchestrate complex infrastructure. The implementation is composed of several specialized Go packages that handle addressing, configuration, planning, state management, and runtime execution.
  4. Handle nested blocks in configuration

    main

    Nested blocks are configuration-only constructs. Because they are defined in the user's configuration, their count cannot be changed dynamically during planning or apply.

    Rules for Nested Blocks:

    • Every block in the configuration must have a corresponding nested object in both the Planned State and the New State.
    • Implicit Objects: If a remote system creates sub-objects implicitly (e.g., a default network interface), the provider cannot use nested blocks to represent them. Instead, the provider must use separate computed attributes (like a list or map of objects) that include both the explicitly configured objects and the implicitly created ones.
    • Structural-typed Attributes: In provider protocol version 6, structural-typed attributes (a hybrid of attribute and nested-block syntax) must follow the same rules as nested blocks.
  5. Understand Terraform's default planning behaviors

    main

    Terraform Core follows a core design tenet: any actions with externally-visible side-effects should be carried out via the standard process of creating a plan and then applying it.

    By default, Terraform Core automatically proposes the following actions for resource instances during the planning phase:

    • Create: Triggered if a resource block exists in the configuration but has no corresponding managed resource in the prior state, or if a count/for_each change results in a new instance key.
    • Delete: Triggered if a resource tracked in the state has no corresponding resource block in the configuration, or if a count/for_each change removes an existing instance key.
    • Update: Triggered when a resource instance exists in both the configuration and the state, but there are differences between them that the provider does not classify as mere normalization.
    • Replace: Triggered when a resource instance is marked as "tainted". This indicates a previous creation failed partially, and Terraform must replace the object to ensure it matches the configuration.
    • Read: Triggered by data blocks. Terraform attempts to perform this eagerly during the planning phase. However, it will delay this to the apply phase if:
      • The configuration contains unknown values.
      • The data resource depends on a managed resource that has proposed changes elsewhere in the plan.
    • No-op: Explicitly represents that Terraform considered a resource instance but determined no action is required.
  6. Refined unknown value representations in MessagePack

    main

    Refined unknown values (extension code 12) allow providers to understand constraints on a value that will only be determined during the apply phase. This helps in detecting errors during plan.

    Refined values use a MessagePack map with integer keys:

    • 1 (nullness): Boolean. true if definitely null, false if definitely not null.
    • 2 (string prefix): A string representing the known prefix (only for string types).
    • 3 (lower bound): A two-element array [number_value, is_inclusive_boolean] (only for number types).
    • 4 (upper bound): A two-element array [number_value, is_inclusive_boolean] (only for number types).
    • 5 (lower bound length): An integer representing the inclusive lower bound of collection length (for list, set, map).
    • 6 (upper bound length): An integer representing the inclusive upper bound of collection length (for list, set, map).

    Implementation Notes:

    • Unmarshalling code must ignore unknown refinement keys to ensure forward compatibility.
    • A provider producing refined values in PlanResourceChange must honor them in ApplyResourceChange.
    • If encoding an unknown value without refinements, use extension code 0 for backward compatibility.
  7. Understand Terraform Milestone naming conventions

    main

    Terraform uses specific naming conventions for GitHub milestones to indicate the release lifecycle and priority of issues:

    • .x Milestones (e.g., 0.13.x): Issues in these milestones are intended to be fixed during that specific release lifecycle. They are high-priority but do not block a patch release. They should be resolved before the next major release candidate (e.g., 0.14.0 RC1) ships.
    • .0 Milestones (e.g., 0.14.0): Issues in these milestones must be fixed before the corresponding major release candidate (e.g., 0.14.0 RC1) ships. Ideally, they should be fixed before the first beta release (e.g., 0.14.0 beta 1).
  8. How Terraform handles Unicode standards

    main
    Terraform uses Unicode standards for various language features, including identifier tokenization and text segmentation. Because these features rely on multiple external libraries (including the Go standard library, HCL, and go-cty), Terraform typically adopts new Unicode versions in conjunction with upgrading the Go runtime. This ensures consistency across all dependencies, as the Go standard library's Unicode support is tied to its specific version (unicode.Version).
  9. How the Terraform resource instance change lifecycle works

    main

    The resource instance lifecycle is the process of reconciling a user's Configuration with the current state of a remote system to produce a New State.

    This process follows these conceptual steps:

    1. Merge: Terraform Core merges the Configuration (what the user wrote) and the Prior State (the last known state of the remote object) to create a Proposed New State.
    2. Plan: Using resource-type-specific logic, the provider calculates the Initial Planned State (what the object should look like) and eventually the Final Planned State (once all dependencies are known).
    3. Apply: The provider modifies the remote system to match the planned state.
    4. Finalize: The provider returns the New State, which represents the actual result of the modifications. This becomes the Previous Run State for the next operation.

    Providers must handle 'unknown' values in the planned states when values are determined by the remote system during apply or depend on other resources that are not yet known.

  10. Understand the Terraform Plugin Protocol versioning strategy

    main

    The plugin protocol uses major and minor versioning to balance feature updates with backward compatibility.

    Major Versions

    Major versions represent breaking changes. They are encoded directly into the protobuf package name (e.g., tfplugin5 for version 5, tfplugin6 for version 6). This allows a single plugin server to implement and export multiple major versions simultaneously by providing different gRPC services.

    Minor Versions

    Minor versions introduce optional new functionality. They are backward-compatible; if a client (Terraform Core) or server (Plugin) does not recognize a new field or feature, it can ignore it. Minor versions are not represented on the wire but are used for feature detection and human communication.

    Compatibility Matrix

    • Terraform Core: Has a minimum required minor version and a maximum supported major version.
    • Provider Plugins: Specify compatibility as a list of major/minor pairs (e.g., "4.0", "5.2"). A provider supporting "5.2" can work with a Terraform Core that only supports "5.0" because the major version matches and the minor enhancements are optional.
  11. How sub-graphs and dynamic expansion work

    main

    Some vertices can dynamically expand to build and walk separate sub-graphs during their own evaluation. This is necessary when the number of instances is not known during the initial graph construction.

    A primary example is the count argument in a resource block. While the initial plan graph contains one vertex for the resource block, it dynamically expands into a sub-graph containing individual vertices for each instance (e.g., aws_instance.example[0], aws_instance.example[1]).

    Vertices that support this behavior implement the terraform.GraphNodeDynamicExpandable interface. These vertices utilize their own nested graph builder, graph walk, and vertex evaluation steps, following the same fundamental logic as the main graph but using specific transforms and evaluation steps tailored to the sub-graph.

  12. Understand the different state representations in Terraform

    main

    When developing a provider, it is critical to distinguish between the various state objects used during the lifecycle:

    • Configuration: The user-defined values in .tf files. Attributes not defined by the user appear as null. Values may be unknown if they depend on other resources.
    • Prior State: The provider's representation of the remote object from the most recent Read operation.
    • Proposed New State: A preliminary merger of Configuration and Prior State created by Terraform Core. It uses Configuration values if non-null, otherwise falling back to Prior State to preserve 'computed' values.
    • Initial Planned State: A description of the desired remote object state created during the planning phase, potentially containing unknown values.
    • Final Planned State: A complete description of the desired state created during the apply step once all dependencies are resolved.
    • New State: The actual, wholly-known representation of the remote system after the Apply step completes.
    • Previous Run State: The New State from the previous execution. It may be incompatible with the current schema or reflect out-of-band changes made to the remote system.
    • Upgraded State: A version of the Previous Run State that has been transformed by provider-specified logic to match the latest schema.