Skip to content

Latest commit

 

History

History
399 lines (315 loc) · 16.9 KB

File metadata and controls

399 lines (315 loc) · 16.9 KB
page_title description
tfplan/v2 - Imports - Sentinel - HCP Terraform
The tfplan/v2 import provides access to a Terraform plan.

-> Note: This is documentation for the next version of the tfplan Sentinel import, designed specifically for Terraform 0.12. This import requires Terraform 0.12 or higher, and must currently be loaded by path, using an alias, example: import "tfplan/v2" as tfplan.

Import: tfplan/v2

The tfplan/v2 import provides access to a Terraform plan.

A Terraform plan is the file created as a result of terraform plan and is the input to terraform apply. The plan represents the changes that Terraform needs to make to infrastructure to reach the desired state represented by the configuration.

@include 'tfc-package-callouts/policies.mdx'

In addition to the diff data available in the plan, there is a "planned state" that is available through this import, via the planned_values collection. This collection presents the Terraform state as how it might look after the plan data is applied, but is not guaranteed to be the final state.

The data in the tfplan/v2 import is sourced from the JSON configuration file that is generated by the terraform show -json command. For more information on the file format, see the JSON Output Format page.

The entirety of the JSON output file is exposed as a Sentinel map via the raw collection. This allows direct, low-level access to the JSON data, but should only be used in complex situations where the higher-level collections do not serve the purpose.

Import Overview

The tfplan/v2 import is structured as a series of collections, keyed as a specific format depending on the collection.

tfplan/v2
├── terraform_version (string)
├── variables
│   └── (indexed by name)
│       ├── name (string)
│       └── value (value)
├── planned_values
│   ├── outputs (tfstate/v2 outputs representation)
│   └── resources (tfstate/v2 resources representation)
├── resource_changes
│   └── (indexed by address[:deposed])
│       ├── address (string)
│       ├── module_address (string)
│       ├── mode (string)
│       ├── type (string)
│       ├── name (string)
│       ├── index (float (number) or string)
│       ├── provider_name (string)
│       ├── deposed (string)
│       └── change (change representation)
├── resource_drift
│   └── (indexed by address[:deposed])
│       ├── address (string)
│       ├── module_address (string)
│       ├── mode (string)
│       ├── type (string)
│       ├── name (string)
│       ├── index (float (number) or string)
│       ├── provider_name (string)
│       ├── deposed (string)
│       └── change (change representation)
├── output_changes
│   └── (indexed by name)
│       ├── name (string)
│       └── change (change representation)
└── raw (map)

The collections are:

  • variables - The values of variables that have been set in the plan itself. This collection only contains variables set in the root module.
  • planned_values - The state representation of planned values, or an estimation of what the state will look like after the plan is applied.
  • resource_changes - The set of change operations for resources and data sources within this plan.
  • resource_drift - A description of the changes Terraform detected when it compared the most recent state to the prior saved state.
  • output_changes - The changes to outputs within this plan. This collection only contains outputs set in the root module.
  • raw - Access to the raw plan data as stored by HCP Terraform.

These collections are specifically designed to be used with the filter quantifier expression in Sentinel, so that one can collect a list of resources to perform policy checks on without having to write complex discovery code. As an example, the following code will return all aws_instance resource changes, across all modules in the plan:

all_aws_instances = filter tfplan.resource_changes as _, rc {
	rc.mode is "managed" and
		rc.type is "aws_instance"
}

You can add specific attributes to the filter to narrow the search, such as the module address, or the operation being performed. The following code would return resources in a module named foo only, and further narrow the search down to only resources that were being created:

all_aws_instances = filter tfplan.resource_changes as _, rc {
	rc.module_address is "module.foo" and
		rc.mode is "managed" and
		rc.type is "aws_instance" and
		rc.change.actions is ["create"]
}

Change Representation

Certain collections in this import contain a change representation, an object with details about changes to a particular entity, such as a resource (within the resource_changes collection), or output (within the output_changes collection).

(change representation)
├── actions (list)
├── before (value, or map)
├── after (value, or map)
└── after_unknown (boolean, or map of booleans)

This change representation contains the following fields:

  • actions - A list of actions being carried out for this change. The order is important, for example a regular replace operation is denoted by ["delete", "create"], but a create_before_destroy resource will have an operation order of ["create", "delete"].
  • before - The representation of the resource data object value before the action. For create-only actions, this is unset. For no-op actions, this value will be identical with after.
  • after - The representation of the resource data object value after the action. For delete-only actions, this is unset. For no-op actions, this value will be identical with before. Note that unknown values will not show up in this field.
  • after_unknown - A deep object of booleans that denotes any values that are unknown in a resource. These values were previously referred to as "computed" values. If the value cannot be found in this map, then its value should be available within after, so long as the operation supports it.

Actions

As mentioned above, actions show up within the actions field of a change representation and indicate the type of actions being performed as part of the change, and the order that they are being performed in.

The current list of actions are as follows:

  • create - The action will create the associated entity. Depending on the order this appears in, the entity may be created alongside a copy of the entity before replacing it.
  • read - The action will read the associated entity. In practice, seeing this change type should be rare, as reads generally happen before a plan is executed (usually during a refresh).
  • update - The action will update the associated entity in a way that alters its state in some way.
  • delete - The action will remove the associated entity, deleting any applicable state and associated real resources or infrastructure.
  • no-op - No action will be performed on the associated entity.

The actions field is a list, as some real-world actions are actually a composite of more than one primitive action. At this point in time, this is generally only applicable to resource replacement, in which the following action orders apply:

  • Normal replacement: ["delete", "create"] - Applies to default lifecycle configurations.
  • Create-before-destroy: ["create", "delete"] - Applies when create_before_destroy is used in a lifecycle configuration.

Note that, in most situations, the plan will list all "changes", including no-op changes. This makes filtering on change type crucial to the accurate selection of data if you are concerned with the state change of a particular resource.

To filter on a change type, use exact list comparison. For example, the following example from the Import Overview filters on exactly the resources being created only:

all_aws_instances = filter tfplan.resource_changes as _, rc {
	rc.module_address is "module.foo" and
		rc.mode is "managed" and
		rc.type is "aws_instance" and
    rc.change.actions is ["create"]
}

before, after, and after_unknown

The exact attribute changes for a particular operation are outlined in the before and after attributes. Depending on the entity being operated on, this will either be a map (as with resource_changes) or a singular value (as with output_changes).

What you can expect in these fields varies depending on the operation:

  • For fresh create operations, before will generally be null, and after will contain the data you can expect to see after the change.
  • For full delete operations, this will be reversed - before will contain data, and after will be null.
  • Update or replace operations will have data in both fields relevant to their states before and after the operation.
  • No-op operations should have identical data in before and after.

For resources, if a field cannot be found in after, it generally means one of two things:

  • The attribute does not exist in the resource schema. Generally, known attributes that do not have a value will show up as null or otherwise empty in after.
  • The attribute is unknown, that is, it was unable to be determined at plan time and will only be available after apply-time values have been able to be calculated.

In the latter case, there should be a value for the particular attribute in after_unknown, which can be checked to assert that the value is indeed unknown, versus invalid:

import "tfplan/v2" as tfplan

no_unknown_amis = rule {
	all filter tfplan.resource_changes as _, rc {
		rc.module_address is "module.foo" and
			rc.mode is "managed" and
			rc.type is "aws_instance" and
			rc.change.actions is ["create"]
	} as _, rc {
		rc.change.after_unknown.ami else false is false
	}
}

For output changes, after_unknown will simply be true if the value won't be known until the plan is applied.

The terraform_version Value

The top-level terraform_version value in this import gives the Terraform version that made the plan. This can be used to do version validation.

import "tfplan/v2" as tfplan
import "strings"

v = strings.split(tfplan.terraform_version, ".")
version_major = int(v[1])
version_minor = int(v[2])

main = rule {
	version_major is 12 and version_minor >= 19
}

-> NOTE: The above example will give errors when working with pre-release versions (example: 0.12.0beta1). Future versions of this import will include helpers to assist with processing versions that will account for these kinds of exceptions.

The variables Collection

The variables collection is a collection of the variables set in the root module when creating the plan.

This collection is indexed on the name of the variable.

The valid values are:

  • name - The name of the variable, also used as the collection key.
  • value - The value of the variable assigned during the plan.

The planned_values Collection

The planned_values collection is a special collection in that it contains two fields that alias to state collections with the planned state set. This is the best prediction of what the state will look like after the plan is executed.

The two fields are:

  • outputs - The prediction of what output values will look like after the state is applied. For more details on the structure of this collection, see the outputs collection in the tfstate/v2 documentation.
  • resources - The prediction of what resource values will look like after the state is applied. For more details on the structure of this collection, see the resources collection in the tfstate/v2 documentation.

-> NOTE: Unknown values are omitted from the planned_values state representations, regardless of whether or not they existed before. Use resource_changes if awareness of unknown data is important.

The resource_changes and resource_drift Collections

The resource_changes and resource_drift collections are a set of change operations for resources and data sources within this plan.

The resource_drift collection provides a description of the changes Terraform detected when it compared the most recent state to the prior saved state.

The resource_changes collection includes all resources that have been found in the configuration and state, regardless of whether or not they are changing.

~> When resource targeting is in effect, the resource_changes collection will only include the resources specified as targets for the run. This may lead to unexpected outcomes if a policy expects a resource to be present in the plan. To prohibit targeted runs altogether, ensure tfrun.target_addrs is undefined or empty.

This collection is indexed on the complete resource address as the key. If deposed is non-empty, it is appended to the end, and may look something like aws_instance.foo:deposed-abc123.

An element contains the following fields:

  • address - The absolute resource address - also the key for the collection's index, if deposed is empty.

  • module_address - The module portion of the absolute resource address.

  • mode - The resource mode, either managed (resources) or data (data sources).

  • type - The resource type, example: aws_instance for aws_instance.foo.

  • name - The resource name, example: foo for aws_instance.foo.

  • index - The resource index. Can be either a number or a string.

  • provider_name - The name of the provider this resource belongs to. This allows the provider to be interpreted unambiguously in the unusual situation where a provider offers a resource type whose name does not start with its own name, such as the googlebeta provider offering google_compute_instance.

    -> Note: Starting with Terraform 0.13, the provider_name field contains the full source address to the provider in the Terraform Registry. Example: registry.terraform.io/hashicorp/null for the null provider.

  • deposed - An identifier used during replacement operations, and can be used to identify the exact resource being replaced in state.

  • change - The data describing the change that will be made to this resource. For more details, see Change Representation.

The output_changes Collection

The output_changes collection is a collection of the change operations for outputs within this plan.

Only outputs for the root module are included.

This collection is indexed by the name of the output. The fields in a collection value are below:

  • name - The name of the output, also the index key.
  • change - The data describing the change that will be made to this output. For more details, see Change Representation.

The raw Collection

The raw collection exposes the raw, unprocessed plan data, direct from the data stored by HCP Terraform.

This is the same data that is produced by terraform show -json on the plan file for the run this policy check is attached to.

Use of this data is only recommended in expert situations where the data the collections present may not exactly serve the needs of the policy. For more information on the file format, see the JSON Output Format page.

-> NOTE: Although designed to be relatively stable, the actual makeup for the JSON output format is a Terraform CLI concern and as such not managed by HCP Terraform. Use at your own risk, follow the Terraform CLI project, and watch the file format documentation for any changes.