From b917154a97fa780f8dc276cfd99190705dc38ff3 Mon Sep 17 00:00:00 2001 From: Liam Cervante Date: Mon, 9 Jan 2023 10:48:23 +0100 Subject: [PATCH] Make required JSON structured output structures public for processing (#32367) * prep for processing the structured run output * undo unwanted change to a json key --- internal/command/jsonplan/plan.go | 25 ++++++++------ internal/command/jsonplan/resource.go | 14 ++++---- internal/command/jsonprovider/attribute.go | 16 ++++----- .../command/jsonprovider/attribute_test.go | 6 ++-- internal/command/jsonprovider/block.go | 26 +++++++------- internal/command/jsonprovider/block_test.go | 14 ++++---- internal/command/jsonprovider/provider.go | 10 +++--- .../command/jsonprovider/provider_test.go | 34 +++++++++---------- internal/command/jsonprovider/schema.go | 16 ++++----- internal/command/jsonprovider/schema_test.go | 8 ++--- 10 files changed, 86 insertions(+), 83 deletions(-) diff --git a/internal/command/jsonplan/plan.go b/internal/command/jsonplan/plan.go index 3edd3e857b..ed3fc22507 100644 --- a/internal/command/jsonplan/plan.go +++ b/internal/command/jsonplan/plan.go @@ -35,9 +35,9 @@ type plan struct { PlannedValues stateValues `json:"planned_values,omitempty"` // ResourceDrift and ResourceChanges are sorted in a user-friendly order // that is undefined at this time, but consistent. - ResourceDrift []resourceChange `json:"resource_drift,omitempty"` - ResourceChanges []resourceChange `json:"resource_changes,omitempty"` - OutputChanges map[string]change `json:"output_changes,omitempty"` + ResourceDrift []ResourceChange `json:"resource_drift,omitempty"` + ResourceChanges []ResourceChange `json:"resource_changes,omitempty"` + OutputChanges map[string]Change `json:"output_changes,omitempty"` PriorState json.RawMessage `json:"prior_state,omitempty"` Config json.RawMessage `json:"configuration,omitempty"` RelevantAttributes []resourceAttr `json:"relevant_attributes,omitempty"` @@ -59,7 +59,7 @@ type resourceAttr struct { } // Change is the representation of a proposed change for an object. -type change struct { +type Change struct { // Actions are the actions that will be taken on the object selected by the // properties below. Valid actions values are: // ["no-op"] @@ -265,11 +265,11 @@ func (p *plan) marshalPlanVariables(vars map[string]plans.DynamicValue, decls ma return nil } -func (p *plan) marshalResourceChanges(resources []*plans.ResourceInstanceChangeSrc, schemas *terraform.Schemas) ([]resourceChange, error) { - var ret []resourceChange +func (p *plan) marshalResourceChanges(resources []*plans.ResourceInstanceChangeSrc, schemas *terraform.Schemas) ([]ResourceChange, error) { + var ret []ResourceChange for _, rc := range resources { - var r resourceChange + var r ResourceChange addr := rc.Addr r.Address = addr.String() if !addr.Equal(rc.PrevRunAddr) { @@ -360,7 +360,7 @@ func (p *plan) marshalResourceChanges(resources []*plans.ResourceInstanceChangeS return nil, err } - r.Change = change{ + r.Change = Change{ Actions: actionString(rc.Action.String()), Before: json.RawMessage(before), After: json.RawMessage(after), @@ -376,7 +376,10 @@ func (p *plan) marshalResourceChanges(resources []*plans.ResourceInstanceChangeS key := addr.Resource.Key if key != nil { - r.Index = key + value := key.Value() + if r.Index, err = ctyjson.Marshal(value, value.Type()); err != nil { + return nil, err + } } switch addr.Resource.Resource.Mode { @@ -440,7 +443,7 @@ func (p *plan) marshalOutputChanges(changes *plans.Changes) error { return nil } - p.OutputChanges = make(map[string]change, len(changes.Outputs)) + p.OutputChanges = make(map[string]Change, len(changes.Outputs)) for _, oc := range changes.Outputs { changeV, err := oc.Decode() if err != nil { @@ -496,7 +499,7 @@ func (p *plan) marshalOutputChanges(changes *plans.Changes) error { a, _ := ctyjson.Marshal(afterUnknown, afterUnknown.Type()) - c := change{ + c := Change{ Actions: actionString(oc.Action.String()), Before: json.RawMessage(before), After: json.RawMessage(after), diff --git a/internal/command/jsonplan/resource.go b/internal/command/jsonplan/resource.go index 1e737a6266..86ca1233ab 100644 --- a/internal/command/jsonplan/resource.go +++ b/internal/command/jsonplan/resource.go @@ -41,10 +41,10 @@ type resource struct { SensitiveValues json.RawMessage `json:"sensitive_values,omitempty"` } -// resourceChange is a description of an individual change action that Terraform +// ResourceChange is a description of an individual change action that Terraform // plans to use to move from the prior state to a new state matching the // configuration. -type resourceChange struct { +type ResourceChange struct { // Address is the absolute resource address Address string `json:"address,omitempty"` @@ -67,10 +67,10 @@ type resourceChange struct { // "managed" or "data" Mode string `json:"mode,omitempty"` - Type string `json:"type,omitempty"` - Name string `json:"name,omitempty"` - Index addrs.InstanceKey `json:"index,omitempty"` - ProviderName string `json:"provider_name,omitempty"` + Type string `json:"type,omitempty"` + Name string `json:"name,omitempty"` + Index json.RawMessage `json:"index,omitempty"` + ProviderName string `json:"provider_name,omitempty"` // "deposed", if set, indicates that this action applies to a "deposed" // object of the given instance rather than to its "current" object. Omitted @@ -78,7 +78,7 @@ type resourceChange struct { Deposed string `json:"deposed,omitempty"` // Change describes the change that will be made to this object - Change change `json:"change,omitempty"` + Change Change `json:"change,omitempty"` // ActionReason is a keyword representing some optional extra context // for why the actions in Change.Actions were chosen. diff --git a/internal/command/jsonprovider/attribute.go b/internal/command/jsonprovider/attribute.go index 9425cd9e58..61deb9c607 100644 --- a/internal/command/jsonprovider/attribute.go +++ b/internal/command/jsonprovider/attribute.go @@ -7,9 +7,9 @@ import ( "github.com/zclconf/go-cty/cty" ) -type attribute struct { +type Attribute struct { AttributeType json.RawMessage `json:"type,omitempty"` - AttributeNestedType *nestedType `json:"nested_type,omitempty"` + AttributeNestedType *NestedType `json:"nested_type,omitempty"` Description string `json:"description,omitempty"` DescriptionKind string `json:"description_kind,omitempty"` Deprecated bool `json:"deprecated,omitempty"` @@ -19,8 +19,8 @@ type attribute struct { Sensitive bool `json:"sensitive,omitempty"` } -type nestedType struct { - Attributes map[string]*attribute `json:"attributes,omitempty"` +type NestedType struct { + Attributes map[string]*Attribute `json:"attributes,omitempty"` NestingMode string `json:"nesting_mode,omitempty"` } @@ -33,8 +33,8 @@ func marshalStringKind(sk configschema.StringKind) string { } } -func marshalAttribute(attr *configschema.Attribute) *attribute { - ret := &attribute{ +func marshalAttribute(attr *configschema.Attribute) *Attribute { + ret := &Attribute{ Description: attr.Description, DescriptionKind: marshalStringKind(attr.DescriptionKind), Required: attr.Required, @@ -52,10 +52,10 @@ func marshalAttribute(attr *configschema.Attribute) *attribute { } if attr.NestedType != nil { - nestedTy := nestedType{ + nestedTy := NestedType{ NestingMode: nestingModeString(attr.NestedType.Nesting), } - attrs := make(map[string]*attribute, len(attr.NestedType.Attributes)) + attrs := make(map[string]*Attribute, len(attr.NestedType.Attributes)) for k, attr := range attr.NestedType.Attributes { attrs[k] = marshalAttribute(attr) } diff --git a/internal/command/jsonprovider/attribute_test.go b/internal/command/jsonprovider/attribute_test.go index a2502eadfc..f79c5f7cdb 100644 --- a/internal/command/jsonprovider/attribute_test.go +++ b/internal/command/jsonprovider/attribute_test.go @@ -13,11 +13,11 @@ import ( func TestMarshalAttribute(t *testing.T) { tests := []struct { Input *configschema.Attribute - Want *attribute + Want *Attribute }{ { &configschema.Attribute{Type: cty.String, Optional: true, Computed: true}, - &attribute{ + &Attribute{ AttributeType: json.RawMessage(`"string"`), Optional: true, Computed: true, @@ -26,7 +26,7 @@ func TestMarshalAttribute(t *testing.T) { }, { // collection types look a little odd. &configschema.Attribute{Type: cty.Map(cty.String), Optional: true, Computed: true}, - &attribute{ + &Attribute{ AttributeType: json.RawMessage(`["map","string"]`), Optional: true, Computed: true, diff --git a/internal/command/jsonprovider/block.go b/internal/command/jsonprovider/block.go index ebb145a4e6..e9fdcfb3ea 100644 --- a/internal/command/jsonprovider/block.go +++ b/internal/command/jsonprovider/block.go @@ -4,26 +4,26 @@ import ( "github.com/hashicorp/terraform/internal/configs/configschema" ) -type block struct { - Attributes map[string]*attribute `json:"attributes,omitempty"` - BlockTypes map[string]*blockType `json:"block_types,omitempty"` +type Block struct { + Attributes map[string]*Attribute `json:"attributes,omitempty"` + BlockTypes map[string]*BlockType `json:"block_types,omitempty"` Description string `json:"description,omitempty"` DescriptionKind string `json:"description_kind,omitempty"` Deprecated bool `json:"deprecated,omitempty"` } -type blockType struct { +type BlockType struct { NestingMode string `json:"nesting_mode,omitempty"` - Block *block `json:"block,omitempty"` + Block *Block `json:"block,omitempty"` MinItems uint64 `json:"min_items,omitempty"` MaxItems uint64 `json:"max_items,omitempty"` } -func marshalBlockTypes(nestedBlock *configschema.NestedBlock) *blockType { +func marshalBlockTypes(nestedBlock *configschema.NestedBlock) *BlockType { if nestedBlock == nil { - return &blockType{} + return &BlockType{} } - ret := &blockType{ + ret := &BlockType{ Block: marshalBlock(&nestedBlock.Block), MinItems: uint64(nestedBlock.MinItems), MaxItems: uint64(nestedBlock.MaxItems), @@ -32,19 +32,19 @@ func marshalBlockTypes(nestedBlock *configschema.NestedBlock) *blockType { return ret } -func marshalBlock(configBlock *configschema.Block) *block { +func marshalBlock(configBlock *configschema.Block) *Block { if configBlock == nil { - return &block{} + return &Block{} } - ret := block{ + ret := Block{ Deprecated: configBlock.Deprecated, Description: configBlock.Description, DescriptionKind: marshalStringKind(configBlock.DescriptionKind), } if len(configBlock.Attributes) > 0 { - attrs := make(map[string]*attribute, len(configBlock.Attributes)) + attrs := make(map[string]*Attribute, len(configBlock.Attributes)) for k, attr := range configBlock.Attributes { attrs[k] = marshalAttribute(attr) } @@ -52,7 +52,7 @@ func marshalBlock(configBlock *configschema.Block) *block { } if len(configBlock.BlockTypes) > 0 { - blockTypes := make(map[string]*blockType, len(configBlock.BlockTypes)) + blockTypes := make(map[string]*BlockType, len(configBlock.BlockTypes)) for k, bt := range configBlock.BlockTypes { blockTypes[k] = marshalBlockTypes(bt) } diff --git a/internal/command/jsonprovider/block_test.go b/internal/command/jsonprovider/block_test.go index 93197fb84b..dea72390f5 100644 --- a/internal/command/jsonprovider/block_test.go +++ b/internal/command/jsonprovider/block_test.go @@ -13,11 +13,11 @@ import ( func TestMarshalBlock(t *testing.T) { tests := []struct { Input *configschema.Block - Want *block + Want *Block }{ { nil, - &block{}, + &Block{}, }, { Input: &configschema.Block{ @@ -37,16 +37,16 @@ func TestMarshalBlock(t *testing.T) { }, }, }, - Want: &block{ - Attributes: map[string]*attribute{ + Want: &Block{ + Attributes: map[string]*Attribute{ "ami": {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"}, "id": {AttributeType: json.RawMessage(`"string"`), Optional: true, Computed: true, DescriptionKind: "plain"}, }, - BlockTypes: map[string]*blockType{ + BlockTypes: map[string]*BlockType{ "network_interface": { NestingMode: "list", - Block: &block{ - Attributes: map[string]*attribute{ + Block: &Block{ + Attributes: map[string]*Attribute{ "description": {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"}, "device_index": {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"}, }, diff --git a/internal/command/jsonprovider/provider.go b/internal/command/jsonprovider/provider.go index 4487db4987..8c839ab07d 100644 --- a/internal/command/jsonprovider/provider.go +++ b/internal/command/jsonprovider/provider.go @@ -18,9 +18,9 @@ type providers struct { } type Provider struct { - Provider *schema `json:"provider,omitempty"` - ResourceSchemas map[string]*schema `json:"resource_schemas,omitempty"` - DataSourceSchemas map[string]*schema `json:"data_source_schemas,omitempty"` + Provider *Schema `json:"provider,omitempty"` + ResourceSchemas map[string]*Schema `json:"resource_schemas,omitempty"` + DataSourceSchemas map[string]*Schema `json:"data_source_schemas,omitempty"` } func newProviders() *providers { @@ -47,8 +47,8 @@ func marshalProvider(tps *terraform.ProviderSchema) *Provider { return &Provider{} } - var ps *schema - var rs, ds map[string]*schema + var ps *Schema + var rs, ds map[string]*Schema if tps.Provider != nil { ps = marshalSchema(tps.Provider) diff --git a/internal/command/jsonprovider/provider_test.go b/internal/command/jsonprovider/provider_test.go index 32e8ebce0f..b849c37b82 100644 --- a/internal/command/jsonprovider/provider_test.go +++ b/internal/command/jsonprovider/provider_test.go @@ -23,9 +23,9 @@ func TestMarshalProvider(t *testing.T) { { testProvider(), &Provider{ - Provider: &schema{ - Block: &block{ - Attributes: map[string]*attribute{ + Provider: &Schema{ + Block: &Block{ + Attributes: map[string]*Attribute{ "region": { AttributeType: json.RawMessage(`"string"`), Required: true, @@ -35,11 +35,11 @@ func TestMarshalProvider(t *testing.T) { DescriptionKind: "plain", }, }, - ResourceSchemas: map[string]*schema{ + ResourceSchemas: map[string]*Schema{ "test_instance": { Version: 42, - Block: &block{ - Attributes: map[string]*attribute{ + Block: &Block{ + Attributes: map[string]*Attribute{ "id": { AttributeType: json.RawMessage(`"string"`), Optional: true, @@ -52,9 +52,9 @@ func TestMarshalProvider(t *testing.T) { DescriptionKind: "plain", }, "volumes": { - AttributeNestedType: &nestedType{ + AttributeNestedType: &NestedType{ NestingMode: "list", - Attributes: map[string]*attribute{ + Attributes: map[string]*Attribute{ "size": { AttributeType: json.RawMessage(`"string"`), Required: true, @@ -71,10 +71,10 @@ func TestMarshalProvider(t *testing.T) { DescriptionKind: "plain", }, }, - BlockTypes: map[string]*blockType{ + BlockTypes: map[string]*BlockType{ "network_interface": { - Block: &block{ - Attributes: map[string]*attribute{ + Block: &Block{ + Attributes: map[string]*Attribute{ "device_index": { AttributeType: json.RawMessage(`"string"`), Optional: true, @@ -95,11 +95,11 @@ func TestMarshalProvider(t *testing.T) { }, }, }, - DataSourceSchemas: map[string]*schema{ + DataSourceSchemas: map[string]*Schema{ "test_data_source": { Version: 3, - Block: &block{ - Attributes: map[string]*attribute{ + Block: &Block{ + Attributes: map[string]*Attribute{ "id": { AttributeType: json.RawMessage(`"string"`), Optional: true, @@ -112,10 +112,10 @@ func TestMarshalProvider(t *testing.T) { DescriptionKind: "plain", }, }, - BlockTypes: map[string]*blockType{ + BlockTypes: map[string]*BlockType{ "network_interface": { - Block: &block{ - Attributes: map[string]*attribute{ + Block: &Block{ + Attributes: map[string]*Attribute{ "device_index": { AttributeType: json.RawMessage(`"string"`), Optional: true, diff --git a/internal/command/jsonprovider/schema.go b/internal/command/jsonprovider/schema.go index 5a1465b8a7..c33962a163 100644 --- a/internal/command/jsonprovider/schema.go +++ b/internal/command/jsonprovider/schema.go @@ -4,29 +4,29 @@ import ( "github.com/hashicorp/terraform/internal/configs/configschema" ) -type schema struct { +type Schema struct { Version uint64 `json:"version"` - Block *block `json:"block,omitempty"` + Block *Block `json:"block,omitempty"` } // marshalSchema is a convenience wrapper around mashalBlock. Schema version // should be set by the caller. -func marshalSchema(block *configschema.Block) *schema { +func marshalSchema(block *configschema.Block) *Schema { if block == nil { - return &schema{} + return &Schema{} } - var ret schema + var ret Schema ret.Block = marshalBlock(block) return &ret } -func marshalSchemas(blocks map[string]*configschema.Block, rVersions map[string]uint64) map[string]*schema { +func marshalSchemas(blocks map[string]*configschema.Block, rVersions map[string]uint64) map[string]*Schema { if blocks == nil { - return map[string]*schema{} + return map[string]*Schema{} } - ret := make(map[string]*schema, len(blocks)) + ret := make(map[string]*Schema, len(blocks)) for k, v := range blocks { ret[k] = marshalSchema(v) version, ok := rVersions[k] diff --git a/internal/command/jsonprovider/schema_test.go b/internal/command/jsonprovider/schema_test.go index 737a8d74f8..d4fae307d5 100644 --- a/internal/command/jsonprovider/schema_test.go +++ b/internal/command/jsonprovider/schema_test.go @@ -12,12 +12,12 @@ func TestMarshalSchemas(t *testing.T) { tests := []struct { Input map[string]*configschema.Block Versions map[string]uint64 - Want map[string]*schema + Want map[string]*Schema }{ { nil, map[string]uint64{}, - map[string]*schema{}, + map[string]*Schema{}, }, } @@ -32,11 +32,11 @@ func TestMarshalSchemas(t *testing.T) { func TestMarshalSchema(t *testing.T) { tests := map[string]struct { Input *configschema.Block - Want *schema + Want *Schema }{ "nil_block": { nil, - &schema{}, + &Schema{}, }, }