command/show: continued work on `terraform show -json` output (#20171)

* command/jsonstate: do not hide SchemaVersion of '0'
* command/jsonconfig: module_calls should be a map
* command/jsonplan: include current terraform version in output
* command/jsonconfig: properly marshal expressions from a module call

Previously this was looking at the root module's variables, instead of
the child module variables, to build the module schema. This fixes that
bug.
This commit is contained in:
Kristin Laemmert 2019-02-01 13:47:18 -08:00 committed by GitHub
parent 18030a487b
commit c810e4582c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 24 additions and 19 deletions

View File

@ -34,8 +34,8 @@ type module struct {
Outputs map[string]configOutput `json:"outputs,omitempty"` Outputs map[string]configOutput `json:"outputs,omitempty"`
// Resources are sorted in a user-friendly order that is undefined at this // Resources are sorted in a user-friendly order that is undefined at this
// time, but consistent. // time, but consistent.
Resources []resource `json:"resources,omitempty"` Resources []resource `json:"resources,omitempty"`
ModuleCalls []moduleCall `json:"module_calls,omitempty"` ModuleCalls map[string]moduleCall `json:"module_calls,omitempty"`
} }
type moduleCall struct { type moduleCall struct {
@ -161,37 +161,39 @@ func marshalModule(c *configs.Config, schemas *terraform.Schemas) (module, error
return module, nil return module, nil
} }
func marshalModuleCalls(c *configs.Config, schemas *terraform.Schemas) []moduleCall { func marshalModuleCalls(c *configs.Config, schemas *terraform.Schemas) map[string]moduleCall {
var ret []moduleCall ret := make(map[string]moduleCall)
for _, v := range c.Module.ModuleCalls { for _, mc := range c.Module.ModuleCalls {
mc := moduleCall{ retMC := moduleCall{
ResolvedSource: v.SourceAddr, ResolvedSource: mc.SourceAddr,
} }
cExp := marshalExpression(v.Count) cExp := marshalExpression(mc.Count)
if !cExp.Empty() { if !cExp.Empty() {
mc.CountExpression = &cExp retMC.CountExpression = &cExp
} else { } else {
fExp := marshalExpression(v.ForEach) fExp := marshalExpression(mc.ForEach)
if !fExp.Empty() { if !fExp.Empty() {
mc.ForEachExpression = &fExp retMC.ForEachExpression = &fExp
} }
} }
// get the called module's variables so we can build up the expressions
childModule := c.Children[mc.Name]
schema := &configschema.Block{} schema := &configschema.Block{}
schema.Attributes = make(map[string]*configschema.Attribute) schema.Attributes = make(map[string]*configschema.Attribute)
for _, variable := range c.Module.Variables { for _, variable := range childModule.Module.Variables {
schema.Attributes[variable.Name] = &configschema.Attribute{ schema.Attributes[variable.Name] = &configschema.Attribute{
Required: variable.Default == cty.NilVal, Required: variable.Default == cty.NilVal,
} }
} }
mc.Expressions = marshalExpressions(v.Config, schema)
retMC.Expressions = marshalExpressions(mc.Config, schema)
for _, cc := range c.Children { for _, cc := range c.Children {
childModule, _ := marshalModule(cc, schemas) childModule, _ := marshalModule(cc, schemas)
mc.Module = childModule retMC.Module = childModule
} }
ret = append(ret, mc) ret[mc.Name] = retMC
} }
return ret return ret

View File

@ -16,6 +16,7 @@ import (
"github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/states/statefile" "github.com/hashicorp/terraform/states/statefile"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/hashicorp/terraform/version"
) )
// FormatVersion represents the version of the json format and will be // FormatVersion represents the version of the json format and will be
@ -26,8 +27,9 @@ const FormatVersion = "0.1"
// Plan is the top-level representation of the json format of a plan. It includes // Plan is the top-level representation of the json format of a plan. It includes
// the complete config and current state. // the complete config and current state.
type plan struct { type plan struct {
FormatVersion string `json:"format_version,omitempty"` FormatVersion string `json:"format_version,omitempty"`
PlannedValues stateValues `json:"planned_values,omitempty"` TerraformVersion string `json:"terraform_version,omitempty"`
PlannedValues stateValues `json:"planned_values,omitempty"`
// ResourceChanges are sorted in a user-friendly order that is undefined at // ResourceChanges are sorted in a user-friendly order that is undefined at
// this time, but consistent. // this time, but consistent.
ResourceChanges []resourceChange `json:"resource_changes,omitempty"` ResourceChanges []resourceChange `json:"resource_changes,omitempty"`
@ -83,6 +85,7 @@ func Marshal(
) ([]byte, error) { ) ([]byte, error) {
output := newPlan() output := newPlan()
output.TerraformVersion = version.String()
// output.PlannedValues // output.PlannedValues
err := output.marshalPlannedValues(p.Changes, schemas) err := output.marshalPlannedValues(p.Changes, schemas)

View File

@ -77,7 +77,7 @@ type resource struct {
// SchemaVersion indicates which version of the resource type schema the // SchemaVersion indicates which version of the resource type schema the
// "values" property conforms to. // "values" property conforms to.
SchemaVersion uint64 `json:"schema_version,omitempty"` SchemaVersion uint64 `json:"schema_version"`
// AttributeValues is the JSON representation of the attribute values of the // AttributeValues is the JSON representation of the attribute values of the
// resource, whose structure depends on the resource type schema. Any // resource, whose structure depends on the resource type schema. Any