Skip to content

Commit

Permalink
Fix provider schema matching (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko authored Mar 17, 2021
1 parent 6d963da commit a8c0201
Show file tree
Hide file tree
Showing 8 changed files with 911 additions and 80 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/google/go-cmp v0.5.5
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-version v1.2.1
github.com/hashicorp/hcl-lang v0.0.0-20210311200725-da0537032422
github.com/hashicorp/hcl-lang v0.0.0-20210317074414-9bb6847208c3
github.com/hashicorp/hcl/v2 v2.9.1
github.com/hashicorp/terraform-config-inspect v0.0.0-20201102131242-0c45ba392e51
github.com/hashicorp/terraform-json v0.8.0
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,15 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws=
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/hcl-lang v0.0.0-20210311200725-da0537032422 h1:hDjba3BV66uIFJN07x2xcubtueRoZMVPpSScv0fQtjI=
github.com/hashicorp/hcl-lang v0.0.0-20210311200725-da0537032422/go.mod h1:TUGbLnxaJsOmfcJ+hwWTQxLmZX2lZSd+uMFNNphz6hc=
github.com/hashicorp/hcl-lang v0.0.0-20210317074414-9bb6847208c3 h1:s33G8woMGjgqckJnOXbDqRi42kNfPs0+I5TmqRU5Xts=
github.com/hashicorp/hcl-lang v0.0.0-20210317074414-9bb6847208c3/go.mod h1:ZGuDQ7IWG2eFZZJC4pBZFnbH8afJ8gyOPmlHt5lJZK0=
github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90=
github.com/hashicorp/hcl/v2 v2.9.1 h1:eOy4gREY0/ZQHNItlfuEZqtcQbXIxzojlP301hDpnac=
github.com/hashicorp/hcl/v2 v2.9.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
Expand Down
26 changes: 26 additions & 0 deletions internal/refdecoder/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,32 @@ terraform {
},
},
},
{
"default namespace provider under different local name",
`
terraform {
required_providers {
rand = {
source = "hashicorp/random"
version = "3.0.0"
}
}
}
resource "random_string" "name" {
provider = rand
}
`,
addrs.ProviderReferences{
addrs.LocalProviderConfig{
LocalName: "rand",
}: addrs.Provider{
Hostname: addrs.DefaultRegistryHost,
Namespace: "hashicorp",
Type: "random",
},
},
},
{
"resource block",
`
Expand Down
67 changes: 42 additions & 25 deletions schema/schema_merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package schema

import (
"fmt"
"strings"

"github.com/hashicorp/go-version"
"github.com/hashicorp/hcl-lang/lang"
Expand Down Expand Up @@ -94,13 +95,6 @@ func (m *SchemaMerger) MergeWithJsonProviderSchemas(ps *tfjson.ProviderSchemas)

localRefs := refs.LocalNamesByAddr(srcAddr)

if len(localRefs) == 0 && (srcAddr.IsBuiltIn() || srcAddr.IsLegacy() || srcAddr.IsDefault()) {
// Assume this provider does not have alias
localRefs = append(localRefs, addrs.LocalProviderConfig{
LocalName: srcAddr.Type,
})
}

var providerSchema *tfjson.SchemaBlock
if provider.ConfigSchema != nil {
providerSchema = provider.ConfigSchema.Block
Expand All @@ -118,27 +112,42 @@ func (m *SchemaMerger) MergeWithJsonProviderSchemas(ps *tfjson.ProviderSchemas)
},
})] = pSchema

providerAddr := lang.Address{
lang.RootStep{Name: localRef.LocalName},
}
if localRef.Alias != "" {
providerAddr = append(providerAddr, lang.AttrStep{Name: localRef.Alias})
}

for rName, rJsonSchema := range provider.ResourceSchemas {
rSchema := convertBodySchemaFromJson(detail, rJsonSchema.Block)

depKeys := schema.DependencyKeys{
Labels: []schema.LabelDependent{
{Index: 0, Value: rName},
},
}
if localRef.Alias != "" {
depKeys.Attributes = append(depKeys.Attributes, schema.AttributeDependent{
Name: "provider",
Expr: schema.ExpressionValue{
Address: lang.Address{
lang.RootStep{Name: localRef.LocalName},
lang.AttrStep{Name: localRef.Alias},
Attributes: []schema.AttributeDependent{
{
Name: "provider",
Expr: schema.ExpressionValue{
Address: providerAddr,
},
},
})
},
}

mergedSchema.Blocks["resource"].DependentBody[schema.NewSchemaKey(depKeys)] = rSchema

// No explicit association is required
// if the resource prefix matches provider name
if strings.HasPrefix(rName, localRef.LocalName+"_") {
depKeys := schema.DependencyKeys{
Labels: []schema.LabelDependent{
{Index: 0, Value: rName},
},
}
mergedSchema.Blocks["resource"].DependentBody[schema.NewSchemaKey(depKeys)] = rSchema
}
}

for dsName, dsJsonSchema := range provider.DataSourceSchemas {
Expand All @@ -148,20 +157,28 @@ func (m *SchemaMerger) MergeWithJsonProviderSchemas(ps *tfjson.ProviderSchemas)
Labels: []schema.LabelDependent{
{Index: 0, Value: dsName},
},
}
if localRef.Alias != "" {
depKeys.Attributes = append(depKeys.Attributes, schema.AttributeDependent{
Name: "provider",
Expr: schema.ExpressionValue{
Address: lang.Address{
lang.RootStep{Name: localRef.LocalName},
lang.AttrStep{Name: localRef.Alias},
Attributes: []schema.AttributeDependent{
{
Name: "provider",
Expr: schema.ExpressionValue{
Address: providerAddr,
},
},
})
},
}

mergedSchema.Blocks["data"].DependentBody[schema.NewSchemaKey(depKeys)] = dsSchema

// No explicit association is required
// if the resource prefix matches provider name
if strings.HasPrefix(dsName, localRef.LocalName+"_") {
depKeys := schema.DependencyKeys{
Labels: []schema.LabelDependent{
{Index: 0, Value: dsName},
},
}
mergedSchema.Blocks["data"].DependentBody[schema.NewSchemaKey(depKeys)] = dsSchema
}
}
}
}
Expand Down
145 changes: 108 additions & 37 deletions schema/schema_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,42 @@ func TestMergeWithJsonProviderSchemas_noCoreSchema(t *testing.T) {
}

func TestMergeWithJsonProviderSchemas_noProviderSchema(t *testing.T) {
testCoreSchema := &schema.BodySchema{
Blocks: map[string]*schema.BlockSchema{
"provider": {
Labels: []*schema.LabelSchema{
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"alias": {Expr: schema.LiteralTypeOnly(cty.String), IsOptional: true},
},
},
},
"resource": {
Labels: []*schema.LabelSchema{
{Name: "type"},
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"count": {Expr: schema.LiteralTypeOnly(cty.Number), IsOptional: true},
},
},
},
"data": {
Labels: []*schema.LabelSchema{
{Name: "type"},
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"count": {Expr: schema.LiteralTypeOnly(cty.Number), IsOptional: true},
},
},
},
},
}
sm := NewSchemaMerger(testCoreSchema)

_, err := sm.MergeWithJsonProviderSchemas(nil)
Expand Down Expand Up @@ -57,6 +93,42 @@ func TestMergeWithJsonProviderSchemas_v012(t *testing.T) {
t.Fatal(err)
}

testCoreSchema := &schema.BodySchema{
Blocks: map[string]*schema.BlockSchema{
"provider": {
Labels: []*schema.LabelSchema{
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"alias": {Expr: schema.LiteralTypeOnly(cty.String), IsOptional: true},
},
},
},
"resource": {
Labels: []*schema.LabelSchema{
{Name: "type"},
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"count": {Expr: schema.LiteralTypeOnly(cty.Number), IsOptional: true},
},
},
},
"data": {
Labels: []*schema.LabelSchema{
{Name: "type"},
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"count": {Expr: schema.LiteralTypeOnly(cty.Number), IsOptional: true},
},
},
},
},
}
sm := NewSchemaMerger(testCoreSchema)
sm.SetParsedFiles(map[string]*hcl.File{
"test.tf": f,
Expand Down Expand Up @@ -96,6 +168,42 @@ func TestMergeWithJsonProviderSchemas_v013(t *testing.T) {
t.Fatal(err)
}

testCoreSchema := &schema.BodySchema{
Blocks: map[string]*schema.BlockSchema{
"provider": {
Labels: []*schema.LabelSchema{
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"alias": {Expr: schema.LiteralTypeOnly(cty.String), IsOptional: true},
},
},
},
"resource": {
Labels: []*schema.LabelSchema{
{Name: "type"},
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"count": {Expr: schema.LiteralTypeOnly(cty.Number), IsOptional: true},
},
},
},
"data": {
Labels: []*schema.LabelSchema{
{Name: "type"},
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"count": {Expr: schema.LiteralTypeOnly(cty.Number), IsOptional: true},
},
},
},
},
}
sm := NewSchemaMerger(testCoreSchema)
sm.SetParsedFiles(map[string]*hcl.File{
"test.tf": f,
Expand All @@ -114,40 +222,3 @@ func TestMergeWithJsonProviderSchemas_v013(t *testing.T) {
t.Fatalf("schema differs: %s", diff)
}
}

var testCoreSchema = &schema.BodySchema{
Blocks: map[string]*schema.BlockSchema{
"provider": {
Labels: []*schema.LabelSchema{
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"alias": {Expr: schema.LiteralTypeOnly(cty.String), IsOptional: true},
},
},
},
"resource": {
Labels: []*schema.LabelSchema{
{Name: "type"},
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"count": {Expr: schema.LiteralTypeOnly(cty.Number), IsOptional: true},
},
},
},
"data": {
Labels: []*schema.LabelSchema{
{Name: "type"},
{Name: "name"},
},
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"count": {Expr: schema.LiteralTypeOnly(cty.Number), IsOptional: true},
},
},
},
},
}
Loading

0 comments on commit a8c0201

Please sign in to comment.