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 {
|
||||
ResolvedSource string `json:"resolved_source,omitempty"`
|
||||
Expressions map[string]interface{} `json:"expressions,omitempty"`
|
||||
CountExpression expression `json:"count_expression,omitempty"`
|
||||
ForEachExpression expression `json:"for_each_expression,omitempty"`
|
||||
CountExpression *expression `json:"count_expression,omitempty"`
|
||||
ForEachExpression *expression `json:"for_each_expression,omitempty"`
|
||||
Module module `json:"module,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,8 @@ type resource struct {
|
|||
// CountExpression and ForEachExpression describe the expressions given for
|
||||
// the corresponding meta-arguments in the resource configuration block.
|
||||
// These are omitted if the corresponding argument isn't set.
|
||||
CountExpression expression `json:"count_expression,omitempty"`
|
||||
ForEachExpression expression `json:"for_each_expression,omitempty"`
|
||||
CountExpression *expression `json:"count_expression,omitempty"`
|
||||
ForEachExpression *expression `json:"for_each_expression,omitempty"`
|
||||
}
|
||||
|
||||
type configOutput struct {
|
||||
|
@ -169,11 +169,11 @@ func marshalModuleCalls(c *configs.Config, schemas *terraform.Schemas) []moduleC
|
|||
}
|
||||
cExp := marshalExpression(v.Count)
|
||||
if !cExp.Empty() {
|
||||
mc.CountExpression = cExp
|
||||
mc.CountExpression = &cExp
|
||||
} else {
|
||||
fExp := marshalExpression(v.ForEach)
|
||||
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)
|
||||
if !cExp.Empty() {
|
||||
r.CountExpression = cExp
|
||||
r.CountExpression = &cExp
|
||||
} else {
|
||||
fExp := marshalExpression(v.ForEach)
|
||||
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.TerraformVersion = sf.TerraformVersion.String()
|
||||
|
||||
if sf.TerraformVersion != nil {
|
||||
output.TerraformVersion = sf.TerraformVersion.String()
|
||||
}
|
||||
// output.StateValues
|
||||
err := output.marshalStateValues(sf.State, schemas)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/format"
|
||||
"github.com/hashicorp/terraform/command/jsonplan"
|
||||
"github.com/hashicorp/terraform/command/jsonstate"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/plans/planfile"
|
||||
"github.com/hashicorp/terraform/states/statefile"
|
||||
|
@ -29,7 +30,7 @@ func (c *ShowCommand) Run(args []string) int {
|
|||
|
||||
cmdFlags := c.Meta.defaultFlagSet("show")
|
||||
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()) }
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
return 1
|
||||
|
@ -110,11 +111,6 @@ func (c *ShowCommand) Run(args []string) int {
|
|||
path := args[0]
|
||||
plan, planErr = getPlanFromPath(path)
|
||||
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)
|
||||
if stateErr != nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
|
@ -162,11 +158,21 @@ func (c *ShowCommand) Run(args []string) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
c.Ui.Output(format.State(&format.StateOpts{
|
||||
State: stateFile.State,
|
||||
Color: c.Colorize(),
|
||||
Schemas: schemas,
|
||||
}))
|
||||
if jsonOutput == true {
|
||||
jsonState, err := jsonstate.Marshal(stateFile, schemas)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
// Create the default state
|
||||
statePath := testStateFile(t, testState())
|
||||
|
|
Loading…
Reference in New Issue