command/show: differentiate between state schemas and plan schemas. (#20516)
When a planfile is supplied to the `terraform show -json` command, the context that loads only included schemas for resources in the plan. We found an edge case where removing a data source from the configuration (though only if there are no managed resources from the same provider) would cause jsonstate.Marshal to fail because the provider schema wasn't in the plan context. jsonplan.Marshal now takes two schemas, one for plan and one for state. If the state schema is nil it will simply use the plan schemas.
This commit is contained in:
parent
c4151b7c7c
commit
8fb4e5ce6e
|
@ -91,7 +91,11 @@ func Marshal(
|
||||||
p *plans.Plan,
|
p *plans.Plan,
|
||||||
sf *statefile.File,
|
sf *statefile.File,
|
||||||
schemas *terraform.Schemas,
|
schemas *terraform.Schemas,
|
||||||
|
stateSchemas *terraform.Schemas,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
|
if stateSchemas == nil {
|
||||||
|
stateSchemas = schemas
|
||||||
|
}
|
||||||
|
|
||||||
output := newPlan()
|
output := newPlan()
|
||||||
output.TerraformVersion = version.String()
|
output.TerraformVersion = version.String()
|
||||||
|
@ -120,7 +124,7 @@ func Marshal(
|
||||||
}
|
}
|
||||||
|
|
||||||
// output.PriorState
|
// output.PriorState
|
||||||
output.PriorState, err = jsonstate.Marshal(sf, schemas)
|
output.PriorState, err = jsonstate.Marshal(sf, stateSchemas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error marshaling prior state: %s", err)
|
return nil, fmt.Errorf("error marshaling prior state: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,30 @@ func (c *ShowCommand) Run(args []string) int {
|
||||||
if plan != nil {
|
if plan != nil {
|
||||||
if jsonOutput == true {
|
if jsonOutput == true {
|
||||||
config := ctx.Config()
|
config := ctx.Config()
|
||||||
jsonPlan, err := jsonplan.Marshal(config, plan, stateFile, schemas)
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Failed to marshal plan to json: %s", err))
|
c.Ui.Error(fmt.Sprintf("Failed to marshal plan to json: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -236,10 +259,6 @@ func getStateFromEnv(b backend.Backend, env string) (*statefile.File, error) {
|
||||||
return nil, fmt.Errorf("Failed to load state manager: %s", err)
|
return nil, fmt.Errorf("Failed to load state manager: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateStore.RefreshState(); err != nil {
|
|
||||||
return nil, fmt.Errorf("Failed to load state: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sf := statemgr.Export(stateStore)
|
sf := statemgr.Export(stateStore)
|
||||||
|
|
||||||
return sf, nil
|
return sf, nil
|
||||||
|
|
Loading…
Reference in New Issue