forked from hashicorp/terraform
-
Notifications
You must be signed in to change notification settings - Fork 0
/
format_state.go
152 lines (127 loc) · 3.54 KB
/
format_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
package command
import (
"bytes"
"fmt"
"sort"
"strings"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/colorstring"
)
// FormatStateOpts are the options for formatting a state.
type FormatStateOpts struct {
// State is the state to format. This is required.
State *terraform.State
// Color is the colorizer. This is optional.
Color *colorstring.Colorize
// ModuleDepth is the depth of the modules to expand. By default this
// is zero which will not expand modules at all.
ModuleDepth int
}
// FormatState takes a state and returns a string
func FormatState(opts *FormatStateOpts) string {
if opts.Color == nil {
panic("colorize not given")
}
s := opts.State
if len(s.Modules) == 0 {
return "The state file is empty. No resources are represented."
}
var buf bytes.Buffer
buf.WriteString("[reset]")
// Format all the modules
for _, m := range s.Modules {
if len(m.Path)-1 <= opts.ModuleDepth || opts.ModuleDepth == -1 {
formatStateModuleExpand(&buf, m, opts)
} else {
formatStateModuleSingle(&buf, m, opts)
}
}
// Write the outputs for the root module
m := s.RootModule()
if len(m.Outputs) > 0 {
buf.WriteString("\nOutputs:\n\n")
// Sort the outputs
ks := make([]string, 0, len(m.Outputs))
for k, _ := range m.Outputs {
ks = append(ks, k)
}
sort.Strings(ks)
// Output each output k/v pair
for _, k := range ks {
v := m.Outputs[k]
switch output := v.Value.(type) {
case string:
buf.WriteString(fmt.Sprintf("%s = %s", k, output))
buf.WriteString("\n")
case []interface{}:
buf.WriteString(formatListOutput("", k, output))
buf.WriteString("\n")
case map[string]interface{}:
buf.WriteString(formatMapOutput("", k, output))
buf.WriteString("\n")
}
}
}
return opts.Color.Color(strings.TrimSpace(buf.String()))
}
func formatStateModuleExpand(
buf *bytes.Buffer, m *terraform.ModuleState, opts *FormatStateOpts) {
var moduleName string
if !m.IsRoot() {
moduleName = fmt.Sprintf("module.%s", strings.Join(m.Path[1:], "."))
}
// First get the names of all the resources so we can show them
// in alphabetical order.
names := make([]string, 0, len(m.Resources))
for name, _ := range m.Resources {
names = append(names, name)
}
sort.Strings(names)
// Go through each resource and begin building up the output.
for _, k := range names {
name := k
if moduleName != "" {
name = moduleName + "." + name
}
rs := m.Resources[k]
is := rs.Primary
var id string
if is != nil {
id = is.ID
}
if id == "" {
id = "<not created>"
}
taintStr := ""
if rs.Primary != nil && rs.Primary.Tainted {
taintStr = " (tainted)"
}
buf.WriteString(fmt.Sprintf("%s:%s\n", name, taintStr))
buf.WriteString(fmt.Sprintf(" id = %s\n", id))
if is != nil {
// Sort the attributes
attrKeys := make([]string, 0, len(is.Attributes))
for ak, _ := range is.Attributes {
// Skip the id attribute since we just show the id directly
if ak == "id" {
continue
}
attrKeys = append(attrKeys, ak)
}
sort.Strings(attrKeys)
// Output each attribute
for _, ak := range attrKeys {
av := is.Attributes[ak]
buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av))
}
}
}
buf.WriteString("[reset]\n")
}
func formatStateModuleSingle(
buf *bytes.Buffer, m *terraform.ModuleState, opts *FormatStateOpts) {
// Header with the module name
buf.WriteString(fmt.Sprintf("module.%s\n", strings.Join(m.Path[1:], ".")))
// Now just write how many resources are in here.
buf.WriteString(fmt.Sprintf(" %d resource(s)\n", len(m.Resources)))
}