]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/command/format/state.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / command / format / state.go
1 package format
2
3 import (
4 "bytes"
5 "fmt"
6 "sort"
7 "strings"
8
9 "github.com/zclconf/go-cty/cty"
10
11 "github.com/hashicorp/terraform/addrs"
12 "github.com/hashicorp/terraform/configs/configschema"
13 "github.com/hashicorp/terraform/plans"
14 "github.com/hashicorp/terraform/states"
15 "github.com/hashicorp/terraform/terraform"
16 "github.com/mitchellh/colorstring"
17 )
18
19 // StateOpts are the options for formatting a state.
20 type StateOpts struct {
21 // State is the state to format. This is required.
22 State *states.State
23
24 // Schemas are used to decode attributes. This is required.
25 Schemas *terraform.Schemas
26
27 // Color is the colorizer. This is optional.
28 Color *colorstring.Colorize
29 }
30
31 // State takes a state and returns a string
32 func State(opts *StateOpts) string {
33 if opts.Color == nil {
34 panic("colorize not given")
35 }
36
37 if opts.Schemas == nil {
38 panic("schemas not given")
39 }
40
41 s := opts.State
42 if len(s.Modules) == 0 {
43 return "The state file is empty. No resources are represented."
44 }
45
46 buf := bytes.NewBufferString("[reset]")
47 p := blockBodyDiffPrinter{
48 buf: buf,
49 color: opts.Color,
50 action: plans.NoOp,
51 }
52
53 // Format all the modules
54 for _, m := range s.Modules {
55 formatStateModule(p, m, opts.Schemas)
56 }
57
58 // Write the outputs for the root module
59 m := s.RootModule()
60
61 if m.OutputValues != nil {
62 if len(m.OutputValues) > 0 {
63 p.buf.WriteString("Outputs:\n\n")
64 }
65
66 // Sort the outputs
67 ks := make([]string, 0, len(m.OutputValues))
68 for k := range m.OutputValues {
69 ks = append(ks, k)
70 }
71 sort.Strings(ks)
72
73 // Output each output k/v pair
74 for _, k := range ks {
75 v := m.OutputValues[k]
76 p.buf.WriteString(fmt.Sprintf("%s = ", k))
77 p.writeValue(v.Value, plans.NoOp, 0)
78 p.buf.WriteString("\n\n")
79 }
80 }
81
82 return opts.Color.Color(strings.TrimSpace(p.buf.String()))
83
84 }
85
86 func formatStateModule(p blockBodyDiffPrinter, m *states.Module, schemas *terraform.Schemas) {
87 // First get the names of all the resources so we can show them
88 // in alphabetical order.
89 names := make([]string, 0, len(m.Resources))
90 for name := range m.Resources {
91 names = append(names, name)
92 }
93 sort.Strings(names)
94
95 // Go through each resource and begin building up the output.
96 for _, key := range names {
97 for k, v := range m.Resources[key].Instances {
98 addr := m.Resources[key].Addr
99
100 taintStr := ""
101 if v.Current.Status == 'T' {
102 taintStr = "(tainted)"
103 }
104 p.buf.WriteString(fmt.Sprintf("# %s: %s\n", addr.Absolute(m.Addr).Instance(k), taintStr))
105
106 var schema *configschema.Block
107 provider := m.Resources[key].ProviderConfig.ProviderConfig.StringCompact()
108 if _, exists := schemas.Providers[provider]; !exists {
109 // This should never happen in normal use because we should've
110 // loaded all of the schemas and checked things prior to this
111 // point. We can't return errors here, but since this is UI code
112 // we will try to do _something_ reasonable.
113 p.buf.WriteString(fmt.Sprintf("# missing schema for provider %q\n\n", provider))
114 continue
115 }
116
117 switch addr.Mode {
118 case addrs.ManagedResourceMode:
119 schema, _ = schemas.ResourceTypeConfig(
120 provider,
121 addr.Mode,
122 addr.Type,
123 )
124 if schema == nil {
125 p.buf.WriteString(fmt.Sprintf(
126 "# missing schema for provider %q resource type %s\n\n", provider, addr.Type))
127 continue
128 }
129
130 p.buf.WriteString(fmt.Sprintf(
131 "resource %q %q {",
132 addr.Type,
133 addr.Name,
134 ))
135 case addrs.DataResourceMode:
136 schema, _ = schemas.ResourceTypeConfig(
137 provider,
138 addr.Mode,
139 addr.Type,
140 )
141 if schema == nil {
142 p.buf.WriteString(fmt.Sprintf(
143 "# missing schema for provider %q data source %s\n\n", provider, addr.Type))
144 continue
145 }
146
147 p.buf.WriteString(fmt.Sprintf(
148 "data %q %q {",
149 addr.Type,
150 addr.Name,
151 ))
152 default:
153 // should never happen, since the above is exhaustive
154 p.buf.WriteString(addr.String())
155 }
156
157 val, err := v.Current.Decode(schema.ImpliedType())
158 if err != nil {
159 fmt.Println(err.Error())
160 break
161 }
162
163 path := make(cty.Path, 0, 3)
164 bodyWritten := p.writeBlockBodyDiff(schema, val.Value, val.Value, 2, path)
165 if bodyWritten {
166 p.buf.WriteString("\n")
167 }
168
169 p.buf.WriteString("}\n\n")
170 }
171 }
172 p.buf.WriteString("[reset]\n")
173 }
174
175 func formatNestedList(indent string, outputList []interface{}) string {
176 outputBuf := new(bytes.Buffer)
177 outputBuf.WriteString(fmt.Sprintf("%s[", indent))
178
179 lastIdx := len(outputList) - 1
180
181 for i, value := range outputList {
182 outputBuf.WriteString(fmt.Sprintf("\n%s%s%s", indent, " ", value))
183 if i != lastIdx {
184 outputBuf.WriteString(",")
185 }
186 }
187
188 outputBuf.WriteString(fmt.Sprintf("\n%s]", indent))
189 return strings.TrimPrefix(outputBuf.String(), "\n")
190 }
191
192 func formatListOutput(indent, outputName string, outputList []interface{}) string {
193 keyIndent := ""
194
195 outputBuf := new(bytes.Buffer)
196
197 if outputName != "" {
198 outputBuf.WriteString(fmt.Sprintf("%s%s = [", indent, outputName))
199 keyIndent = " "
200 }
201
202 lastIdx := len(outputList) - 1
203
204 for i, value := range outputList {
205 switch typedValue := value.(type) {
206 case string:
207 outputBuf.WriteString(fmt.Sprintf("\n%s%s%s", indent, keyIndent, value))
208 case []interface{}:
209 outputBuf.WriteString(fmt.Sprintf("\n%s%s", indent,
210 formatNestedList(indent+keyIndent, typedValue)))
211 case map[string]interface{}:
212 outputBuf.WriteString(fmt.Sprintf("\n%s%s", indent,
213 formatNestedMap(indent+keyIndent, typedValue)))
214 }
215
216 if lastIdx != i {
217 outputBuf.WriteString(",")
218 }
219 }
220
221 if outputName != "" {
222 if len(outputList) > 0 {
223 outputBuf.WriteString(fmt.Sprintf("\n%s]", indent))
224 } else {
225 outputBuf.WriteString("]")
226 }
227 }
228
229 return strings.TrimPrefix(outputBuf.String(), "\n")
230 }
231
232 func formatNestedMap(indent string, outputMap map[string]interface{}) string {
233 ks := make([]string, 0, len(outputMap))
234 for k, _ := range outputMap {
235 ks = append(ks, k)
236 }
237 sort.Strings(ks)
238
239 outputBuf := new(bytes.Buffer)
240 outputBuf.WriteString(fmt.Sprintf("%s{", indent))
241
242 lastIdx := len(outputMap) - 1
243 for i, k := range ks {
244 v := outputMap[k]
245 outputBuf.WriteString(fmt.Sprintf("\n%s%s = %v", indent+" ", k, v))
246
247 if lastIdx != i {
248 outputBuf.WriteString(",")
249 }
250 }
251
252 outputBuf.WriteString(fmt.Sprintf("\n%s}", indent))
253
254 return strings.TrimPrefix(outputBuf.String(), "\n")
255 }
256
257 func formatMapOutput(indent, outputName string, outputMap map[string]interface{}) string {
258 ks := make([]string, 0, len(outputMap))
259 for k, _ := range outputMap {
260 ks = append(ks, k)
261 }
262 sort.Strings(ks)
263
264 keyIndent := ""
265
266 outputBuf := new(bytes.Buffer)
267 if outputName != "" {
268 outputBuf.WriteString(fmt.Sprintf("%s%s = {", indent, outputName))
269 keyIndent = " "
270 }
271
272 for _, k := range ks {
273 v := outputMap[k]
274 outputBuf.WriteString(fmt.Sprintf("\n%s%s%s = %v", indent, keyIndent, k, v))
275 }
276
277 if outputName != "" {
278 if len(outputMap) > 0 {
279 outputBuf.WriteString(fmt.Sprintf("\n%s}", indent))
280 } else {
281 outputBuf.WriteString("}")
282 }
283 }
284
285 return strings.TrimPrefix(outputBuf.String(), "\n")
286 }