forked from hashicorp/terraform-json
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstate.go
206 lines (166 loc) · 6.46 KB
/
state.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
203
204
205
206
package tfjson
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/hashicorp/go-version"
"github.com/zclconf/go-cty/cty"
)
// StateFormatVersionConstraints defines the versions of the JSON state format
// that are supported by this package.
var StateFormatVersionConstraints = ">= 0.1, < 2.0"
// State is the top-level representation of a Terraform state.
type State struct {
// useJSONNumber opts into the behavior of calling
// json.Decoder.UseNumber prior to decoding the state, which turns
// numbers into json.Numbers instead of float64s. Set it using
// State.UseJSONNumber.
useJSONNumber bool
// The version of the state format. This should always match the
// StateFormatVersion constant in this package, or else am
// unmarshal will be unstable.
FormatVersion string `json:"format_version,omitempty"`
// The Terraform version used to make the state.
TerraformVersion string `json:"terraform_version,omitempty"`
// The values that make up the state.
Values *StateValues `json:"values,omitempty"`
}
// UseJSONNumber controls whether the State will be decoded using the
// json.Number behavior or the float64 behavior. When b is true, the State will
// represent numbers in StateOutputs as json.Numbers. When b is false, the
// State will represent numbers in StateOutputs as float64s.
func (s *State) UseJSONNumber(b bool) {
s.useJSONNumber = b
}
// Validate checks to ensure that the state is present, and the
// version matches the version supported by this library.
func (s *State) Validate() error {
if s == nil {
return errors.New("state is nil")
}
if s.FormatVersion == "" {
return errors.New("unexpected state input, format version is missing")
}
constraint, err := version.NewConstraint(StateFormatVersionConstraints)
if err != nil {
return fmt.Errorf("invalid version constraint: %w", err)
}
version, err := version.NewVersion(s.FormatVersion)
if err != nil {
return fmt.Errorf("invalid format version %q: %w", s.FormatVersion, err)
}
if !constraint.Check(version) {
return fmt.Errorf("unsupported state format version: %q does not satisfy %q",
version, constraint)
}
return nil
}
func (s *State) UnmarshalJSON(b []byte) error {
type rawState State
var state rawState
dec := json.NewDecoder(bytes.NewReader(b))
if s.useJSONNumber {
dec.UseNumber()
}
err := dec.Decode(&state)
if err != nil {
return err
}
*s = *(*State)(&state)
return s.Validate()
}
// StateValues is the common representation of resolved values for both the
// prior state (which is always complete) and the planned new state.
type StateValues struct {
// The Outputs for this common state representation.
Outputs map[string]*StateOutput `json:"outputs,omitempty"`
// The root module in this state representation.
RootModule *StateModule `json:"root_module,omitempty"`
}
// StateModule is the representation of a module in the common state
// representation. This can be the root module or a child module.
type StateModule struct {
// All resources or data sources within this module.
Resources []*StateResource `json:"resources,omitempty"`
// The absolute module address, omitted for the root module.
Address string `json:"address,omitempty"`
// Any child modules within this module.
ChildModules []*StateModule `json:"child_modules,omitempty"`
}
// StateResource is the representation of a resource in the common
// state representation.
type StateResource struct {
// The absolute resource address.
Address string `json:"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"`
// The version of the resource type schema the "values" property
// conforms to.
SchemaVersion uint64 `json:"schema_version,"`
// The JSON representation of the attribute values of the resource,
// whose structure depends on the resource type schema. Any unknown
// values are omitted or set to null, making them indistinguishable
// from absent values.
AttributeValues map[string]interface{} `json:"values,omitempty"`
// The JSON representation of the sensitivity of the resource's
// attribute values. Only attributes which are sensitive
// are included in this structure.
SensitiveValues json.RawMessage `json:"sensitive_values,omitempty"`
// The addresses of the resources that this resource depends on.
DependsOn []string `json:"depends_on,omitempty"`
// If true, the resource has been marked as tainted and will be
// re-created on the next update.
Tainted bool `json:"tainted,omitempty"`
// DeposedKey is set if the resource instance has been marked Deposed and
// will be destroyed on the next apply.
DeposedKey string `json:"deposed_key,omitempty"`
}
// StateOutput represents an output value in a common state
// representation.
type StateOutput struct {
// Whether or not the output was marked as sensitive.
Sensitive bool `json:"sensitive"`
// The value of the output.
Value interface{} `json:"value,omitempty"`
// The type of the output.
Type cty.Type `json:"type,omitempty"`
}
// jsonStateOutput describes an output value in a middle-step internal
// representation before marshalled into a more useful StateOutput with cty.Type.
//
// This avoid panic on marshalling cty.NilType (from cty upstream)
// which the default Go marshaller cannot ignore because it's a
// not nil-able struct.
type jsonStateOutput struct {
Sensitive bool `json:"sensitive"`
Value interface{} `json:"value,omitempty"`
Type json.RawMessage `json:"type,omitempty"`
}
func (so *StateOutput) MarshalJSON() ([]byte, error) {
jsonSa := &jsonStateOutput{
Sensitive: so.Sensitive,
Value: so.Value,
}
if so.Type != cty.NilType {
outputType, _ := so.Type.MarshalJSON()
jsonSa.Type = outputType
}
return json.Marshal(jsonSa)
}