From 6ae4677cab0945e21cdb7ff400f327348caaf5e1 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Thu, 11 Mar 2021 14:15:37 +0000 Subject: [PATCH] Expose configuration_aliases from required_providers --- go.mod | 5 +- go.sum | 27 ++++-- tfconfig/provider_ref.go | 97 ++++++++++++++++++- .../provider-aliases-json.out.json | 27 ++++++ .../provider-aliases-json.out.md | 10 ++ .../provider-aliases-json.tf.json | 35 +++++++ .../provider-aliases.out.json | 6 +- 7 files changed, 191 insertions(+), 16 deletions(-) create mode 100644 tfconfig/testdata/provider-aliases-json/provider-aliases-json.out.json create mode 100644 tfconfig/testdata/provider-aliases-json/provider-aliases-json.out.md create mode 100644 tfconfig/testdata/provider-aliases-json/provider-aliases-json.tf.json diff --git a/go.mod b/go.mod index 5cbcfbc..a25ee7e 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,13 @@ module github.com/hashicorp/terraform-config-inspect require ( github.com/agext/levenshtein v1.2.2 // indirect github.com/go-test/deep v1.0.3 - github.com/google/go-cmp v0.3.0 // indirect github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f - github.com/hashicorp/hcl/v2 v2.0.0 + github.com/hashicorp/hcl/v2 v2.9.1 github.com/kylelemons/godebug v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/spf13/pflag v1.0.3 github.com/stretchr/testify v1.3.0 // indirect - github.com/zclconf/go-cty v1.1.0 + github.com/zclconf/go-cty v1.8.0 ) go 1.13 diff --git a/go.sum b/go.sum index 5e519d8..291e72d 100644 --- a/go.sum +++ b/go.sum @@ -5,20 +5,22 @@ github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 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/v2 v2.0.0 h1:efQznTz+ydmQXq3BOnRa3AXzvCeTq1P4dKj/z5GLlY8= -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= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -46,12 +48,18 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/zclconf/go-cty v1.1.0 h1:uJwc9HiBOCpoKIObTQaLR+tsEXx1HBHnOsOOpcdhZgw= -github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= +github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= +github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA= +github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -60,6 +68,9 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/tfconfig/provider_ref.go b/tfconfig/provider_ref.go index c173114..a8a956e 100644 --- a/tfconfig/provider_ref.go +++ b/tfconfig/provider_ref.go @@ -17,8 +17,9 @@ type ProviderRef struct { } type ProviderRequirement struct { - Source string `json:"source,omitempty"` - VersionConstraints []string `json:"version_constraints,omitempty"` + Source string `json:"source,omitempty"` + VersionConstraints []string `json:"version_constraints,omitempty"` + ConfigurationAliases []ProviderRef `json:"aliases,omitempty"` } func decodeRequiredProvidersBlock(block *hcl.Block) (map[string]*ProviderRequirement, hcl.Diagnostics) { @@ -85,8 +86,8 @@ func decodeRequiredProvidersBlock(block *hcl.Block) (map[string]*ProviderRequire } case "source": - source, err := kv.Value.Value(nil) - if err != nil || !source.Type().Equals(cty.String) { + source, valDiags := kv.Value.Value(nil) + if valDiags.HasErrors() || !source.Type().Equals(cty.String) { diags = append(diags, &hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Unsuitable value type", @@ -99,6 +100,13 @@ func decodeRequiredProvidersBlock(block *hcl.Block) (map[string]*ProviderRequire if !source.IsNull() { pr.Source = source.AsString() } + case "configuration_aliases": + aliases, valDiags := decodeConfigurationAliases(name, kv.Value) + if valDiags.HasErrors() { + diags = append(diags, valDiags...) + continue + } + pr.ConfigurationAliases = append(pr.ConfigurationAliases, aliases...) } reqs[name] = &pr @@ -107,3 +115,84 @@ func decodeRequiredProvidersBlock(block *hcl.Block) (map[string]*ProviderRequire return reqs, diags } + +func decodeConfigurationAliases(localName string, value hcl.Expression) ([]ProviderRef, hcl.Diagnostics) { + aliases := make([]ProviderRef, 0) + var diags hcl.Diagnostics + + exprs, listDiags := hcl.ExprList(value) + if listDiags.HasErrors() { + diags = append(diags, listDiags...) + return aliases, diags + } + + for _, expr := range exprs { + traversal, travDiags := hcl.AbsTraversalForExpr(expr) + if travDiags.HasErrors() { + diags = append(diags, travDiags...) + continue + } + + ref, cfgDiags := parseProviderRef(traversal) + if cfgDiags.HasErrors() { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid configuration_aliases value", + Detail: `Configuration aliases can only contain references to local provider configuration names in the format of provider.alias`, + Subject: value.Range().Ptr(), + }) + continue + } + + if ref.Name != localName { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid configuration_aliases value", + Detail: fmt.Sprintf(`Configuration aliases must be prefixed with the provider name. Expected %q, but found %q.`, localName, ref.Name), + Subject: value.Range().Ptr(), + }) + continue + } + + aliases = append(aliases, ref) + } + + return aliases, diags +} + +func parseProviderRef(traversal hcl.Traversal) (ProviderRef, hcl.Diagnostics) { + var diags hcl.Diagnostics + ret := ProviderRef{ + Name: traversal.RootName(), + } + + if len(traversal) < 2 { + // Just a local name, then. + return ret, diags + } + + aliasStep := traversal[1] + switch ts := aliasStep.(type) { + case hcl.TraverseAttr: + ret.Alias = ts.Name + return ret, diags + default: + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid provider configuration address", + Detail: "The provider type name must either stand alone or be followed by an alias name separated with a dot.", + Subject: aliasStep.SourceRange().Ptr(), + }) + } + + if len(traversal) > 2 { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid provider configuration address", + Detail: "Extraneous extra operators after provider configuration address.", + Subject: traversal[2:].SourceRange().Ptr(), + }) + } + + return ret, diags +} diff --git a/tfconfig/testdata/provider-aliases-json/provider-aliases-json.out.json b/tfconfig/testdata/provider-aliases-json/provider-aliases-json.out.json new file mode 100644 index 0000000..3c8be0c --- /dev/null +++ b/tfconfig/testdata/provider-aliases-json/provider-aliases-json.out.json @@ -0,0 +1,27 @@ +{ + "path": "testdata/provider-aliases-json", + "variables": {}, + "outputs": {}, + "required_providers": { + "bar": {}, + "baz": {}, + "bleep": { + "aliases": [ + {"name": "bleep", "alias": "bloop"} + ] + }, + "empty": {}, + "foo": {} + }, + "provider_configs": { + "bar.yellow": {"name": "bar", "alias": "yellow"}, + "baz": {"name": "baz"}, + "empty": {"name": "empty"}, + "bar": {"name": "bar"}, + "foo.blue": {"name": "foo", "alias": "blue"}, + "foo.red": {"name": "foo", "alias": "red"} + }, + "managed_resources": {}, + "data_resources": {}, + "module_calls": {} +} diff --git a/tfconfig/testdata/provider-aliases-json/provider-aliases-json.out.md b/tfconfig/testdata/provider-aliases-json/provider-aliases-json.out.md new file mode 100644 index 0000000..7b99e9f --- /dev/null +++ b/tfconfig/testdata/provider-aliases-json/provider-aliases-json.out.md @@ -0,0 +1,10 @@ + +# Module `testdata/provider-aliases-json` + +Provider Requirements: +* **bar:** (any version) +* **baz:** (any version) +* **bleep:** (any version) +* **empty:** (any version) +* **foo:** (any version) + diff --git a/tfconfig/testdata/provider-aliases-json/provider-aliases-json.tf.json b/tfconfig/testdata/provider-aliases-json/provider-aliases-json.tf.json new file mode 100644 index 0000000..81d5322 --- /dev/null +++ b/tfconfig/testdata/provider-aliases-json/provider-aliases-json.tf.json @@ -0,0 +1,35 @@ +{ + "terraform": { + "required_providers": { + "bleep": { + "configuration_aliases": [ + "bleep.bloop" + ] + } + } + }, + "provider": { + "foo": [ + { + "alias": "blue" + }, + { + "alias": "red" + } + ], + "bar": [ + {}, + { + "alias": "yellow" + } + ], + "baz": [ + {} + ], + "empty": [ + { + "alias": "" + } + ] + } +} diff --git a/tfconfig/testdata/provider-aliases/provider-aliases.out.json b/tfconfig/testdata/provider-aliases/provider-aliases.out.json index 7446e68..6cceac4 100644 --- a/tfconfig/testdata/provider-aliases/provider-aliases.out.json +++ b/tfconfig/testdata/provider-aliases/provider-aliases.out.json @@ -5,7 +5,11 @@ "required_providers": { "bar": {}, "baz": {}, - "bleep": {}, + "bleep": { + "aliases": [ + {"name": "bleep", "alias": "bloop"} + ] + }, "empty": {}, "foo": {} },