command/jsonprovider: export providers schemas to json (#20446)
* command/jsonprovider: a new package for exporting providers schemas as JSON
This commit is contained in:
parent
2b9e2b4c2b
commit
16823f43de
|
@ -0,0 +1,31 @@
|
|||
package jsonprovider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
)
|
||||
|
||||
type attribute struct {
|
||||
AttributeType json.RawMessage `json:"type,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Required bool `json:"required,omitempty"`
|
||||
Optional bool `json:"optional,omitempty"`
|
||||
Computed bool `json:"computed,omitempty"`
|
||||
Sensitive bool `json:"sensitive,omitempty"`
|
||||
}
|
||||
|
||||
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,
|
||||
Description: attr.Description,
|
||||
Required: attr.Required,
|
||||
Optional: attr.Optional,
|
||||
Computed: attr.Computed,
|
||||
Sensitive: attr.Sensitive,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package jsonprovider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
)
|
||||
|
||||
func TestMarshalAttribute(t *testing.T) {
|
||||
tests := []struct {
|
||||
Input *configschema.Attribute
|
||||
Want *attribute
|
||||
}{
|
||||
{
|
||||
&configschema.Attribute{Type: cty.String, Optional: true, Computed: true},
|
||||
&attribute{
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
{ // collection types look a little odd.
|
||||
&configschema.Attribute{Type: cty.Map(cty.String), Optional: true, Computed: true},
|
||||
&attribute{
|
||||
AttributeType: json.RawMessage(`["map","string"]`),
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := marshalAttribute(test.Input)
|
||||
if !cmp.Equal(got, test.Want) {
|
||||
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package jsonprovider
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
)
|
||||
|
||||
type block struct {
|
||||
Attributes map[string]*attribute `json:"attributes,omitempty"`
|
||||
BlockTypes map[string]*blockType `json:"block_types,omitempty"`
|
||||
}
|
||||
|
||||
type blockType struct {
|
||||
NestingMode string `json:"nesting_mode,omitempty"`
|
||||
Block *block `json:"block,omitempty"`
|
||||
MinItems uint64 `json:"min_items,omitempty"`
|
||||
MaxItems uint64 `json:"max_items,omitempty"`
|
||||
}
|
||||
|
||||
func marshalBlockTypes(nestedBlock *configschema.NestedBlock) *blockType {
|
||||
if nestedBlock == nil {
|
||||
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.NestingList:
|
||||
ret.NestingMode = "list"
|
||||
case configschema.NestingSet:
|
||||
ret.NestingMode = "set"
|
||||
case configschema.NestingMap:
|
||||
ret.NestingMode = "map"
|
||||
default:
|
||||
ret.NestingMode = "invalid"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func marshalBlock(configBlock *configschema.Block) *block {
|
||||
if configBlock == nil {
|
||||
return &block{}
|
||||
}
|
||||
|
||||
var ret block
|
||||
if len(configBlock.Attributes) > 0 {
|
||||
attrs := make(map[string]*attribute, len(configBlock.Attributes))
|
||||
for k, attr := range configBlock.Attributes {
|
||||
attrs[k] = marshalAttribute(attr)
|
||||
}
|
||||
ret.Attributes = attrs
|
||||
}
|
||||
|
||||
if len(configBlock.BlockTypes) > 0 {
|
||||
blockTypes := make(map[string]*blockType, len(configBlock.BlockTypes))
|
||||
for k, bt := range configBlock.BlockTypes {
|
||||
blockTypes[k] = marshalBlockTypes(bt)
|
||||
}
|
||||
ret.BlockTypes = blockTypes
|
||||
}
|
||||
|
||||
return &ret
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package jsonprovider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
)
|
||||
|
||||
func TestMarshalBlock(t *testing.T) {
|
||||
tests := []struct {
|
||||
Input *configschema.Block
|
||||
Want *block
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
&block{},
|
||||
},
|
||||
{
|
||||
Input: &configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Optional: true, Computed: true},
|
||||
"ami": {Type: cty.String, Optional: true},
|
||||
},
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"network_interface": {
|
||||
Nesting: configschema.NestingList,
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"device_index": {Type: cty.String, Optional: true},
|
||||
"description": {Type: cty.String, Optional: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Want: &block{
|
||||
Attributes: map[string]*attribute{
|
||||
"ami": {AttributeType: json.RawMessage(`"string"`), Optional: true},
|
||||
"id": {AttributeType: json.RawMessage(`"string"`), Optional: true, Computed: true},
|
||||
},
|
||||
BlockTypes: map[string]*blockType{
|
||||
"network_interface": {
|
||||
NestingMode: "list",
|
||||
Block: &block{
|
||||
Attributes: map[string]*attribute{
|
||||
"description": {AttributeType: json.RawMessage(`"string"`), Optional: true},
|
||||
"device_index": {AttributeType: json.RawMessage(`"string"`), Optional: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := marshalBlock(test.Input)
|
||||
if !cmp.Equal(got, test.Want) {
|
||||
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
// Package jsonprovider contains types and functions to marshal terraform
|
||||
// provider schemas into a json formatted output.
|
||||
package jsonprovider
|
|
@ -0,0 +1,75 @@
|
|||
package jsonprovider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
// FormatVersion represents the version of the json format and will be
|
||||
// incremented for any change to this format that requires changes to a
|
||||
// consuming parser.
|
||||
const FormatVersion = "0.1"
|
||||
|
||||
// providers is the top-level object returned when exporting provider schemas
|
||||
type providers struct {
|
||||
FormatVersion string `json:"format_version"`
|
||||
Schemas map[string]Provider `json:"provider_schemas"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
func newProviders() *providers {
|
||||
schemas := make(map[string]Provider)
|
||||
return &providers{
|
||||
FormatVersion: FormatVersion,
|
||||
Schemas: schemas,
|
||||
}
|
||||
}
|
||||
|
||||
func Marshal(s *terraform.Schemas) ([]byte, error) {
|
||||
if len(s.Providers) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
providers := newProviders()
|
||||
|
||||
for k, v := range s.Providers {
|
||||
providers.Schemas[k] = marshalProvider(v)
|
||||
}
|
||||
|
||||
// add some polish for the human consumers
|
||||
ret, err := json.MarshalIndent(providers, "", " ")
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func marshalProvider(tps *terraform.ProviderSchema) Provider {
|
||||
if tps == nil {
|
||||
return Provider{}
|
||||
}
|
||||
|
||||
var ps *schema
|
||||
var rs, ds map[string]*schema
|
||||
|
||||
if tps.Provider != nil {
|
||||
ps = marshalSchema(tps.Provider)
|
||||
}
|
||||
|
||||
if tps.ResourceTypes != nil {
|
||||
rs = marshalSchemas(tps.ResourceTypes, tps.ResourceTypeSchemaVersions)
|
||||
}
|
||||
|
||||
if tps.DataSources != nil {
|
||||
ds = marshalSchemas(tps.DataSources, tps.ResourceTypeSchemaVersions)
|
||||
}
|
||||
|
||||
return Provider{
|
||||
Provider: ps,
|
||||
ResourceSchemas: rs,
|
||||
DataSourceSchemas: ds,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
package jsonprovider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestMarshalProvider(t *testing.T) {
|
||||
tests := []struct {
|
||||
Input *terraform.ProviderSchema
|
||||
Want Provider
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
Provider{},
|
||||
},
|
||||
{
|
||||
testProvider(),
|
||||
Provider{
|
||||
Provider: &schema{
|
||||
Block: &block{
|
||||
Attributes: map[string]*attribute{
|
||||
"region": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ResourceSchemas: map[string]*schema{
|
||||
"test_instance": {
|
||||
Version: 42,
|
||||
Block: &block{
|
||||
Attributes: map[string]*attribute{
|
||||
"id": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"ami": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
BlockTypes: map[string]*blockType{
|
||||
"network_interface": {
|
||||
Block: &block{
|
||||
Attributes: map[string]*attribute{
|
||||
"device_index": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
},
|
||||
"description": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
NestingMode: "list",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DataSourceSchemas: map[string]*schema{
|
||||
"test_data_source": {
|
||||
Version: 3,
|
||||
Block: &block{
|
||||
Attributes: map[string]*attribute{
|
||||
"id": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"ami": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
BlockTypes: map[string]*blockType{
|
||||
"network_interface": {
|
||||
Block: &block{
|
||||
Attributes: map[string]*attribute{
|
||||
"device_index": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
},
|
||||
"description": {
|
||||
AttributeType: json.RawMessage(`"string"`),
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
NestingMode: "list",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := marshalProvider(test.Input)
|
||||
if !cmp.Equal(got, test.Want) {
|
||||
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testProviders() *terraform.Schemas {
|
||||
return &terraform.Schemas{
|
||||
Providers: map[string]*terraform.ProviderSchema{
|
||||
"test": testProvider(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testProvider() *terraform.ProviderSchema {
|
||||
return &terraform.ProviderSchema{
|
||||
Provider: &configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"region": {Type: cty.String, Required: true},
|
||||
},
|
||||
},
|
||||
ResourceTypes: map[string]*configschema.Block{
|
||||
"test_instance": {
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Optional: true, Computed: true},
|
||||
"ami": {Type: cty.String, Optional: true},
|
||||
},
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"network_interface": {
|
||||
Nesting: configschema.NestingList,
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"device_index": {Type: cty.String, Optional: true},
|
||||
"description": {Type: cty.String, Optional: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DataSources: map[string]*configschema.Block{
|
||||
"test_data_source": {
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Optional: true, Computed: true},
|
||||
"ami": {Type: cty.String, Optional: true},
|
||||
},
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"network_interface": {
|
||||
Nesting: configschema.NestingList,
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"device_index": {Type: cty.String, Optional: true},
|
||||
"description": {Type: cty.String, Optional: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
ResourceTypeSchemaVersions: map[string]uint64{
|
||||
"test_instance": 42,
|
||||
"test_data_source": 3,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package jsonprovider
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
)
|
||||
|
||||
type schema struct {
|
||||
Version uint64 `json:"version"`
|
||||
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 {
|
||||
if block == nil {
|
||||
return &schema{}
|
||||
}
|
||||
|
||||
var ret schema
|
||||
ret.Block = marshalBlock(block)
|
||||
|
||||
return &ret
|
||||
}
|
||||
|
||||
func marshalSchemas(blocks map[string]*configschema.Block, rVersions map[string]uint64) map[string]*schema {
|
||||
if blocks == nil {
|
||||
return map[string]*schema{}
|
||||
}
|
||||
ret := make(map[string]*schema, len(blocks))
|
||||
for k, v := range blocks {
|
||||
ret[k] = marshalSchema(v)
|
||||
version, ok := rVersions[k]
|
||||
if ok {
|
||||
ret[k].Version = version
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package jsonprovider
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
)
|
||||
|
||||
func TestMarshalSchemas(t *testing.T) {
|
||||
tests := []struct {
|
||||
Input map[string]*configschema.Block
|
||||
Versions map[string]uint64
|
||||
Want map[string]*schema
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
map[string]uint64{},
|
||||
map[string]*schema{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := marshalSchemas(test.Input, test.Versions)
|
||||
if !cmp.Equal(got, test.Want) {
|
||||
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalSchema(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
Input *configschema.Block
|
||||
Want *schema
|
||||
}{
|
||||
"nil_block": {
|
||||
nil,
|
||||
&schema{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := marshalSchema(test.Input)
|
||||
if !cmp.Equal(got, test.Want) {
|
||||
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/jsonprovider"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
// ProvidersCommand is a Command implementation that prints out information
|
||||
// about the providers used in the current configuration/state.
|
||||
type ProvidersSchemaCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *ProvidersSchemaCommand) Help() string {
|
||||
return providersSchemaCommandHelp
|
||||
}
|
||||
|
||||
func (c *ProvidersSchemaCommand) Synopsis() string {
|
||||
return "Prints the schemas of the providers used in the configuration"
|
||||
}
|
||||
|
||||
func (c *ProvidersSchemaCommand) Run(args []string) int {
|
||||
args, err := c.Meta.process(args, false)
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
cmdFlags := c.Meta.defaultFlagSet("providers schema")
|
||||
var jsonOutput bool
|
||||
cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output")
|
||||
|
||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
if !jsonOutput {
|
||||
c.Ui.Error(
|
||||
"The `terraform providers schema` command requires the `-json` flag.\n")
|
||||
cmdFlags.Usage()
|
||||
return 1
|
||||
}
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// Load the backend
|
||||
b, backendDiags := c.Backend(nil)
|
||||
diags = diags.Append(backendDiags)
|
||||
if backendDiags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// We require a local backend
|
||||
local, ok := b.(backend.Local)
|
||||
if !ok {
|
||||
c.showDiagnostics(diags) // in case of any warnings in here
|
||||
c.Ui.Error(ErrUnsupportedLocalOp)
|
||||
return 1
|
||||
}
|
||||
|
||||
// we expect that the config dir is the cwd
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting cwd: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Build the operation
|
||||
opReq := c.Operation(b)
|
||||
opReq.ConfigDir = cwd
|
||||
opReq.ConfigLoader, err = c.initConfigLoader()
|
||||
if err != nil {
|
||||
diags = diags.Append(err)
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get the context
|
||||
ctx, _, ctxDiags := local.Context(opReq)
|
||||
diags = diags.Append(ctxDiags)
|
||||
if ctxDiags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
schemas := ctx.Schemas()
|
||||
jsonSchemas, err := jsonprovider.Marshal(schemas)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to marshal provider schemas to json: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(string(jsonSchemas))
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
const providersSchemaCommandHelp = `
|
||||
Usage: terraform providers schemas -json
|
||||
|
||||
Prints out a json representation of the schemas for all providers used
|
||||
in the current configuration.
|
||||
`
|
|
@ -0,0 +1,101 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/mitchellh/cli"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/copy"
|
||||
)
|
||||
|
||||
func TestProvidersSchema_error(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
c := &ProvidersSchemaCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
},
|
||||
}
|
||||
|
||||
if code := c.Run(nil); code != 1 {
|
||||
fmt.Println(ui.OutputWriter.String())
|
||||
t.Fatalf("expected error: \n%s", ui.OutputWriter.String())
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
inputDir := "test-fixtures/providers-schema"
|
||||
td := tempDir(t)
|
||||
copy.CopyDir(inputDir, td)
|
||||
defer os.RemoveAll(td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
p := showFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
}
|
||||
|
||||
// `terrafrom init`
|
||||
ic := &InitCommand{
|
||||
Meta: m,
|
||||
providerInstaller: &mockProviderInstaller{
|
||||
Providers: map[string][]string{
|
||||
"test": []string{"1.2.3"},
|
||||
},
|
||||
Dir: m.pluginDir(),
|
||||
},
|
||||
}
|
||||
if code := ic.Run([]string{}); code != 0 {
|
||||
t.Fatalf("init failed\n%s", ui.ErrorWriter)
|
||||
}
|
||||
|
||||
// flush the init output from the mock ui
|
||||
ui.OutputWriter.Reset()
|
||||
|
||||
// `terraform provider schemas` command
|
||||
pc := &ProvidersSchemaCommand{Meta: m}
|
||||
if code := pc.Run([]string{"-json"}); code != 0 {
|
||||
t.Fatalf("wrong exit status %d; want 0\nstderr: %s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
var got, want providerSchemas
|
||||
|
||||
gotString := ui.OutputWriter.String()
|
||||
json.Unmarshal([]byte(gotString), &got)
|
||||
|
||||
wantFile, err := os.Open("output.json")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer wantFile.Close()
|
||||
byteValue, err := ioutil.ReadAll(wantFile)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
json.Unmarshal([]byte(byteValue), &want)
|
||||
|
||||
if !cmp.Equal(got, want) {
|
||||
fmt.Println(gotString)
|
||||
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type providerSchemas struct {
|
||||
FormatVersion string `json:"format_version"`
|
||||
Schemas map[string]providerSchema `json:"provider_schemas"`
|
||||
}
|
||||
|
||||
type providerSchema struct {
|
||||
Provider interface{} `json:"provider,omitempty"`
|
||||
ResourceSchemas map[string]interface{} `json:"resource_schemas,omitempty"`
|
||||
DataSourceSchemas map[string]interface{} `json:"data_source_schemas,omitempty"`
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"format_version": "0.1",
|
||||
"provider_schemas": {
|
||||
"test": {
|
||||
"resource_schemas": {
|
||||
"test_instance": {
|
||||
"version": 0,
|
||||
"block": {
|
||||
"attributes": {
|
||||
"ami": {
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"computed": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
provider "test" {
|
||||
|
||||
}
|
|
@ -186,6 +186,12 @@ func initCommands(config *Config, services *disco.Disco) {
|
|||
}, nil
|
||||
},
|
||||
|
||||
"providers schema": func() (cli.Command, error) {
|
||||
return &command.ProvidersSchemaCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"push": func() (cli.Command, error) {
|
||||
return &command.PushCommand{
|
||||
Meta: meta,
|
||||
|
|
Loading…
Reference in New Issue