tfplanparse

package module
v0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 2, 2021 License: MIT Imports: 8 Imported by: 1

README

tfplanparse

tfplanparse is a Go library for parsing terraform plan outputs. Supports terraform v0.12 CLI output currently. Does not fully support multiline diffs right now.

NOTE: This library does not parse the file produced by terraform plan -out=<file>. If you want to parse that file, you should use hashicorp/terraform-json.

This project is still WIP and the schemas are subject to change.

Why

By parsing the output from terraform plan into something more machine readable, you can perform some validation and workflows depending on what the output contains. Some example use cases include:

  • Filter out unexpected changes from routine terraform operations
  • Send a notification when a certain type of resource is being modified
  • Trigger additional workflows before terraform apply if a certain resource type is modified

tfplanparse vs terraform-json

You can parse the output from terraform plan using terraform-json by running terraform plan -out=<file> followed by terraform state show -json <file>. However, while the output file is encoded, it contains sensitive information, and terraform state show -json <file> will output this sensitive information in plain text.

With tfplanparse, you can parse the output from terraform plan directly, skipping writing a state file containing sensitive data to disk. Additionally, sensitive data is redacted in the terraform plan output, so the secrets will remain redacted when parsed.

Usage

import "github.com/drlau/tfplanparse"

func main() {
    result, err := tfplanparse.Parse(os.Stdin)
    if err != nil {
        panic(err)
    }

    // or, you can read directly from a file
    fromFile, err := tfplanparse.ParseFromFile("out.stdout")
    if err != nil {
        panic(err)
    }
}

The returned type from Parse and ParseFromFile is []*tfplanparse.ResourceChange. Each ResourceChange corresponds to a single resource in the terraform plan output and has the following fields:

  • Address: Absolute resource address
  • ModuleAddress: Module portion of the absolute address, if any
  • Type: The type of the resource (example: gcp_instance.foo -> "gcp_instance")
  • Name: The name of the resource (example: gcp_instance.foo -> "foo")
  • Index: The index key for resources created with count or for_each
  • UpdateType: The type of update (refer to updatetype.go for possible values)
  • Tainted: Indicates whether the resource is tainted or not
  • AttributeChanges: Planned attribute changes

Each ResourceChange also has the following helper functions:

  • GetBeforeResource: Returns the resource before the planned changes as a map[string]interface{}
  • GetAfterResource: Returns the resource after the planned changes as a map[string]interface{}

Additionally, these helper functions accept the following options:

  • IgnoreComputed
  • IgnoreSensitive
  • IgnoreNoOp
  • ComputedOnly

Documentation

Index

Constants

View Source
const (
	ATTRIBUTE_CHANGE_DELIMITER    = " -> "
	ATTRIBUTE_DEFINITON_DELIMITER = " = "
	SENSITIVE_VALUE               = "(sensitive value)"
	COMPUTED_VALUE                = "(known after apply)"
)
View Source
const (
	NO_CHANGES_STRING    = "No changes. Infrastructure is up-to-date."
	CHANGES_START_STRING = "Terraform will perform the following actions:"
	CHANGES_END_STRING   = "Plan: "
	ERROR_STRING         = "Error: "
)
View Source
const (
	RESOURCE_CREATED                   = " will be created"
	RESOURCE_READ                      = " will be read during apply"
	RESOURCE_READ_VALUES_NOT_YET_KNOWN = " (config refers to values not yet known)"
	RESOURCE_UPDATED_IN_PLACE          = " will be updated in-place"
	RESOURCE_TAINTED                   = " is tainted, so must be replaced"
	RESOURCE_REPLACED                  = " must be replaced"
	RESOURCE_DESTROYED                 = " will be destroyed"
)

Variables

This section is empty.

Functions

func ComputedOnly

func ComputedOnly(a attributeChange) bool

func IgnoreComputed

func IgnoreComputed(a attributeChange) bool

func IgnoreNoOp added in v0.0.9

func IgnoreNoOp(a attributeChange) bool

func IgnoreSensitive

func IgnoreSensitive(a attributeChange) bool

func IsArrayAttributeChangeLine added in v0.0.6

func IsArrayAttributeChangeLine(line string) bool

IsArrayAttributeChangeLine returns true if the line is a valid attribute change This requires the line to start with "+", "-" or "~", not be followed with "resource" or "data", and ends with "[".

func IsArrayAttributeTerminator added in v0.0.6

func IsArrayAttributeTerminator(line string) bool

IsArrayAttributeTerminator returns true if the line is "]" or "] -> null"

func IsAttributeChangeArrayItem added in v0.0.6

func IsAttributeChangeArrayItem(line string) bool

IsAttributeChangeArrayItem returns true if the line is a valid attribute change in an array

func IsAttributeChangeLine

func IsAttributeChangeLine(line string) bool

IsAttributeChangeLine returns true if the line is a valid attribute change This requires the line to start with "+", "-" or "~", and not be followed with "resource"

func IsHeredocAttributeChangeLine added in v0.0.6

func IsHeredocAttributeChangeLine(line string) bool

IsHeredocAttributeChangeLine returns true if the line is a valid attribute change This requires the line to start with "+", "-" or "~", delimited with a space, and the value to start with "<<".

func IsHeredocAttributeTerminator added in v0.0.6

func IsHeredocAttributeTerminator(line string) bool

IsHeredocAttributeTerminator returns true if the line is "EOT" EOT is the only possible terminator for the heredoc Ref: https://github.com/hashicorp/terraform/blob/6a126df0c601ab23689171506bfc1386fea4c96c/command/format/diff.go#L880

func IsJSONEncodeAttributeChangeLine added in v0.0.14

func IsJSONEncodeAttributeChangeLine(line string) bool

IsJSONEncodeAttributeChangeLine returns true if the line is a valid attribute change This requires the line to start with "+", "-" or "~", delimited with a space, and the value to start with "jsonencode(".

func IsJSONEncodeAttributeTerminator added in v0.0.14

func IsJSONEncodeAttributeTerminator(line string) bool

IsJSONEncodeAttributeTerminator returns true if the line is ")" TODO: verify this

func IsMapAttributeChangeLine

func IsMapAttributeChangeLine(line string) bool

IsMapAttributeChangeLine returns true if the line is a valid attribute change This requires the line to start with "+", "-" or "~", not be followed with "resource" or "data", and ends with "{".

func IsMapAttributeTerminator

func IsMapAttributeTerminator(line string) bool

IsMapAttributeTerminator returns true if the line is a "}" or "},"

func IsOneLineEmptyArrayAttribute added in v0.0.6

func IsOneLineEmptyArrayAttribute(line string) bool

IsOneLineEmptyArrayAttribute returns true if the line ends with a "[]"

func IsOneLineEmptyMapAttribute added in v0.0.6

func IsOneLineEmptyMapAttribute(line string) bool

IsOneLineEmptyMapAttribute returns true if the line ends with a "{}"

func IsResourceChangeLine

func IsResourceChangeLine(line string) bool

IsResourceChangeLine returns true if the line is a valid resource change line A valid line starts with the change type, then "resource" or "data", and then the type and name, followed by a { Example: + resource "type" "name" {

func IsResourceCommentLine

func IsResourceCommentLine(line string) bool

IsResourceCommentLine returns true if the line is a valid resource comment line A valid line starts with a "#" and has a suffix describing the change Example: # module.type.item will be created

func IsResourceTerminator added in v0.0.7

func IsResourceTerminator(line string) bool

IsResourceTerminator returns true if the line is a "}"

Types

type ArrayAttributeChange added in v0.0.6

type ArrayAttributeChange struct {
	Name             string
	AttributeChanges []attributeChange
	UpdateType       UpdateType
}

TODO: array attributes can be any attribute change, an array of arrays, or array of maps Type of the attribute can vary, but they're all the same Should use an interface

func NewArrayAttributeChangeFromLine added in v0.0.6

func NewArrayAttributeChangeFromLine(line string) (*ArrayAttributeChange, error)

NewArrayAttributeChangeFromLine initializes an ArrayAttributeChange from a line containing an array attribute change It expects a line that passes the IsArrayAttributeChangeLine check

func (*ArrayAttributeChange) GetAfter added in v0.0.9

func (a *ArrayAttributeChange) GetAfter(opts ...GetBeforeAfterOptions) interface{}

func (*ArrayAttributeChange) GetBefore added in v0.0.9

func (a *ArrayAttributeChange) GetBefore(opts ...GetBeforeAfterOptions) interface{}

func (*ArrayAttributeChange) GetName added in v0.0.9

func (a *ArrayAttributeChange) GetName() string

GetName returns the name of the attribute

func (*ArrayAttributeChange) GetUpdateType added in v0.0.9

func (a *ArrayAttributeChange) GetUpdateType() UpdateType

GetUpdateType returns the UpdateType of the attribute

func (*ArrayAttributeChange) IsComputed added in v0.0.9

func (a *ArrayAttributeChange) IsComputed() bool

IsComputed returns true if the attribute contains a computed value

func (*ArrayAttributeChange) IsNoOp added in v0.0.9

func (a *ArrayAttributeChange) IsNoOp() bool

IsNoOp returns true if the attribute has not changed

func (*ArrayAttributeChange) IsSensitive added in v0.0.9

func (a *ArrayAttributeChange) IsSensitive() bool

IsSensitive returns true if the attribute contains a sensitive value

type AttributeChange

type AttributeChange struct {
	Name       string
	OldValue   interface{}
	NewValue   interface{}
	UpdateType UpdateType
}

func NewAttributeChangeFromArray added in v0.0.6

func NewAttributeChangeFromArray(line string) (*AttributeChange, error)

NewAttributeChangeFromLine initializes an AttributeChange from a line within an Array attribute In an array resource, the attribute change does not have a name

func NewAttributeChangeFromLine

func NewAttributeChangeFromLine(line string) (*AttributeChange, error)

NewAttributeChangeFromLine initializes an AttributeChange from a line containing an attribute change It expects a line that passes the IsAttributeChangeLine check

func (*AttributeChange) GetAfter added in v0.0.9

func (a *AttributeChange) GetAfter(opts ...GetBeforeAfterOptions) interface{}

GetAfter returns the planned value of the attribute

func (*AttributeChange) GetBefore added in v0.0.9

func (a *AttributeChange) GetBefore(opts ...GetBeforeAfterOptions) interface{}

GetBefore returns the initial value of the attribute

func (*AttributeChange) GetName added in v0.0.9

func (a *AttributeChange) GetName() string

GetName returns the name of the attribute

func (*AttributeChange) GetUpdateType added in v0.0.9

func (a *AttributeChange) GetUpdateType() UpdateType

GetUpdateType returns the UpdateType of the attribute

func (*AttributeChange) IsComputed

func (a *AttributeChange) IsComputed() bool

IsComputed returns true if the attribute contains a computed value

func (*AttributeChange) IsNoOp added in v0.0.9

func (a *AttributeChange) IsNoOp() bool

IsNoOp returns true if the attribute has not changed

func (*AttributeChange) IsSensitive

func (a *AttributeChange) IsSensitive() bool

IsSensitive returns true if the attribute contains a sensitive value

type GetBeforeAfterOptions

type GetBeforeAfterOptions func(a attributeChange) bool

type HeredocAttributeChange added in v0.0.6

type HeredocAttributeChange struct {
	Name       string
	Before     []string
	After      []string
	UpdateType UpdateType
}

func NewHeredocAttributeChangeFromLine added in v0.0.6

func NewHeredocAttributeChangeFromLine(line string) (*HeredocAttributeChange, error)

NewHeredocAttributeChangeFromLine initializes a HeredocAttributeChange from a line containing a heredoc change It expects a line that passes the IsHeredocAttributeChangeLine check

func (*HeredocAttributeChange) AddLineToContent added in v0.0.6

func (h *HeredocAttributeChange) AddLineToContent(line string)

func (*HeredocAttributeChange) GetAfter added in v0.0.9

func (h *HeredocAttributeChange) GetAfter(opts ...GetBeforeAfterOptions) interface{}

func (*HeredocAttributeChange) GetBefore added in v0.0.9

func (h *HeredocAttributeChange) GetBefore(opts ...GetBeforeAfterOptions) interface{}

func (*HeredocAttributeChange) GetName added in v0.0.9

func (h *HeredocAttributeChange) GetName() string

GetName returns the name of the attribute

func (*HeredocAttributeChange) GetUpdateType added in v0.0.9

func (h *HeredocAttributeChange) GetUpdateType() UpdateType

GetUpdateType returns the UpdateType of the attribute

func (*HeredocAttributeChange) IsComputed added in v0.0.9

func (h *HeredocAttributeChange) IsComputed() bool

IsComputed returns true if the attribute contains a computed value

func (*HeredocAttributeChange) IsNoOp added in v0.0.9

func (h *HeredocAttributeChange) IsNoOp() bool

IsNoOp returns true if the attribute has not changed

func (*HeredocAttributeChange) IsSensitive added in v0.0.9

func (h *HeredocAttributeChange) IsSensitive() bool

IsSensitive returns true if the attribute contains a sensitive value

type JSONEncodeAttributeChange added in v0.0.14

type JSONEncodeAttributeChange struct {
	Name             string
	AttributeChanges []attributeChange
	UpdateType       UpdateType
}

func NewJSONEncodeAttributeChangeFromLine added in v0.0.14

func NewJSONEncodeAttributeChangeFromLine(line string) (*JSONEncodeAttributeChange, error)

NewJSONEncodeAttributeChangeFromLine initializes a JSONEncodeAttributeChange from a line containing a JSONEncode change It expects a line that passes the IsJSONEncodeAttributeChangeLine check

func (*JSONEncodeAttributeChange) GetAfter added in v0.0.14

func (j *JSONEncodeAttributeChange) GetAfter(opts ...GetBeforeAfterOptions) interface{}

func (*JSONEncodeAttributeChange) GetBefore added in v0.0.14

func (j *JSONEncodeAttributeChange) GetBefore(opts ...GetBeforeAfterOptions) interface{}

func (*JSONEncodeAttributeChange) GetName added in v0.0.14

func (j *JSONEncodeAttributeChange) GetName() string

GetName returns the name of the attribute

func (*JSONEncodeAttributeChange) GetUpdateType added in v0.0.14

func (j *JSONEncodeAttributeChange) GetUpdateType() UpdateType

GetUpdateType returns the UpdateType of the attribute

func (*JSONEncodeAttributeChange) IsComputed added in v0.0.14

func (j *JSONEncodeAttributeChange) IsComputed() bool

IsComputed returns true if the attribute contains a computed value

func (*JSONEncodeAttributeChange) IsNoOp added in v0.0.14

func (j *JSONEncodeAttributeChange) IsNoOp() bool

IsNoOp returns true if the attribute has not changed

func (*JSONEncodeAttributeChange) IsSensitive added in v0.0.14

func (j *JSONEncodeAttributeChange) IsSensitive() bool

IsSensitive returns true if the attribute contains a sensitive value

type MapAttributeChange

type MapAttributeChange struct {
	Name             string
	AttributeChanges []attributeChange
	UpdateType       UpdateType
}

func NewMapAttributeChangeFromLine

func NewMapAttributeChangeFromLine(line string) (*MapAttributeChange, error)

NewMapAttributeChangeFromLine initializes an AttributeChange from a line containing an attribute change It expects a line that passes the IsAttributeChangeLine check

func (*MapAttributeChange) GetAfter added in v0.0.9

func (m *MapAttributeChange) GetAfter(opts ...GetBeforeAfterOptions) interface{}

func (*MapAttributeChange) GetBefore added in v0.0.9

func (m *MapAttributeChange) GetBefore(opts ...GetBeforeAfterOptions) interface{}

func (*MapAttributeChange) GetName added in v0.0.9

func (m *MapAttributeChange) GetName() string

GetName returns the name of the attribute

func (*MapAttributeChange) GetUpdateType added in v0.0.9

func (m *MapAttributeChange) GetUpdateType() UpdateType

GetUpdateType returns the UpdateType of the attribute

func (*MapAttributeChange) IsComputed added in v0.0.9

func (m *MapAttributeChange) IsComputed() bool

IsComputed returns true if the attribute contains a computed value

func (*MapAttributeChange) IsNoOp added in v0.0.9

func (m *MapAttributeChange) IsNoOp() bool

IsNoOp returns true if the attribute has not changed

func (*MapAttributeChange) IsSensitive added in v0.0.9

func (m *MapAttributeChange) IsSensitive() bool

IsSensitive returns true if the attribute contains a sensitive value

type ResourceChange

type ResourceChange struct {
	// Address contains the absolute resource address
	Address string

	// ModuleAddress contains the module portion of the absolute address, if any
	ModuleAddress string

	// The type of the resource
	// Example: gcp_instance.foo -> "gcp_instance"
	Type string

	// The name of the resource
	// Example: gcp_instance.foo -> "foo"
	Name string

	// The index key for resources created with "count" or "for_each"
	// "count" resources will be an int index, and "for_each" will be a string
	Index interface{}

	// UpdateType contains the type of update
	// Refer to updatetype.go for possible values
	UpdateType UpdateType

	// Tainted indicates whether the resource is tainted or not
	Tainted bool

	// AttributeChanges contains all the planned attribute changes
	AttributeChanges []attributeChange
}

func NewResourceChangeFromComment

func NewResourceChangeFromComment(comment string) (*ResourceChange, error)

NewResourceChangeFromComment creates a ResourceChange from a valid resource comment line

func Parse

func Parse(input io.Reader) ([]*ResourceChange, error)

func ParseFromFile

func ParseFromFile(filepath string) ([]*ResourceChange, error)

func (*ResourceChange) GetAfterResource

func (rc *ResourceChange) GetAfterResource(opts ...GetBeforeAfterOptions) map[string]interface{}

func (*ResourceChange) GetBeforeResource

func (rc *ResourceChange) GetBeforeResource(opts ...GetBeforeAfterOptions) map[string]interface{}

type UpdateType

type UpdateType string
const (
	NoOpResource          UpdateType = "no-op"
	NewResource           UpdateType = "created"
	UpdateInPlaceResource UpdateType = "updateInPlace"
	ForceReplaceResource  UpdateType = "forceReplace"
	DestroyResource       UpdateType = "destroyed"
	ReadResource          UpdateType = "read"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL