forked from hashicorp/terraform-json
-
Notifications
You must be signed in to change notification settings - Fork 0
/
plan.go
202 lines (161 loc) · 6.72 KB
/
plan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package tfjson
import (
"encoding/json"
"errors"
"fmt"
"github.com/hashicorp/go-version"
)
// PlanFormatVersionConstraints defines the versions of the JSON plan format
// that are supported by this package.
var PlanFormatVersionConstraints = ">= 0.1, < 2.0"
// ResourceMode is a string representation of the resource type found
// in certain fields in the plan.
type ResourceMode string
const (
// DataResourceMode is the resource mode for data sources.
DataResourceMode ResourceMode = "data"
// ManagedResourceMode is the resource mode for managed resources.
ManagedResourceMode ResourceMode = "managed"
)
// Plan represents the entire contents of an output Terraform plan.
type Plan struct {
// The version of the plan format. This should always match the
// PlanFormatVersion constant in this package, or else an unmarshal
// will be unstable.
FormatVersion string `json:"format_version,omitempty"`
// The version of Terraform used to make the plan.
TerraformVersion string `json:"terraform_version,omitempty"`
// The variables set in the root module when creating the plan.
Variables map[string]*PlanVariable `json:"variables,omitempty"`
// The common state representation of resources within this plan.
// This is a product of the existing state merged with the diff for
// this plan.
PlannedValues *StateValues `json:"planned_values,omitempty"`
// The change operations for resources and data sources within this
// plan.
ResourceChanges []*ResourceChange `json:"resource_changes,omitempty"`
// The change operations for outputs within this plan.
OutputChanges map[string]*Change `json:"output_changes,omitempty"`
// The Terraform state prior to the plan operation. This is the
// same format as PlannedValues, without the current diff merged.
PriorState *State `json:"prior_state,omitempty"`
// The Terraform configuration used to make the plan.
Config *Config `json:"configuration,omitempty"`
// RelevantAttributes represents any resource instances and their
// attributes which may have contributed to the planned changes
RelevantAttributes []ResourceAttribute `json:"relevant_attributes,omitempty"`
}
// ResourceAttribute describes a full path to a resource attribute
type ResourceAttribute struct {
// Resource describes resource instance address (e.g. null_resource.foo)
Resource string `json:"resource"`
// Attribute describes the attribute path using a lossy representation
// of cty.Path. (e.g. ["id"] or ["objects", 0, "val"]).
Attribute []json.RawMessage `json:"attribute"`
}
// Validate checks to ensure that the plan is present, and the
// version matches the version supported by this library.
func (p *Plan) Validate() error {
if p == nil {
return errors.New("plan is nil")
}
if p.FormatVersion == "" {
return errors.New("unexpected plan input, format version is missing")
}
constraint, err := version.NewConstraint(PlanFormatVersionConstraints)
if err != nil {
return fmt.Errorf("invalid version constraint: %w", err)
}
version, err := version.NewVersion(p.FormatVersion)
if err != nil {
return fmt.Errorf("invalid format version %q: %w", p.FormatVersion, err)
}
if !constraint.Check(version) {
return fmt.Errorf("unsupported plan format version: %q does not satisfy %q",
version, constraint)
}
return nil
}
func isStringInSlice(slice []string, s string) bool {
for _, el := range slice {
if el == s {
return true
}
}
return false
}
func (p *Plan) UnmarshalJSON(b []byte) error {
type rawPlan Plan
var plan rawPlan
err := json.Unmarshal(b, &plan)
if err != nil {
return err
}
*p = *(*Plan)(&plan)
return p.Validate()
}
// ResourceChange is a description of an individual change action
// that Terraform plans to use to move from the prior state to a new
// state matching the configuration.
type ResourceChange struct {
// The absolute resource address.
Address string `json:"address,omitempty"`
// The module portion of the above address. Omitted if the instance
// is in the root module.
ModuleAddress string `json:"module_address,omitempty"`
// The resource mode.
Mode ResourceMode `json:"mode,omitempty"`
// The resource type, example: "aws_instance" for aws_instance.foo.
Type string `json:"type,omitempty"`
// The resource name, example: "foo" for aws_instance.foo.
Name string `json:"name,omitempty"`
// The instance key for any resources that have been created using
// "count" or "for_each". If neither of these apply the key will be
// empty.
//
// This value can be either an integer (int) or a string.
Index interface{} `json:"index,omitempty"`
// 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".
ProviderName string `json:"provider_name,omitempty"`
// An identifier used during replacement operations, and can be
// used to identify the exact resource being replaced in state.
DeposedKey string `json:"deposed,omitempty"`
// The data describing the change that will be made to this object.
Change *Change `json:"change,omitempty"`
}
// Change is the representation of a proposed change for an object.
type Change struct {
// The action to be carried out by this change.
Actions Actions `json:"actions,omitempty"`
// Before and After are representations of the object value both
// before and after the action. For create and delete actions,
// either Before or After is unset (respectively). For no-op
// actions, both values will be identical. After will be incomplete
// if there are values within it that won't be known until after
// apply.
Before interface{} `json:"before,"`
After interface{} `json:"after,omitempty"`
// 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.
AfterUnknown interface{} `json:"after_unknown,omitempty"`
// BeforeSensitive and AfterSensitive are object values with similar
// structure to Before and After, but with all sensitive leaf values
// replaced with true, and all non-sensitive leaf values omitted. These
// objects should be combined with Before and After to prevent accidental
// display of sensitive values in user interfaces.
BeforeSensitive interface{} `json:"before_sensitive,omitempty"`
AfterSensitive interface{} `json:"after_sensitive,omitempty"`
}
// PlanVariable is a top-level variable in the Terraform plan.
type PlanVariable struct {
// The value for this variable at plan time.
Value interface{} `json:"value,omitempty"`
}