github.com/mkuzmin/terraform@v0.3.7-0.20161118171027-ec4c00ff92a9/command/format_state.go (about) 1 package command 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 "strings" 8 9 "github.com/hashicorp/terraform/terraform" 10 "github.com/mitchellh/colorstring" 11 ) 12 13 // FormatStateOpts are the options for formatting a state. 14 type FormatStateOpts struct { 15 // State is the state to format. This is required. 16 State *terraform.State 17 18 // Color is the colorizer. This is optional. 19 Color *colorstring.Colorize 20 21 // ModuleDepth is the depth of the modules to expand. By default this 22 // is zero which will not expand modules at all. 23 ModuleDepth int 24 } 25 26 // FormatState takes a state and returns a string 27 func FormatState(opts *FormatStateOpts) string { 28 if opts.Color == nil { 29 panic("colorize not given") 30 } 31 32 s := opts.State 33 if len(s.Modules) == 0 { 34 return "The state file is empty. No resources are represented." 35 } 36 37 var buf bytes.Buffer 38 buf.WriteString("[reset]") 39 40 // Format all the modules 41 for _, m := range s.Modules { 42 if len(m.Path)-1 <= opts.ModuleDepth || opts.ModuleDepth == -1 { 43 formatStateModuleExpand(&buf, m, opts) 44 } else { 45 formatStateModuleSingle(&buf, m, opts) 46 } 47 } 48 49 // Write the outputs for the root module 50 m := s.RootModule() 51 if len(m.Outputs) > 0 { 52 buf.WriteString("\nOutputs:\n\n") 53 54 // Sort the outputs 55 ks := make([]string, 0, len(m.Outputs)) 56 for k, _ := range m.Outputs { 57 ks = append(ks, k) 58 } 59 sort.Strings(ks) 60 61 // Output each output k/v pair 62 for _, k := range ks { 63 v := m.Outputs[k] 64 switch output := v.Value.(type) { 65 case string: 66 buf.WriteString(fmt.Sprintf("%s = %s", k, output)) 67 buf.WriteString("\n") 68 case []interface{}: 69 buf.WriteString(formatListOutput("", k, output)) 70 buf.WriteString("\n") 71 case map[string]interface{}: 72 buf.WriteString(formatMapOutput("", k, output)) 73 buf.WriteString("\n") 74 } 75 } 76 } 77 78 return opts.Color.Color(strings.TrimSpace(buf.String())) 79 } 80 81 func formatStateModuleExpand( 82 buf *bytes.Buffer, m *terraform.ModuleState, opts *FormatStateOpts) { 83 var moduleName string 84 if !m.IsRoot() { 85 moduleName = fmt.Sprintf("module.%s", strings.Join(m.Path[1:], ".")) 86 } 87 88 // First get the names of all the resources so we can show them 89 // in alphabetical order. 90 names := make([]string, 0, len(m.Resources)) 91 for name, _ := range m.Resources { 92 names = append(names, name) 93 } 94 sort.Strings(names) 95 96 // Go through each resource and begin building up the output. 97 for _, k := range names { 98 name := k 99 if moduleName != "" { 100 name = moduleName + "." + name 101 } 102 103 rs := m.Resources[k] 104 is := rs.Primary 105 var id string 106 if is != nil { 107 id = is.ID 108 } 109 if id == "" { 110 id = "<not created>" 111 } 112 113 taintStr := "" 114 if rs.Primary != nil && rs.Primary.Tainted { 115 taintStr = " (tainted)" 116 } 117 118 buf.WriteString(fmt.Sprintf("%s:%s\n", name, taintStr)) 119 buf.WriteString(fmt.Sprintf(" id = %s\n", id)) 120 121 if is != nil { 122 // Sort the attributes 123 attrKeys := make([]string, 0, len(is.Attributes)) 124 for ak, _ := range is.Attributes { 125 // Skip the id attribute since we just show the id directly 126 if ak == "id" { 127 continue 128 } 129 130 attrKeys = append(attrKeys, ak) 131 } 132 sort.Strings(attrKeys) 133 134 // Output each attribute 135 for _, ak := range attrKeys { 136 av := is.Attributes[ak] 137 buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) 138 } 139 } 140 } 141 142 buf.WriteString("[reset]\n") 143 } 144 145 func formatStateModuleSingle( 146 buf *bytes.Buffer, m *terraform.ModuleState, opts *FormatStateOpts) { 147 // Header with the module name 148 buf.WriteString(fmt.Sprintf("module.%s\n", strings.Join(m.Path[1:], "."))) 149 150 // Now just write how many resources are in here. 151 buf.WriteString(fmt.Sprintf(" %d resource(s)\n", len(m.Resources))) 152 }