github.com/mehmetalisavas/terraform@v0.7.10/command/output.go (about) 1 package command 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "flag" 7 "fmt" 8 "sort" 9 "strings" 10 ) 11 12 // OutputCommand is a Command implementation that reads an output 13 // from a Terraform state and prints it. 14 type OutputCommand struct { 15 Meta 16 } 17 18 func (c *OutputCommand) Run(args []string) int { 19 args = c.Meta.process(args, false) 20 21 var module string 22 var jsonOutput bool 23 24 cmdFlags := flag.NewFlagSet("output", flag.ContinueOnError) 25 cmdFlags.BoolVar(&jsonOutput, "json", false, "json") 26 cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path") 27 cmdFlags.StringVar(&module, "module", "", "module") 28 cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } 29 30 if err := cmdFlags.Parse(args); err != nil { 31 return 1 32 } 33 34 args = cmdFlags.Args() 35 if len(args) > 1 { 36 c.Ui.Error( 37 "The output command expects exactly one argument with the name\n" + 38 "of an output variable or no arguments to show all outputs.\n") 39 cmdFlags.Usage() 40 return 1 41 } 42 43 name := "" 44 if len(args) > 0 { 45 name = args[0] 46 } 47 48 stateStore, err := c.Meta.State() 49 if err != nil { 50 c.Ui.Error(fmt.Sprintf("Error reading state: %s", err)) 51 return 1 52 } 53 54 if module == "" { 55 module = "root" 56 } else { 57 module = "root." + module 58 } 59 60 // Get the proper module we want to get outputs for 61 modPath := strings.Split(module, ".") 62 63 state := stateStore.State() 64 mod := state.ModuleByPath(modPath) 65 66 if mod == nil { 67 c.Ui.Error(fmt.Sprintf( 68 "The module %s could not be found. There is nothing to output.", 69 module)) 70 return 1 71 } 72 73 if state.Empty() || len(mod.Outputs) == 0 { 74 c.Ui.Error(fmt.Sprintf( 75 "The state file has no outputs defined. Define an output\n" + 76 "in your configuration with the `output` directive and re-run\n" + 77 "`terraform apply` for it to become available.")) 78 return 1 79 } 80 81 if name == "" { 82 if jsonOutput { 83 jsonOutputs, err := json.MarshalIndent(mod.Outputs, "", " ") 84 if err != nil { 85 return 1 86 } 87 88 c.Ui.Output(string(jsonOutputs)) 89 return 0 90 } else { 91 c.Ui.Output(outputsAsString(state, modPath, nil, false)) 92 return 0 93 } 94 } 95 96 v, ok := mod.Outputs[name] 97 if !ok { 98 c.Ui.Error(fmt.Sprintf( 99 "The output variable requested could not be found in the state\n" + 100 "file. If you recently added this to your configuration, be\n" + 101 "sure to run `terraform apply`, since the state won't be updated\n" + 102 "with new output variables until that command is run.")) 103 return 1 104 } 105 106 if jsonOutput { 107 jsonOutputs, err := json.MarshalIndent(v, "", " ") 108 if err != nil { 109 return 1 110 } 111 112 c.Ui.Output(string(jsonOutputs)) 113 } else { 114 switch output := v.Value.(type) { 115 case string: 116 c.Ui.Output(output) 117 return 0 118 case []interface{}: 119 c.Ui.Output(formatListOutput("", "", output)) 120 return 0 121 case map[string]interface{}: 122 c.Ui.Output(formatMapOutput("", "", output)) 123 return 0 124 default: 125 c.Ui.Error(fmt.Sprintf("Unknown output type: %T", v.Type)) 126 return 1 127 } 128 } 129 130 return 0 131 } 132 133 func formatNestedList(indent string, outputList []interface{}) string { 134 outputBuf := new(bytes.Buffer) 135 outputBuf.WriteString(fmt.Sprintf("%s[", indent)) 136 137 lastIdx := len(outputList) - 1 138 139 for i, value := range outputList { 140 outputBuf.WriteString(fmt.Sprintf("\n%s%s%s", indent, " ", value)) 141 if i != lastIdx { 142 outputBuf.WriteString(",") 143 } 144 } 145 146 outputBuf.WriteString(fmt.Sprintf("\n%s]", indent)) 147 return strings.TrimPrefix(outputBuf.String(), "\n") 148 } 149 150 func formatListOutput(indent, outputName string, outputList []interface{}) string { 151 keyIndent := "" 152 153 outputBuf := new(bytes.Buffer) 154 155 if outputName != "" { 156 outputBuf.WriteString(fmt.Sprintf("%s%s = [", indent, outputName)) 157 keyIndent = " " 158 } 159 160 lastIdx := len(outputList) - 1 161 162 for i, value := range outputList { 163 switch typedValue := value.(type) { 164 case string: 165 outputBuf.WriteString(fmt.Sprintf("\n%s%s%s", indent, keyIndent, value)) 166 case []interface{}: 167 outputBuf.WriteString(fmt.Sprintf("\n%s%s", indent, 168 formatNestedList(indent+keyIndent, typedValue))) 169 case map[string]interface{}: 170 outputBuf.WriteString(fmt.Sprintf("\n%s%s", indent, 171 formatNestedMap(indent+keyIndent, typedValue))) 172 } 173 174 if lastIdx != i { 175 outputBuf.WriteString(",") 176 } 177 } 178 179 if outputName != "" { 180 if len(outputList) > 0 { 181 outputBuf.WriteString(fmt.Sprintf("\n%s]", indent)) 182 } else { 183 outputBuf.WriteString("]") 184 } 185 } 186 187 return strings.TrimPrefix(outputBuf.String(), "\n") 188 } 189 190 func formatNestedMap(indent string, outputMap map[string]interface{}) string { 191 ks := make([]string, 0, len(outputMap)) 192 for k, _ := range outputMap { 193 ks = append(ks, k) 194 } 195 sort.Strings(ks) 196 197 outputBuf := new(bytes.Buffer) 198 outputBuf.WriteString(fmt.Sprintf("%s{", indent)) 199 200 lastIdx := len(outputMap) - 1 201 for i, k := range ks { 202 v := outputMap[k] 203 outputBuf.WriteString(fmt.Sprintf("\n%s%s = %v", indent+" ", k, v)) 204 205 if lastIdx != i { 206 outputBuf.WriteString(",") 207 } 208 } 209 210 outputBuf.WriteString(fmt.Sprintf("\n%s}", indent)) 211 212 return strings.TrimPrefix(outputBuf.String(), "\n") 213 } 214 func formatMapOutput(indent, outputName string, outputMap map[string]interface{}) string { 215 ks := make([]string, 0, len(outputMap)) 216 for k, _ := range outputMap { 217 ks = append(ks, k) 218 } 219 sort.Strings(ks) 220 221 keyIndent := "" 222 223 outputBuf := new(bytes.Buffer) 224 if outputName != "" { 225 outputBuf.WriteString(fmt.Sprintf("%s%s = {", indent, outputName)) 226 keyIndent = " " 227 } 228 229 for _, k := range ks { 230 v := outputMap[k] 231 outputBuf.WriteString(fmt.Sprintf("\n%s%s%s = %v", indent, keyIndent, k, v)) 232 } 233 234 if outputName != "" { 235 if len(outputMap) > 0 { 236 outputBuf.WriteString(fmt.Sprintf("\n%s}", indent)) 237 } else { 238 outputBuf.WriteString("}") 239 } 240 } 241 242 return strings.TrimPrefix(outputBuf.String(), "\n") 243 } 244 245 func (c *OutputCommand) Help() string { 246 helpText := ` 247 Usage: terraform output [options] [NAME] 248 249 Reads an output variable from a Terraform state file and prints 250 the value. With no additional arguments, output will display all 251 the outputs for the root module. If NAME is not specified, all 252 outputs are printed. 253 254 Options: 255 256 -state=path Path to the state file to read. Defaults to 257 "terraform.tfstate". 258 259 -no-color If specified, output won't contain any color. 260 261 -module=name If specified, returns the outputs for a 262 specific module 263 264 -json If specified, machine readable output will be 265 printed in JSON format 266 267 ` 268 return strings.TrimSpace(helpText) 269 } 270 271 func (c *OutputCommand) Synopsis() string { 272 return "Read an output from a state file" 273 }