command/show
This commit is contained in:
parent
3d35158170
commit
dbc1c63d79
|
@ -12,6 +12,10 @@ import (
|
|||
|
||||
// FormatPlan takes a plan and returns a
|
||||
func FormatPlan(p *terraform.Plan, c *colorstring.Colorize) string {
|
||||
if p.Diff == nil || p.Diff.Empty() {
|
||||
return "This plan does nothing."
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
c = &colorstring.Colorize{
|
||||
Colors: colorstring.DefaultColors,
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/colorstring"
|
||||
)
|
||||
|
||||
// FormatState takes a state and returns a string
|
||||
func FormatState(s *terraform.State, c *colorstring.Colorize) string {
|
||||
if len(s.Resources) == 0 {
|
||||
return "The state file is empty. No resources are represented."
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
c = &colorstring.Colorize{
|
||||
Colors: colorstring.DefaultColors,
|
||||
Reset: false,
|
||||
}
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteString("[reset]")
|
||||
|
||||
// First get the names of all the resources so we can show them
|
||||
// in alphabetical order.
|
||||
names := make([]string, 0, len(s.Resources))
|
||||
for name, _ := range s.Resources {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
// Go through each resource and begin building up the output.
|
||||
for _, k := range names {
|
||||
rs := s.Resources[k]
|
||||
id := rs.ID
|
||||
if id == "" {
|
||||
id = "<not created>"
|
||||
}
|
||||
|
||||
buf.WriteString(fmt.Sprintf("%s:\n", k))
|
||||
buf.WriteString(fmt.Sprintf(" id = %s\n", id))
|
||||
|
||||
// Sort the attributes
|
||||
attrKeys := make([]string, 0, len(rs.Attributes))
|
||||
for ak, _ := range rs.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 := rs.Attributes[ak]
|
||||
buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av))
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.Outputs) > 0 {
|
||||
buf.WriteString("\nOutputs:\n\n")
|
||||
|
||||
// Sort the outputs
|
||||
ks := make([]string, 0, len(s.Outputs))
|
||||
for k, _ := range s.Outputs {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
sort.Strings(ks)
|
||||
|
||||
// Output each output k/v pair
|
||||
for _, k := range ks {
|
||||
v := s.Outputs[k]
|
||||
buf.WriteString(fmt.Sprintf("%s = %s\n", k, v))
|
||||
}
|
||||
}
|
||||
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
|
@ -32,7 +32,7 @@ func TestGraph(t *testing.T) {
|
|||
|
||||
func TestGraph_multipleArgs(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
c := &ApplyCommand{
|
||||
c := &GraphCommand{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// ShowCommand is a Command implementation that reads and outputs the
|
||||
// contents of a Terraform plan or state file.
|
||||
type ShowCommand struct {
|
||||
ContextOpts *terraform.ContextOpts
|
||||
Ui cli.Ui
|
||||
}
|
||||
|
||||
func (c *ShowCommand) Run(args []string) int {
|
||||
cmdFlags := flag.NewFlagSet("show", flag.ContinueOnError)
|
||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
args = cmdFlags.Args()
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error(
|
||||
"The show command expects exactly one argument with the path\n" +
|
||||
"to a Terraform state or plan file.\n")
|
||||
cmdFlags.Usage()
|
||||
return 1
|
||||
}
|
||||
path := args[0]
|
||||
|
||||
var plan *terraform.Plan
|
||||
var state *terraform.State
|
||||
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error loading file: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
var planErr, stateErr error
|
||||
plan, err = terraform.ReadPlan(f)
|
||||
if err != nil {
|
||||
if _, err := f.Seek(0, 0); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error reading file: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
plan = nil
|
||||
planErr = err
|
||||
}
|
||||
if plan == nil {
|
||||
state, err = terraform.ReadState(f)
|
||||
if err != nil {
|
||||
stateErr = err
|
||||
}
|
||||
}
|
||||
if plan == nil && state == nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Terraform couldn't read the given file as a state or plan file.\n"+
|
||||
"The errors while attempting to read the file as each format are\n"+
|
||||
"shown below.\n\n"+
|
||||
"State read error: %s\n\nPlan read error: %s",
|
||||
stateErr,
|
||||
planErr))
|
||||
return 1
|
||||
}
|
||||
|
||||
if plan != nil {
|
||||
c.Ui.Output(FormatPlan(plan, nil))
|
||||
return 0
|
||||
}
|
||||
|
||||
c.Ui.Output(FormatState(state, nil))
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *ShowCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: terraform show [options] path
|
||||
|
||||
Reads and outputs a Terraform state or plan file in a human-readable
|
||||
form.
|
||||
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *ShowCommand) Synopsis() string {
|
||||
return "Inspect Terraform state or plan"
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/config"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func TestShow(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
c := &ShowCommand{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"bad",
|
||||
"bad",
|
||||
}
|
||||
if code := c.Run(args); code != 1 {
|
||||
t.Fatalf("bad: \n%s", ui.OutputWriter.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestShow_noArgs(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
c := &ShowCommand{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
}
|
||||
|
||||
args := []string{}
|
||||
if code := c.Run(args); code != 1 {
|
||||
t.Fatalf("bad: \n%s", ui.OutputWriter.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestShow_plan(t *testing.T) {
|
||||
planPath := testPlanFile(t, &terraform.Plan{
|
||||
Config: new(config.Config),
|
||||
})
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &ShowCommand{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
}
|
||||
|
||||
args := []string{
|
||||
planPath,
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestShow_state(t *testing.T) {
|
||||
originalState := &terraform.State{
|
||||
Resources: map[string]*terraform.ResourceState{
|
||||
"test_instance.foo": &terraform.ResourceState{
|
||||
ID: "bar",
|
||||
Type: "test_instance",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
statePath := testStateFile(t, originalState)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &ShowCommand{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
}
|
||||
|
||||
args := []string{
|
||||
statePath,
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
||||
}
|
||||
}
|
|
@ -56,6 +56,13 @@ func init() {
|
|||
}, nil
|
||||
},
|
||||
|
||||
"show": func() (cli.Command, error) {
|
||||
return &command.ShowCommand{
|
||||
ContextOpts: &ContextOpts,
|
||||
Ui: Ui,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"version": func() (cli.Command, error) {
|
||||
return &command.VersionCommand{
|
||||
Revision: GitCommit,
|
||||
|
|
Loading…
Reference in New Issue