configs: parse the "providers" map for module calls
This was accidentally missed on the first pass of module call decoding. As before, this is a map from child provider config address to parent provider config address, allowing the set of providers to be projected in arbitrary ways into a child module.
This commit is contained in:
parent
c6598a3f86
commit
b6fdd0446e
|
@ -1,6 +1,8 @@
|
|||
package configs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/hcl2/gohcl"
|
||||
"github.com/hashicorp/hcl2/hcl"
|
||||
"github.com/hashicorp/hcl2/hcl/hclsyntax"
|
||||
|
@ -21,6 +23,8 @@ type ModuleCall struct {
|
|||
Count hcl.Expression
|
||||
ForEach hcl.Expression
|
||||
|
||||
Providers []PassedProviderConfig
|
||||
|
||||
DependsOn []hcl.Traversal
|
||||
|
||||
DeclRange hcl.Range
|
||||
|
@ -76,9 +80,49 @@ func decodeModuleBlock(block *hcl.Block, override bool) (*ModuleCall, hcl.Diagno
|
|||
mc.DependsOn = append(mc.DependsOn, deps...)
|
||||
}
|
||||
|
||||
if attr, exists := content.Attributes["providers"]; exists {
|
||||
seen := make(map[string]hcl.Range)
|
||||
pairs, pDiags := hcl.ExprMap(attr.Expr)
|
||||
diags = append(diags, pDiags...)
|
||||
for _, pair := range pairs {
|
||||
key, keyDiags := decodeProviderConfigRef(pair.Key, "providers")
|
||||
diags = append(diags, keyDiags...)
|
||||
value, valueDiags := decodeProviderConfigRef(pair.Value, "providers")
|
||||
diags = append(diags, valueDiags...)
|
||||
if keyDiags.HasErrors() || valueDiags.HasErrors() {
|
||||
continue
|
||||
}
|
||||
|
||||
matchKey := key.String()
|
||||
if prev, exists := seen[matchKey]; exists {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate provider address",
|
||||
Detail: fmt.Sprintf("A provider configuration was already passed to %s at %s. Each child provider configuration can be assigned only once.", matchKey, prev),
|
||||
Subject: pair.Value.Range().Ptr(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
rng := hcl.RangeBetween(pair.Key.Range(), pair.Value.Range())
|
||||
seen[matchKey] = rng
|
||||
mc.Providers = append(mc.Providers, PassedProviderConfig{
|
||||
InChild: key,
|
||||
InParent: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return mc, diags
|
||||
}
|
||||
|
||||
// PassedProviderConfig represents a provider config explicitly passed down to
|
||||
// a child module, possibly giving it a new local address in the process.
|
||||
type PassedProviderConfig struct {
|
||||
InChild *ProviderConfigRef
|
||||
InParent *ProviderConfigRef
|
||||
}
|
||||
|
||||
var moduleBlockSchema = &hcl.BodySchema{
|
||||
Attributes: []hcl.AttributeSchema{
|
||||
{
|
||||
|
@ -97,5 +141,8 @@ var moduleBlockSchema = &hcl.BodySchema{
|
|||
{
|
||||
Name: "depends_on",
|
||||
},
|
||||
{
|
||||
Name: "providers",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
package configs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/go-test/deep"
|
||||
"github.com/hashicorp/hcl2/hcl"
|
||||
)
|
||||
|
||||
func TestLoadModuleCall(t *testing.T) {
|
||||
src, err := ioutil.ReadFile("test-fixtures/valid-files/module-calls.tf")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
parser := testParser(map[string]string{
|
||||
"module-calls.tf": string(src),
|
||||
})
|
||||
|
||||
file, diags := parser.LoadConfigFile("module-calls.tf")
|
||||
if len(diags) != 0 {
|
||||
t.Errorf("Wrong number of diagnostics %d; want 0", len(diags))
|
||||
for _, diag := range diags {
|
||||
t.Logf("- %s", diag)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
gotModules := file.ModuleCalls
|
||||
wantModules := []*ModuleCall{
|
||||
{
|
||||
Name: "foo",
|
||||
SourceAddr: "./foo",
|
||||
SourceSet: true,
|
||||
SourceAddrRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 3, Column: 12, Byte: 27},
|
||||
End: hcl.Pos{Line: 3, Column: 19, Byte: 34},
|
||||
},
|
||||
DeclRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 2, Column: 1, Byte: 1},
|
||||
End: hcl.Pos{Line: 2, Column: 13, Byte: 13},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
SourceAddr: "hashicorp/bar/aws",
|
||||
SourceSet: true,
|
||||
SourceAddrRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 8, Column: 12, Byte: 113},
|
||||
End: hcl.Pos{Line: 8, Column: 31, Byte: 132},
|
||||
},
|
||||
DeclRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 7, Column: 1, Byte: 87},
|
||||
End: hcl.Pos{Line: 7, Column: 13, Byte: 99},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
SourceAddr: "git::https://example.com/",
|
||||
SourceSet: true,
|
||||
SourceAddrRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 15, Column: 12, Byte: 193},
|
||||
End: hcl.Pos{Line: 15, Column: 39, Byte: 220},
|
||||
},
|
||||
DependsOn: []hcl.Traversal{
|
||||
{
|
||||
hcl.TraverseRoot{
|
||||
Name: "module",
|
||||
SrcRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 23, Column: 5, Byte: 295},
|
||||
End: hcl.Pos{Line: 23, Column: 11, Byte: 301},
|
||||
},
|
||||
},
|
||||
hcl.TraverseAttr{
|
||||
Name: "bar",
|
||||
SrcRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 23, Column: 11, Byte: 301},
|
||||
End: hcl.Pos{Line: 23, Column: 15, Byte: 305},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Providers: []PassedProviderConfig{
|
||||
{
|
||||
InChild: &ProviderConfigRef{
|
||||
Name: "aws",
|
||||
NameRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 27, Column: 5, Byte: 332},
|
||||
End: hcl.Pos{Line: 27, Column: 8, Byte: 335},
|
||||
},
|
||||
},
|
||||
InParent: &ProviderConfigRef{
|
||||
Name: "aws",
|
||||
NameRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 27, Column: 11, Byte: 338},
|
||||
End: hcl.Pos{Line: 27, Column: 14, Byte: 341},
|
||||
},
|
||||
Alias: "foo",
|
||||
AliasRange: &hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 27, Column: 14, Byte: 341},
|
||||
End: hcl.Pos{Line: 27, Column: 18, Byte: 345},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DeclRange: hcl.Range{
|
||||
Filename: "module-calls.tf",
|
||||
Start: hcl.Pos{Line: 14, Column: 1, Byte: 167},
|
||||
End: hcl.Pos{Line: 14, Column: 13, Byte: 179},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// We'll hide all of the bodies/exprs since we're treating them as opaque
|
||||
// here anyway... the point of this test is to ensure we handle everything
|
||||
// else properly.
|
||||
for _, m := range gotModules {
|
||||
m.Config = nil
|
||||
m.Count = nil
|
||||
m.ForEach = nil
|
||||
}
|
||||
|
||||
for _, problem := range deep.Equal(gotModules, wantModules) {
|
||||
t.Error(problem)
|
||||
}
|
||||
}
|
|
@ -114,7 +114,7 @@ func decodeResourceBlock(block *hcl.Block) (*Resource, hcl.Diagnostics) {
|
|||
|
||||
if attr, exists := content.Attributes["provider"]; exists {
|
||||
var providerDiags hcl.Diagnostics
|
||||
r.ProviderConfigRef, providerDiags = decodeProviderConfigRef(attr)
|
||||
r.ProviderConfigRef, providerDiags = decodeProviderConfigRef(attr.Expr, "provider")
|
||||
diags = append(diags, providerDiags...)
|
||||
}
|
||||
|
||||
|
@ -290,7 +290,7 @@ func decodeDataBlock(block *hcl.Block) (*Resource, hcl.Diagnostics) {
|
|||
|
||||
if attr, exists := content.Attributes["provider"]; exists {
|
||||
var providerDiags hcl.Diagnostics
|
||||
r.ProviderConfigRef, providerDiags = decodeProviderConfigRef(attr)
|
||||
r.ProviderConfigRef, providerDiags = decodeProviderConfigRef(attr.Expr, "provider")
|
||||
diags = append(diags, providerDiags...)
|
||||
}
|
||||
|
||||
|
@ -324,10 +324,11 @@ type ProviderConfigRef struct {
|
|||
AliasRange *hcl.Range // nil if alias not set
|
||||
}
|
||||
|
||||
func decodeProviderConfigRef(attr *hcl.Attribute) (*ProviderConfigRef, hcl.Diagnostics) {
|
||||
func decodeProviderConfigRef(expr hcl.Expression, argName string) (*ProviderConfigRef, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
expr, shimDiags := shimTraversalInString(attr.Expr, false)
|
||||
var shimDiags hcl.Diagnostics
|
||||
expr, shimDiags = shimTraversalInString(expr, false)
|
||||
diags = append(diags, shimDiags...)
|
||||
|
||||
traversal, travDiags := hcl.AbsTraversalForExpr(expr)
|
||||
|
@ -345,7 +346,7 @@ func decodeProviderConfigRef(attr *hcl.Attribute) (*ProviderConfigRef, hcl.Diagn
|
|||
// showing that usage, so we'll sniff for that situation here and
|
||||
// produce a specialized error message for it to help users find
|
||||
// the new correct form.
|
||||
if exprIsNativeQuotedString(attr.Expr) {
|
||||
if exprIsNativeQuotedString(expr) {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid provider configuration reference",
|
||||
|
@ -358,7 +359,7 @@ func decodeProviderConfigRef(attr *hcl.Attribute) (*ProviderConfigRef, hcl.Diagn
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid provider configuration reference",
|
||||
Detail: fmt.Sprintf("The %s argument requires a provider type name, optionally followed by a period and then a configuration alias.", attr.Name),
|
||||
Detail: fmt.Sprintf("The %s argument requires a provider type name, optionally followed by a period and then a configuration alias.", argName),
|
||||
Subject: expr.Range().Ptr(),
|
||||
})
|
||||
return nil, diags
|
||||
|
|
|
@ -22,5 +22,8 @@ module "baz" {
|
|||
depends_on = [
|
||||
module.bar,
|
||||
]
|
||||
}
|
||||
|
||||
providers = {
|
||||
aws = aws.foo
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue