command: state output is well formatted for modules

This commit is contained in:
Mitchell Hashimoto 2014-09-25 19:25:10 -07:00
parent 30dcacf29f
commit e5e51d7b17
3 changed files with 86 additions and 27 deletions

View File

@ -10,26 +10,70 @@ import (
"github.com/mitchellh/colorstring" "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 // FormatState takes a state and returns a string
func FormatState(s *terraform.State, c *colorstring.Colorize) string { func FormatState(opts *FormatStateOpts) string {
if c == nil { if opts.Color == nil {
panic("colorize not given") panic("colorize not given")
} }
s := opts.State
if len(s.Modules) == 0 { if len(s.Modules) == 0 {
return "The state file is empty. No resources are represented." return "The state file is empty. No resources are represented."
} }
var buf bytes.Buffer var buf bytes.Buffer
buf.WriteString("[reset]")
// Format all the modules
for _, m := range s.Modules { for _, m := range s.Modules {
formatStateModule(&buf, m, c) if len(m.Path)-1 <= opts.ModuleDepth || opts.ModuleDepth == -1 {
formatStateModuleExpand(&buf, m, opts)
} else {
formatStateModuleSingle(&buf, m, opts)
}
} }
return c.Color(strings.TrimSpace(buf.String())) // 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]
buf.WriteString(fmt.Sprintf("%s = %s\n", k, v))
}
}
return opts.Color.Color(strings.TrimSpace(buf.String()))
} }
func formatStateModule(buf *bytes.Buffer, m *terraform.ModuleState, c *colorstring.Colorize) { func formatStateModuleExpand(
buf.WriteString("[reset]") 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 // First get the names of all the resources so we can show them
// in alphabetical order. // in alphabetical order.
@ -41,6 +85,11 @@ func formatStateModule(buf *bytes.Buffer, m *terraform.ModuleState, c *colorstri
// Go through each resource and begin building up the output. // Go through each resource and begin building up the output.
for _, k := range names { for _, k := range names {
name := k
if moduleName != "" {
name = moduleName + "." + name
}
rs := m.Resources[k] rs := m.Resources[k]
is := rs.Primary is := rs.Primary
id := is.ID id := is.ID
@ -53,7 +102,7 @@ func formatStateModule(buf *bytes.Buffer, m *terraform.ModuleState, c *colorstri
taintStr = " (tainted)" taintStr = " (tainted)"
} }
buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr)) buf.WriteString(fmt.Sprintf("%s:%s\n", name, taintStr))
buf.WriteString(fmt.Sprintf(" id = %s\n", id)) buf.WriteString(fmt.Sprintf(" id = %s\n", id))
// Sort the attributes // Sort the attributes
@ -75,20 +124,14 @@ func formatStateModule(buf *bytes.Buffer, m *terraform.ModuleState, c *colorstri
} }
} }
if len(m.Outputs) > 0 { buf.WriteString("[reset]\n")
buf.WriteString("\nOutputs:\n\n") }
// Sort the outputs func formatStateModuleSingle(
ks := make([]string, 0, len(m.Outputs)) buf *bytes.Buffer, m *terraform.ModuleState, opts *FormatStateOpts) {
for k, _ := range m.Outputs { // Header with the module name
ks = append(ks, k) buf.WriteString(fmt.Sprintf("module.%s\n", strings.Join(m.Path[1:], ".")))
}
sort.Strings(ks) // Now just write how many resources are in here.
buf.WriteString(fmt.Sprintf(" %d resource(s)\n", len(m.Resources)))
// Output each output k/v pair
for _, k := range ks {
v := m.Outputs[k]
buf.WriteString(fmt.Sprintf("%s = %s\n", k, v))
}
}
} }

View File

@ -16,9 +16,12 @@ type ShowCommand struct {
} }
func (c *ShowCommand) Run(args []string) int { func (c *ShowCommand) Run(args []string) int {
var moduleDepth int
args = c.Meta.process(args, false) args = c.Meta.process(args, false)
cmdFlags := flag.NewFlagSet("show", flag.ContinueOnError) cmdFlags := flag.NewFlagSet("show", flag.ContinueOnError)
cmdFlags.IntVar(&moduleDepth, "module-depth", 0, "module-depth")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return 1 return 1
@ -73,13 +76,18 @@ func (c *ShowCommand) Run(args []string) int {
if plan != nil { if plan != nil {
c.Ui.Output(FormatPlan(&FormatPlanOpts{ c.Ui.Output(FormatPlan(&FormatPlanOpts{
Plan: plan, Plan: plan,
Color: c.Colorize(), Color: c.Colorize(),
ModuleDepth: moduleDepth,
})) }))
return 0 return 0
} }
c.Ui.Output(FormatState(state, c.Colorize())) c.Ui.Output(FormatState(&FormatStateOpts{
State: state,
Color: c.Colorize(),
ModuleDepth: moduleDepth,
}))
return 0 return 0
} }
@ -92,7 +100,10 @@ Usage: terraform show [options] path
Options: Options:
-no-color If specified, output won't contain any color. -module-depth=n Specifies the depth of modules to show in the output.
By default this is zero. -1 will expand all.
-no-color If specified, output won't contain any color.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)

View File

@ -182,6 +182,11 @@ type ModuleState struct {
Resources map[string]*ResourceState `json:"resources"` Resources map[string]*ResourceState `json:"resources"`
} }
// IsRoot says whether or not this module diff is for the root module.
func (m *ModuleState) IsRoot() bool {
return reflect.DeepEqual(m.Path, rootModulePath)
}
// Orphans returns a list of keys of resources that are in the State // Orphans returns a list of keys of resources that are in the State
// but aren't present in the configuration itself. Hence, these keys // but aren't present in the configuration itself. Hence, these keys
// represent the state of resources that are orphans. // represent the state of resources that are orphans.