1package terraform
2
3import (
4	"bytes"
5	"encoding/gob"
6	"fmt"
7	"io"
8	"sync"
9
10	"github.com/zclconf/go-cty/cty"
11
12	"github.com/hashicorp/terraform/configs"
13)
14
15func init() {
16	gob.Register(make([]interface{}, 0))
17	gob.Register(make([]map[string]interface{}, 0))
18	gob.Register(make(map[string]interface{}))
19	gob.Register(make(map[string]string))
20}
21
22// Plan represents a single Terraform execution plan, which contains
23// all the information necessary to make an infrastructure change.
24//
25// A plan has to contain basically the entire state of the world
26// necessary to make a change: the state, diff, config, backend config, etc.
27// This is so that it can run alone without any other data.
28type Plan struct {
29	// Diff describes the resource actions that must be taken when this
30	// plan is applied.
31	Diff *Diff
32
33	// Config represents the entire configuration that was present when this
34	// plan was created.
35	Config *configs.Config
36
37	// State is the Terraform state that was current when this plan was
38	// created.
39	//
40	// It is not allowed to apply a plan that has a stale state, since its
41	// diff could be outdated.
42	State *State
43
44	// Vars retains the variables that were set when creating the plan, so
45	// that the same variables can be applied during apply.
46	Vars map[string]cty.Value
47
48	// Targets, if non-empty, contains a set of resource address strings that
49	// identify graph nodes that were selected as targets for plan.
50	//
51	// When targets are set, any graph node that is not directly targeted or
52	// indirectly targeted via dependencies is excluded from the graph.
53	Targets []string
54
55	// TerraformVersion is the version of Terraform that was used to create
56	// this plan.
57	//
58	// It is not allowed to apply a plan created with a different version of
59	// Terraform, since the other fields of this structure may be interpreted
60	// in different ways between versions.
61	TerraformVersion string
62
63	// ProviderSHA256s is a map giving the SHA256 hashes of the exact binaries
64	// used as plugins for each provider during plan.
65	//
66	// These must match between plan and apply to ensure that the diff is
67	// correctly interpreted, since different provider versions may have
68	// different attributes or attribute value constraints.
69	ProviderSHA256s map[string][]byte
70
71	// Backend is the backend that this plan should use and store data with.
72	Backend *BackendState
73
74	// Destroy indicates that this plan was created for a full destroy operation
75	Destroy bool
76
77	once sync.Once
78}
79
80func (p *Plan) String() string {
81	buf := new(bytes.Buffer)
82	buf.WriteString("DIFF:\n\n")
83	buf.WriteString(p.Diff.String())
84	buf.WriteString("\n\nSTATE:\n\n")
85	buf.WriteString(p.State.String())
86	return buf.String()
87}
88
89func (p *Plan) init() {
90	p.once.Do(func() {
91		if p.Diff == nil {
92			p.Diff = new(Diff)
93			p.Diff.init()
94		}
95
96		if p.State == nil {
97			p.State = new(State)
98			p.State.init()
99		}
100
101		if p.Vars == nil {
102			p.Vars = make(map[string]cty.Value)
103		}
104	})
105}
106
107// The format byte is prefixed into the plan file format so that we have
108// the ability in the future to change the file format if we want for any
109// reason.
110const planFormatMagic = "tfplan"
111const planFormatVersion byte = 2
112
113// ReadPlan reads a plan structure out of a reader in the format that
114// was written by WritePlan.
115func ReadPlan(src io.Reader) (*Plan, error) {
116	return nil, fmt.Errorf("terraform.ReadPlan is no longer in use; use planfile.Open instead")
117}
118
119// WritePlan writes a plan somewhere in a binary format.
120func WritePlan(d *Plan, dst io.Writer) error {
121	return fmt.Errorf("terraform.WritePlan is no longer in use; use planfile.Create instead")
122}
123