command/show: improvements to json output (#20139)
* command/show: add support for -json output for state * command/jsonconfig: do not marshal empty count/for each expressions * command/jsonstate: continue gracefully if the terraform version is somehow missing from state
This commit is contained in:
parent
50e2b1856e
commit
a2ac491cde
|
@ -41,8 +41,8 @@ type module struct {
|
||||||
type moduleCall struct {
|
type moduleCall struct {
|
||||||
ResolvedSource string `json:"resolved_source,omitempty"`
|
ResolvedSource string `json:"resolved_source,omitempty"`
|
||||||
Expressions map[string]interface{} `json:"expressions,omitempty"`
|
Expressions map[string]interface{} `json:"expressions,omitempty"`
|
||||||
CountExpression expression `json:"count_expression,omitempty"`
|
CountExpression *expression `json:"count_expression,omitempty"`
|
||||||
ForEachExpression expression `json:"for_each_expression,omitempty"`
|
ForEachExpression *expression `json:"for_each_expression,omitempty"`
|
||||||
Module module `json:"module,omitempty"`
|
Module module `json:"module,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,8 +76,8 @@ type resource struct {
|
||||||
// CountExpression and ForEachExpression describe the expressions given for
|
// CountExpression and ForEachExpression describe the expressions given for
|
||||||
// the corresponding meta-arguments in the resource configuration block.
|
// the corresponding meta-arguments in the resource configuration block.
|
||||||
// These are omitted if the corresponding argument isn't set.
|
// These are omitted if the corresponding argument isn't set.
|
||||||
CountExpression expression `json:"count_expression,omitempty"`
|
CountExpression *expression `json:"count_expression,omitempty"`
|
||||||
ForEachExpression expression `json:"for_each_expression,omitempty"`
|
ForEachExpression *expression `json:"for_each_expression,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type configOutput struct {
|
type configOutput struct {
|
||||||
|
@ -169,11 +169,11 @@ func marshalModuleCalls(c *configs.Config, schemas *terraform.Schemas) []moduleC
|
||||||
}
|
}
|
||||||
cExp := marshalExpression(v.Count)
|
cExp := marshalExpression(v.Count)
|
||||||
if !cExp.Empty() {
|
if !cExp.Empty() {
|
||||||
mc.CountExpression = cExp
|
mc.CountExpression = &cExp
|
||||||
} else {
|
} else {
|
||||||
fExp := marshalExpression(v.ForEach)
|
fExp := marshalExpression(v.ForEach)
|
||||||
if !fExp.Empty() {
|
if !fExp.Empty() {
|
||||||
mc.ForEachExpression = fExp
|
mc.ForEachExpression = &fExp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,11 +219,11 @@ func marshalResources(resources map[string]*configs.Resource, schemas *terraform
|
||||||
|
|
||||||
cExp := marshalExpression(v.Count)
|
cExp := marshalExpression(v.Count)
|
||||||
if !cExp.Empty() {
|
if !cExp.Empty() {
|
||||||
r.CountExpression = cExp
|
r.CountExpression = &cExp
|
||||||
} else {
|
} else {
|
||||||
fExp := marshalExpression(v.ForEach)
|
fExp := marshalExpression(v.ForEach)
|
||||||
if !fExp.Empty() {
|
if !fExp.Empty() {
|
||||||
r.ForEachExpression = fExp
|
r.ForEachExpression = &fExp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,8 +119,9 @@ func Marshal(sf *statefile.File, schemas *terraform.Schemas) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
output := newState()
|
output := newState()
|
||||||
output.TerraformVersion = sf.TerraformVersion.String()
|
if sf.TerraformVersion != nil {
|
||||||
|
output.TerraformVersion = sf.TerraformVersion.String()
|
||||||
|
}
|
||||||
// output.StateValues
|
// output.StateValues
|
||||||
err := output.marshalStateValues(sf.State, schemas)
|
err := output.marshalStateValues(sf.State, schemas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/backend"
|
"github.com/hashicorp/terraform/backend"
|
||||||
"github.com/hashicorp/terraform/command/format"
|
"github.com/hashicorp/terraform/command/format"
|
||||||
"github.com/hashicorp/terraform/command/jsonplan"
|
"github.com/hashicorp/terraform/command/jsonplan"
|
||||||
|
"github.com/hashicorp/terraform/command/jsonstate"
|
||||||
"github.com/hashicorp/terraform/plans"
|
"github.com/hashicorp/terraform/plans"
|
||||||
"github.com/hashicorp/terraform/plans/planfile"
|
"github.com/hashicorp/terraform/plans/planfile"
|
||||||
"github.com/hashicorp/terraform/states/statefile"
|
"github.com/hashicorp/terraform/states/statefile"
|
||||||
|
@ -29,7 +30,7 @@ func (c *ShowCommand) Run(args []string) int {
|
||||||
|
|
||||||
cmdFlags := c.Meta.defaultFlagSet("show")
|
cmdFlags := c.Meta.defaultFlagSet("show")
|
||||||
var jsonOutput bool
|
var jsonOutput bool
|
||||||
cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output (only available when showing a planfile)")
|
cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output")
|
||||||
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
|
||||||
|
@ -110,11 +111,6 @@ func (c *ShowCommand) Run(args []string) int {
|
||||||
path := args[0]
|
path := args[0]
|
||||||
plan, planErr = getPlanFromPath(path)
|
plan, planErr = getPlanFromPath(path)
|
||||||
if planErr != nil {
|
if planErr != nil {
|
||||||
// json output is only supported for plans
|
|
||||||
if jsonOutput == true {
|
|
||||||
c.Ui.Error("Error: JSON output not available for state")
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
stateFile, stateErr = getStateFromPath(path)
|
stateFile, stateErr = getStateFromPath(path)
|
||||||
if stateErr != nil {
|
if stateErr != nil {
|
||||||
c.Ui.Error(fmt.Sprintf(
|
c.Ui.Error(fmt.Sprintf(
|
||||||
|
@ -162,11 +158,21 @@ func (c *ShowCommand) Run(args []string) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Ui.Output(format.State(&format.StateOpts{
|
if jsonOutput == true {
|
||||||
State: stateFile.State,
|
jsonState, err := jsonstate.Marshal(stateFile, schemas)
|
||||||
Color: c.Colorize(),
|
if err != nil {
|
||||||
Schemas: schemas,
|
c.Ui.Error(fmt.Sprintf("Failed to marshal state to json: %s", err))
|
||||||
}))
|
return 1
|
||||||
|
}
|
||||||
|
c.Ui.Output(string(jsonState))
|
||||||
|
} else {
|
||||||
|
c.Ui.Output(format.State(&format.StateOpts{
|
||||||
|
State: stateFile.State,
|
||||||
|
Color: c.Colorize(),
|
||||||
|
Schemas: schemas,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,27 +36,6 @@ func TestShow(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShow_JSONStateNotImplemented(t *testing.T) {
|
|
||||||
// Create the default state
|
|
||||||
statePath := testStateFile(t, testState())
|
|
||||||
defer testChdir(t, filepath.Dir(statePath))()
|
|
||||||
ui := new(cli.MockUi)
|
|
||||||
c := &ShowCommand{
|
|
||||||
Meta: Meta{
|
|
||||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
||||||
Ui: ui,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{
|
|
||||||
"-json",
|
|
||||||
statePath,
|
|
||||||
}
|
|
||||||
if code := c.Run(args); code != 1 {
|
|
||||||
t.Fatalf("bad: \n%s", ui.OutputWriter.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShow_noArgs(t *testing.T) {
|
func TestShow_noArgs(t *testing.T) {
|
||||||
// Create the default state
|
// Create the default state
|
||||||
statePath := testStateFile(t, testState())
|
statePath := testStateFile(t, testState())
|
||||||
|
|
Loading…
Reference in New Issue