command/plan: nice plan formatting
This commit is contained in:
parent
e476bca29c
commit
832211c17a
|
@ -0,0 +1,97 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/colorstring"
|
||||
)
|
||||
|
||||
// FormatPlan takes a plan and returns a
|
||||
func FormatPlan(p *terraform.Plan, c *colorstring.Colorize) string {
|
||||
if c == nil {
|
||||
c = &colorstring.Colorize{
|
||||
Colors: colorstring.DefaultColors,
|
||||
Reset: false,
|
||||
}
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// We want to output the resources in sorted order to make things
|
||||
// easier to scan through, so get all the resource names and sort them.
|
||||
names := make([]string, 0, len(p.Diff.Resources))
|
||||
for name, _ := range p.Diff.Resources {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
// Go through each sorted name and start building the output
|
||||
for _, name := range names {
|
||||
rdiff := p.Diff.Resources[name]
|
||||
|
||||
// Determine the color for the text (green for adding, yellow
|
||||
// for change, red for delete), and symbol, and output the
|
||||
// resource header.
|
||||
color := "yellow"
|
||||
symbol := "~"
|
||||
if rdiff.RequiresNew() {
|
||||
color = "green"
|
||||
symbol = "+"
|
||||
} else if rdiff.Destroy {
|
||||
color = "red"
|
||||
symbol = "-"
|
||||
}
|
||||
buf.WriteString(c.Color(fmt.Sprintf(
|
||||
"[%s]%s %s\n",
|
||||
color, symbol, name)))
|
||||
|
||||
// Get all the attributes that are changing, and sort them. Also
|
||||
// determine the longest key so that we can align them all.
|
||||
keyLen := 0
|
||||
keys := make([]string, 0, len(rdiff.Attributes))
|
||||
for key, _ := range rdiff.Attributes {
|
||||
// Skip the ID since we do that specially
|
||||
if key == "id" {
|
||||
continue
|
||||
}
|
||||
|
||||
keys = append(keys, key)
|
||||
if len(key) > keyLen {
|
||||
keyLen = len(key)
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// Go through and output each attribute
|
||||
for _, attrK := range keys {
|
||||
attrDiff := rdiff.Attributes[attrK]
|
||||
|
||||
v := attrDiff.New
|
||||
if attrDiff.NewComputed {
|
||||
v = "<computed>"
|
||||
}
|
||||
|
||||
newResource := ""
|
||||
if attrDiff.RequiresNew && rdiff.Destroy {
|
||||
newResource = " (forces new resource)"
|
||||
}
|
||||
|
||||
buf.WriteString(fmt.Sprintf(
|
||||
" %s:%s %#v => %#v%s\n",
|
||||
attrK,
|
||||
strings.Repeat(" ", keyLen-len(attrK)),
|
||||
attrDiff.Old,
|
||||
v,
|
||||
newResource))
|
||||
}
|
||||
|
||||
// Write the reset color so we don't overload the user's terminal
|
||||
buf.WriteString(c.Color("[reset]\n"))
|
||||
}
|
||||
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
|
@ -29,9 +29,6 @@ func (h *UiHook) PreApply(
|
|||
|
||||
func (h *UiHook) PreDiff(
|
||||
id string, s *terraform.ResourceState) (terraform.HookAction, error) {
|
||||
h.once.Do(h.init)
|
||||
|
||||
h.ui.Output(fmt.Sprintf("%s: Calculating diff", id))
|
||||
return terraform.HookActionContinue, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -109,8 +109,6 @@ func (c *PlanCommand) Run(args []string) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
c.Ui.Output(strings.TrimSpace(plan.String()))
|
||||
|
||||
if outPath != "" {
|
||||
log.Printf("[INFO] Writing plan output to: %s", outPath)
|
||||
f, err := os.Create(outPath)
|
||||
|
@ -124,6 +122,16 @@ func (c *PlanCommand) Run(args []string) int {
|
|||
}
|
||||
}
|
||||
|
||||
if outPath == "" {
|
||||
c.Ui.Output(strings.TrimSpace(planHeaderNoOutput)+"\n")
|
||||
} else {
|
||||
c.Ui.Output(fmt.Sprintf(
|
||||
strings.TrimSpace(planHeaderYesOutput)+"\n",
|
||||
outPath))
|
||||
}
|
||||
|
||||
c.Ui.Output(FormatPlan(plan, nil))
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
@ -159,3 +167,28 @@ Options:
|
|||
func (c *PlanCommand) Synopsis() string {
|
||||
return "Show changes between Terraform config and infrastructure"
|
||||
}
|
||||
|
||||
const planHeaderNoOutput = `
|
||||
The Terraform execution plan has been generated and is shown below.
|
||||
Resources are shown in alphabetical order for quick scanning. Green resources
|
||||
will be created (or destroyed and then created if an existing resource
|
||||
exists), yellow resources are being changed in-place, and red resources
|
||||
will be destroyed.
|
||||
|
||||
Note: You didn't specify an "-out" parameter to save this plan, so when
|
||||
"apply" is called, Terraform can't guarantee this is what will execute.
|
||||
`
|
||||
|
||||
const planHeaderYesOutput = `
|
||||
The Terraform execution plan has been generated and is shown below.
|
||||
Resources are shown in alphabetical order for quick scanning. Green resources
|
||||
will be created (or destroyed and then created if an existing resource
|
||||
exists), yellow resources are being changed in-place, and red resources
|
||||
will be destroyed.
|
||||
|
||||
Your plan was also saved to the path below. Call the "apply" subcommand
|
||||
with this plan file and Terraform will exactly execute this execution
|
||||
plan.
|
||||
|
||||
Path: %s
|
||||
`
|
||||
|
|
Loading…
Reference in New Issue