Skip to content

Commit

Permalink
command/show (json): marshal the state snapshot included with the pla…
Browse files Browse the repository at this point in the history
…n file (#21597)

* command/show: marshal the state snapshot from the planfile

The planfile contains a state snapshot with certain resources updated
(outputs and datasources). Previously `terraform show -json PLANFILE`
was using the current state instead of the state inside the plan as
intended.

This caused an issue when the state included a terraform_remote_state
datasource. The datasource's state gets refreshed - and therefore
upgraded to the current state version - during plan, but that won't
persist to state until apply.

* update comment to reflect new return
  • Loading branch information
mildwonkey authored Jun 5, 2019
1 parent 2f893f2 commit b9f114a
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 43 deletions.
7 changes: 1 addition & 6 deletions command/jsonplan/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,7 @@ func Marshal(
p *plans.Plan,
sf *statefile.File,
schemas *terraform.Schemas,
stateSchemas *terraform.Schemas,
) ([]byte, error) {
if stateSchemas == nil {
stateSchemas = schemas
}

output := newPlan()
output.TerraformVersion = version.String()

Expand Down Expand Up @@ -125,7 +120,7 @@ func Marshal(

// output.PriorState
if sf != nil && !sf.State.Empty() {
output.PriorState, err = jsonstate.Marshal(sf, stateSchemas)
output.PriorState, err = jsonstate.Marshal(sf, schemas)
if err != nil {
return nil, fmt.Errorf("error marshaling prior state: %s", err)
}
Expand Down
46 changes: 12 additions & 34 deletions command/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (c *ShowCommand) Run(args []string) int {
// if that fails, try to read the cli argument as a path to a statefile
if len(args) > 0 {
path := args[0]
plan, planErr = getPlanFromPath(path)
plan, stateFile, planErr = getPlanFromPath(path)
if planErr != nil {
stateFile, stateErr = getStateFromPath(path)
if stateErr != nil {
Expand All @@ -129,9 +129,7 @@ func (c *ShowCommand) Run(args []string) int {
return 1
}
}
}

if stateFile == nil {
} else {
env := c.Workspace()
stateFile, stateErr = getStateFromEnv(b, env)
if err != nil {
Expand All @@ -143,29 +141,7 @@ func (c *ShowCommand) Run(args []string) int {
if plan != nil {
if jsonOutput == true {
config := ctx.Config()

var err error
var jsonPlan []byte

// If there is no prior state, we have all the schemas needed.
if stateFile == nil {
jsonPlan, err = jsonplan.Marshal(config, plan, stateFile, schemas, nil)
} else {
// If there is state, we need the state-specific schemas, which
// may differ from the schemas loaded from the plan.
// This occurs if there is a data_source in the state that was
// removed from the configuration, because terraform core does
// not need to load the schema to remove a data source.
opReq.PlanFile = nil
ctx, _, ctxDiags := local.Context(opReq)
diags = diags.Append(ctxDiags)
if ctxDiags.HasErrors() {
c.showDiagnostics(diags)
return 1
}
stateSchemas := ctx.Schemas()
jsonPlan, err = jsonplan.Marshal(config, plan, stateFile, schemas, stateSchemas)
}
jsonPlan, err := jsonplan.Marshal(config, plan, stateFile, schemas)

if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to marshal plan to json: %s", err))
Expand Down Expand Up @@ -224,19 +200,21 @@ func (c *ShowCommand) Synopsis() string {
return "Inspect Terraform state or plan"
}

// getPlanFromPath returns a plan if the user-supplied path points to a planfile.
// If both plan and error are nil, the path is likely a directory.
// An error could suggest that the given path points to a statefile.
func getPlanFromPath(path string) (*plans.Plan, error) {
// getPlanFromPath returns a plan and statefile if the user-supplied path points
// to a planfile. If both plan and error are nil, the path is likely a
// directory. An error could suggest that the given path points to a statefile.
func getPlanFromPath(path string) (*plans.Plan, *statefile.File, error) {
pr, err := planfile.Open(path)
if err != nil {
return nil, err
return nil, nil, err
}
plan, err := pr.ReadPlan()
if err != nil {
return nil, err
return nil, nil, err
}
return plan, nil

stateFile, err := pr.ReadStateFile()
return plan, stateFile, nil
}

// getStateFromPath returns a statefile if the user-supplied path points to a statefile.
Expand Down
7 changes: 6 additions & 1 deletion command/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,11 @@ type plan struct {
PlannedValues map[string]interface{} `json:"planned_values,omitempty"`
ResourceChanges []interface{} `json:"resource_changes,omitempty"`
OutputChanges map[string]interface{} `json:"output_changes,omitempty"`
PriorState map[string]interface{} `json:"prior_state,omitempty"`
PriorState priorState `json:"prior_state,omitempty"`
Config map[string]interface{} `json:"configuration,omitempty"`
}

type priorState struct {
FormatVersion string `json:"format_version,omitempty"`
Values map[string]interface{} `json:"values,omitempty"`
}
12 changes: 12 additions & 0 deletions command/test-fixtures/show-json/basic-create/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@
]
}
},
"prior_state": {
"format_version": "0.1",
"values": {
"outputs": {
"test": {
"sensitive": false,
"value": "bar"
}
},
"root_module": {}
}
},
"resource_changes": [
{
"address": "test_instance.test[0]",
Expand Down
7 changes: 6 additions & 1 deletion command/test-fixtures/show-json/basic-delete/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,13 @@
},
"prior_state": {
"format_version": "0.1",
"terraform_version": "0.12.0",
"values": {
"outputs": {
"test": {
"sensitive": false,
"value": "bar"
}
},
"root_module": {
"resources": [
{
Expand Down
7 changes: 6 additions & 1 deletion command/test-fixtures/show-json/basic-update/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,13 @@
},
"prior_state": {
"format_version": "0.1",
"terraform_version": "0.12.0",
"values": {
"outputs": {
"test": {
"sensitive": false,
"value": "bar"
}
},
"root_module": {
"resources": [
{
Expand Down
12 changes: 12 additions & 0 deletions command/test-fixtures/show-json/modules/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@
]
}
},
"prior_state": {
"format_version": "0.1",
"values": {
"outputs": {
"test": {
"sensitive": false,
"value": "baz"
}
},
"root_module": {}
}
},
"resource_changes": [
{
"address": "module.module_test_bar.test_instance.test",
Expand Down

0 comments on commit b9f114a

Please sign in to comment.