terraform-json

repository·main·Indexed 41 days ago

https://github.com/hashicorp/terraform-json

A Go library providing data types for parsing the JSON output of `terraform show -json` and `terraform providers schema -json`. It serves as a stable interface for external tools to consume Terraform's state and schema data, including types for resource changes (Action/Actions), conditional check results (CheckStatus), and configuration structures (Config, ConfigModule, ConfigResource).

Tokens
17.5K
Snippets
63
Records
77
Agent score
48%

What's inside terraform-json

  1. Understand the purpose of terraform-json

    main

    The terraform-json library provides Go data types designed to parse the JSON output produced by specific Terraform commands. It serves as both a parsing library and a de facto documentation reference for the Terraform JSON formats.

    It is primarily intended for decoding the following command outputs:

    • terraform show -json
    • terraform providers schema -json

    Use this library when you need to decode core stable data types for inspection or analysis, but do not intend to emit JSON that must strictly match Terraform's internal semantic format.

  2. Determine if terraform-json is suitable for your use case

    main

    The Terraform core team recommends against using terraform-json if your application requires any of the following:

    • Forward-compatibility: The library represents a snapshot of the Terraform JSON output format and may lag behind new Terraform releases. If you need guaranteed compatibility with future Terraform versions, implement your own custom decoders.
    • Writing JSON output: The structures in this library are not guaranteed to emit JSON that is semantically equivalent to Terraform's own output. For robustly writing JSON for consumption by other Terraform-aware systems, implement your own custom encoders.
    • Filtering or round-tripping: This library drops unknown attributes. If your application performs a read-modify-write operation (filtering data and writing it back), you will silently drop new attributes introduced in newer Terraform versions. For round-tripping, implement a custom decoder/encoder that preserves unknown attributes.
  3. Build the Round-Trip Dumper tool

    main

    To use the Round-Trip Dumper/Diagnostic Tool, you can build the binary using Go. This tool loads a Terraform plan JSON file and immediately dumps it back to stdout, which is useful for troubleshooting large parsing errors.

    To build the binary, run the following command from the cmd/round-trip-dumper directory:

    go build ./
  4. Understand the ProviderSchemas structure

    main

    The ProviderSchemas struct acts as a registry for all schemas used in a configuration. It contains:

    • FormatVersion: The version of the JSON plan format.
    • Schemas: A map of provider types (e.g., "hashicorp/aws") to their respective ProviderSchema.
    type ProviderSchemas struct {
    	FormatVersion string                       `json:"format_version,omitempty"` 
    	Schemas       map[string]*ProviderSchema `json:"provider_schemas,omitempty"` 
    }
  5. Define and navigate Schema blocks and attributes

    main

    Terraform schemas are hierarchical. A Schema contains a Block, which contains Attributes and NestedBlocks (of type SchemaBlockType).

    • SchemaBlock: Contains Attributes (key-value pairs) and NestedBlocks (complex structures).
    • SchemaAttribute: Defines a single value. It uses either AttributeType (a cty.Type) or AttributeNestedType (for complex nested structures). It includes metadata like Required, Optional, Computed, Sensitive, and Deprecated.
    • SchemaBlockType: Defines how nested blocks behave using a NestingMode.
  6. Define Terraform modules and resources using StateValues

    main

    The StateValues type provides a common representation for both existing state and planned state. It contains:

    • Outputs: A map of StateOutput objects.
    • RootModule: A pointer to the StateModule representing the root of the configuration.

    StateModule can represent the root or child modules and contains a list of Resources and ChildModules.

    // Accessing the root module and its resources
    root := state.Values.RootModule
    for _, resource := range root.Resources {
        fmt.Printf("Resource Address: %s\n", resource.Address)
    }
  7. Handle resource imports in a plan

    main

    If a resource is being imported during the plan, the ResourceChange.Change object will contain an Importing field. This field contains:

    • ID: The original ID used to target the import.
    • Unknown: A boolean indicating if the ID was unknown at plan time.
    • Identity: The identity used to target the resource for import.
  8. Distinguish between null and unknown values using UnknownConstantValue

    main

    In Terraform, there is a distinction between an explicit null and a value that is unknown because it depends on references that cannot be resolved at parse-time.

    • Explicit Null: Represented by a nil value in the ConstantValue field of ExpressionData.
    • Unknown Value: Represented by the UnknownConstantValue singleton. When unmarshaling JSON, if the references array is non-empty, the library automatically sets ConstantValue to UnknownConstantValue to signal that the value is unresolved.
    if expr.ConstantValue == tfjson.UnknownConstantValue {
    	// The value is unknown due to unresolved references
    } else if expr.ConstantValue == nil {
    	// The value is an explicit null
    }
  9. Understand the Plan structure

    main

    The Plan struct is the root object representing the entire output of a Terraform plan. Key fields include:

    • FormatVersion: The version of the JSON plan format.
    • TerraformVersion: The version of Terraform that generated the plan.
    • Variables: A map of top-level PlanVariable objects.
    • PlannedValues: The state representation after changes are applied.
    • ResourceChanges: A list of ResourceChange objects describing actions for resources and data sources.
    • ResourceDrift: Changes resulting from resource drift.
    • DeferredChanges: Changes that are deferred (e.g., due to unknown values).
    • OutputChanges: Changes to Terraform outputs.
    • PriorState: The state before the plan operation.
    • Config: The Terraform configuration used.
  10. Represent Terraform resource changes with Action and Actions

    main

    The tfjson package provides types to represent Terraform resource change operations.

    • Action: A string type representing a single operation (e.g., create, update).
    • Actions: A slice of Action types. Because some Terraform operations are composite (like a replacement), you should use the Actions type and its helper methods to determine the nature of a change rather than inspecting individual actions manually.

    Common single actions include ActionCreate, ActionUpdate, and ActionDelete. Composite operations like replacement are represented as a sequence of actions within the Actions slice.

    import "github.com/hashicorp/terraform-json"
    
    // Example of checking for a replacement operation
    var change tfjson.Actions = tfjson.Actions{tfjson.ActionDelete, tfjson.ActionCreate}
    
    if change.Replace() {
        // Handle resource replacement logic
    }
  11. Analyze ResourceChange and Change actions

    main

    A ResourceChange describes how a specific resource (identified by Address, Type, and Name) will move from its prior state to a new state.

    Each ResourceChange contains a Change object which includes:

    • Actions: The specific operations to perform (e.g., create, read, update, delete).
    • Before / After: The state of the resource before and after the action.
    • AfterUnknown: A map indicating which values in the After state are unknown until apply time.
    • BeforeSensitive / AfterSensitive: Versions of the state where sensitive values are masked to prevent accidental exposure.
    • ReplacePaths: Paths to attributes causing a resource replacement instead of a simple update.