diff --git a/command/jsonprovider/attribute.go b/command/jsonprovider/attribute.go index fd5adb268e1a..0702e73cef2b 100644 --- a/command/jsonprovider/attribute.go +++ b/command/jsonprovider/attribute.go @@ -4,17 +4,26 @@ import ( "encoding/json" "github.com/hashicorp/terraform/configs/configschema" + "github.com/zclconf/go-cty/cty" ) type attribute struct { - AttributeType json.RawMessage `json:"type,omitempty"` - Description string `json:"description,omitempty"` - DescriptionKind string `json:"description_kind,omitempty"` - Deprecated bool `json:"deprecated,omitempty"` - Required bool `json:"required,omitempty"` - Optional bool `json:"optional,omitempty"` - Computed bool `json:"computed,omitempty"` - Sensitive bool `json:"sensitive,omitempty"` + AttributeType json.RawMessage `json:"type,omitempty"` + AttributeNestedType *nestedType `json:"nested_type,omitempty"` + Description string `json:"description,omitempty"` + DescriptionKind string `json:"description_kind,omitempty"` + Deprecated bool `json:"deprecated,omitempty"` + Required bool `json:"required,omitempty"` + Optional bool `json:"optional,omitempty"` + Computed bool `json:"computed,omitempty"` + Sensitive bool `json:"sensitive,omitempty"` +} + +type nestedType struct { + Attributes map[string]*attribute `json:"attributes,omitempty"` + NestingMode string `json:"nesting_mode,omitempty"` + MinItems uint64 `json:"min_items,omitempty"` + MaxItems uint64 `json:"max_items,omitempty"` } func marshalStringKind(sk configschema.StringKind) string { @@ -27,12 +36,7 @@ func marshalStringKind(sk configschema.StringKind) string { } func marshalAttribute(attr *configschema.Attribute) *attribute { - // we're not concerned about errors because at this point the schema has - // already been checked and re-checked. - attrTy, _ := attr.Type.MarshalJSON() - - return &attribute{ - AttributeType: attrTy, + ret := &attribute{ Description: attr.Description, DescriptionKind: marshalStringKind(attr.DescriptionKind), Required: attr.Required, @@ -41,4 +45,27 @@ func marshalAttribute(attr *configschema.Attribute) *attribute { Sensitive: attr.Sensitive, Deprecated: attr.Deprecated, } + + // we're not concerned about errors because at this point the schema has + // already been checked and re-checked. + if attr.Type != cty.NilType { + attrTy, _ := attr.Type.MarshalJSON() + ret.AttributeType = attrTy + } + + if attr.NestedType != nil { + nestedTy := nestedType{ + MinItems: uint64(attr.NestedType.MinItems), + MaxItems: uint64(attr.NestedType.MaxItems), + NestingMode: nestingModeString(attr.NestedType.Nesting), + } + attrs := make(map[string]*attribute, len(attr.NestedType.Attributes)) + for k, attr := range attr.NestedType.Attributes { + attrs[k] = marshalAttribute(attr) + } + nestedTy.Attributes = attrs + ret.AttributeNestedType = &nestedTy + } + + return ret } diff --git a/command/jsonprovider/block.go b/command/jsonprovider/block.go index 3f90987f2984..a41f9a8399a9 100644 --- a/command/jsonprovider/block.go +++ b/command/jsonprovider/block.go @@ -24,24 +24,10 @@ func marshalBlockTypes(nestedBlock *configschema.NestedBlock) *blockType { return &blockType{} } ret := &blockType{ - Block: marshalBlock(&nestedBlock.Block), - MinItems: uint64(nestedBlock.MinItems), - MaxItems: uint64(nestedBlock.MaxItems), - } - - switch nestedBlock.Nesting { - case configschema.NestingSingle: - ret.NestingMode = "single" - case configschema.NestingGroup: - ret.NestingMode = "group" - case configschema.NestingList: - ret.NestingMode = "list" - case configschema.NestingSet: - ret.NestingMode = "set" - case configschema.NestingMap: - ret.NestingMode = "map" - default: - ret.NestingMode = "invalid" + Block: marshalBlock(&nestedBlock.Block), + MinItems: uint64(nestedBlock.MinItems), + MaxItems: uint64(nestedBlock.MaxItems), + NestingMode: nestingModeString(nestedBlock.Nesting), } return ret } @@ -75,3 +61,20 @@ func marshalBlock(configBlock *configschema.Block) *block { return &ret } + +func nestingModeString(mode configschema.NestingMode) string { + switch mode { + case configschema.NestingSingle: + return "single" + case configschema.NestingGroup: + return "group" + case configschema.NestingList: + return "list" + case configschema.NestingSet: + return "set" + case configschema.NestingMap: + return "map" + default: + return "invalid" + } +} diff --git a/command/jsonprovider/provider_test.go b/command/jsonprovider/provider_test.go index 1d6bfd7240d7..098d5dc1b9e3 100644 --- a/command/jsonprovider/provider_test.go +++ b/command/jsonprovider/provider_test.go @@ -51,6 +51,25 @@ func TestMarshalProvider(t *testing.T) { Optional: true, DescriptionKind: "plain", }, + "volumes": { + AttributeNestedType: &nestedType{ + NestingMode: "list", + Attributes: map[string]*attribute{ + "size": { + AttributeType: json.RawMessage(`"string"`), + Required: true, + DescriptionKind: "plain", + }, + "mount_point": { + AttributeType: json.RawMessage(`"string"`), + Required: true, + DescriptionKind: "plain", + }, + }, + }, + Optional: true, + DescriptionKind: "plain", + }, }, BlockTypes: map[string]*blockType{ "network_interface": { @@ -141,6 +160,16 @@ func testProvider() *terraform.ProviderSchema { Attributes: map[string]*configschema.Attribute{ "id": {Type: cty.String, Optional: true, Computed: true}, "ami": {Type: cty.String, Optional: true}, + "volumes": { + Optional: true, + NestedType: &configschema.Object{ + Nesting: configschema.NestingList, + Attributes: map[string]*configschema.Attribute{ + "size": {Type: cty.String, Required: true}, + "mount_point": {Type: cty.String, Required: true}, + }, + }, + }, }, BlockTypes: map[string]*configschema.NestedBlock{ "network_interface": { diff --git a/command/providers_schema_test.go b/command/providers_schema_test.go index 96890f254ffa..3cf0de1f53c0 100644 --- a/command/providers_schema_test.go +++ b/command/providers_schema_test.go @@ -9,7 +9,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" + "github.com/zclconf/go-cty/cty" ) func TestProvidersSchema_error(t *testing.T) { @@ -28,8 +32,6 @@ func TestProvidersSchema_error(t *testing.T) { } func TestProvidersSchema_output(t *testing.T) { - // there's only one test at this time. This can be refactored to have - // multiple test cases in individual directories as needed. fixtureDir := "testdata/providers-schema" testDirs, err := ioutil.ReadDir(fixtureDir) if err != nil { @@ -48,11 +50,11 @@ func TestProvidersSchema_output(t *testing.T) { defer testChdir(t, td)() providerSource, close := newMockProviderSource(t, map[string][]string{ - "test": []string{"1.2.3"}, + "test": {"1.2.3"}, }) defer close() - p := showFixtureProvider() + p := providersSchemaFixtureProvider() ui := new(cli.MockUi) m := Meta{ testingOverrides: metaOverridesForProvider(p), @@ -109,3 +111,45 @@ type providerSchema struct { ResourceSchemas map[string]interface{} `json:"resource_schemas,omitempty"` DataSourceSchemas map[string]interface{} `json:"data_source_schemas,omitempty"` } + +// testProvider returns a mock provider that is configured for basic +// operation with the configuration in testdata/providers-schema. +func providersSchemaFixtureProvider() *terraform.MockProvider { + p := testProvider() + p.GetProviderSchemaResponse = providersSchemaFixtureSchema() + return p +} + +// providersSchemaFixtureSchema returns a schema suitable for processing the +// configuration in testdata/providers-schema.ß +func providersSchemaFixtureSchema() *providers.GetProviderSchemaResponse { + return &providers.GetProviderSchemaResponse{ + Provider: providers.Schema{ + Block: &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "region": {Type: cty.String, Optional: true}, + }, + }, + }, + ResourceTypes: map[string]providers.Schema{ + "test_instance": { + Block: &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "id": {Type: cty.String, Optional: true, Computed: true}, + "ami": {Type: cty.String, Optional: true}, + "volumes": { + NestedType: &configschema.Object{ + Nesting: configschema.NestingList, + Attributes: map[string]*configschema.Attribute{ + "size": {Type: cty.String, Required: true}, + "mount_point": {Type: cty.String, Required: true}, + }, + }, + Optional: true, + }, + }, + }, + }, + }, + } +} diff --git a/command/testdata/providers-schema/basic/output.json b/command/testdata/providers-schema/basic/output.json index ba58e2f3c601..9841064cc5fa 100644 --- a/command/testdata/providers-schema/basic/output.json +++ b/command/testdata/providers-schema/basic/output.json @@ -30,6 +30,25 @@ "optional": true, "computed": true, "description_kind": "plain" + }, + "volumes": { + "nested_type": { + "nesting_mode": "list", + "attributes": { + "size": { + "type": "string", + "required": true, + "description_kind": "plain" + }, + "mount_point": { + "type": "string", + "required": true, + "description_kind": "plain" + } + } + }, + "description_kind": "plain", + "optional": true } }, "description_kind": "plain" diff --git a/command/testdata/providers-schema/required/output.json b/command/testdata/providers-schema/required/output.json index ba58e2f3c601..9841064cc5fa 100644 --- a/command/testdata/providers-schema/required/output.json +++ b/command/testdata/providers-schema/required/output.json @@ -30,6 +30,25 @@ "optional": true, "computed": true, "description_kind": "plain" + }, + "volumes": { + "nested_type": { + "nesting_mode": "list", + "attributes": { + "size": { + "type": "string", + "required": true, + "description_kind": "plain" + }, + "mount_point": { + "type": "string", + "required": true, + "description_kind": "plain" + } + } + }, + "description_kind": "plain", + "optional": true } }, "description_kind": "plain"