mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
parent
1155a3f711
commit
e802b23200
@ -16,7 +16,6 @@ ENHANCEMENTS:
|
||||
* Added a help target to the Makefile. ([#1925](https://github.com/opentofu/opentofu/pull/1925))
|
||||
* Added a simplified Build Process with a Makefile Target ([#1926](https://github.com/opentofu/opentofu/issues/1926))
|
||||
* Ensures that the Makefile adheres to POSIX standards ([#1811](https://github.com/opentofu/opentofu/pull/1928))
|
||||
* Added for-each support to providers ([#300](https://github.com/opentofu/opentofu/issues/300))
|
||||
* Added consolidate warnings and errors flags ([#1894](https://github.com/opentofu/opentofu/pull/1894))
|
||||
|
||||
BUG FIXES:
|
||||
|
@ -950,6 +950,7 @@ func (c *Config) transformProviderConfigsForTest(run *TestRun, file *TestFile) (
|
||||
// for by this run block.
|
||||
|
||||
for _, ref := range run.Providers {
|
||||
|
||||
testProvider, ok := file.getTestProviderOrMock(ref.InParent.String())
|
||||
if !ok {
|
||||
// Then this reference was invalid as we didn't have the
|
||||
@ -965,16 +966,15 @@ func (c *Config) transformProviderConfigsForTest(run *TestRun, file *TestFile) (
|
||||
}
|
||||
|
||||
next[ref.InChild.String()] = &Provider{
|
||||
ProviderCommon: ProviderCommon{
|
||||
Name: ref.InChild.Name,
|
||||
NameRange: ref.InChild.NameRange,
|
||||
Version: testProvider.Version,
|
||||
Config: testProvider.Config,
|
||||
DeclRange: testProvider.DeclRange,
|
||||
IsMocked: testProvider.IsMocked,
|
||||
MockResources: testProvider.MockResources,
|
||||
},
|
||||
Alias: ref.InChild.Alias,
|
||||
Name: ref.InChild.Name,
|
||||
NameRange: ref.InChild.NameRange,
|
||||
Alias: ref.InChild.Alias,
|
||||
AliasRange: ref.InChild.AliasRange,
|
||||
Version: testProvider.Version,
|
||||
Config: testProvider.Config,
|
||||
DeclRange: testProvider.DeclRange,
|
||||
IsMocked: testProvider.IsMocked,
|
||||
MockResources: testProvider.MockResources,
|
||||
}
|
||||
|
||||
}
|
||||
@ -986,14 +986,13 @@ func (c *Config) transformProviderConfigsForTest(run *TestRun, file *TestFile) (
|
||||
}
|
||||
for _, mp := range file.MockProviders {
|
||||
next[mp.moduleUniqueKey()] = &Provider{
|
||||
ProviderCommon: ProviderCommon{
|
||||
Name: mp.Name,
|
||||
NameRange: mp.NameRange,
|
||||
DeclRange: mp.DeclRange,
|
||||
IsMocked: true,
|
||||
MockResources: mp.MockResources,
|
||||
},
|
||||
Alias: mp.Alias,
|
||||
Name: mp.Name,
|
||||
NameRange: mp.NameRange,
|
||||
Alias: mp.Alias,
|
||||
AliasRange: mp.AliasRange,
|
||||
DeclRange: mp.DeclRange,
|
||||
IsMocked: true,
|
||||
MockResources: mp.MockResources,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -628,9 +628,7 @@ func TestTransformForTest(t *testing.T) {
|
||||
}
|
||||
|
||||
provider := &Provider{
|
||||
ProviderCommon: ProviderCommon{
|
||||
Config: file.Body,
|
||||
},
|
||||
Config: file.Body,
|
||||
}
|
||||
|
||||
parts := strings.Split(key, ".")
|
||||
|
@ -70,8 +70,8 @@ type Module struct {
|
||||
|
||||
// GetProviderConfig uses name and alias to find the respective Provider configuration.
|
||||
func (m *Module) GetProviderConfig(name, alias string) (*Provider, bool) {
|
||||
tp := &Provider{ProviderCommon: ProviderCommon{Name: name}, Alias: alias}
|
||||
p, ok := m.ProviderConfigs[tp.Addr().StringCompact()]
|
||||
tp := &Provider{Name: name, Alias: alias}
|
||||
p, ok := m.ProviderConfigs[tp.moduleUniqueKey()]
|
||||
return p, ok
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ type File struct {
|
||||
|
||||
Backends []*Backend
|
||||
CloudConfigs []*CloudConfig
|
||||
ProviderConfigs []*ProviderBlock
|
||||
ProviderConfigs []*Provider
|
||||
ProviderMetas []*ProviderMeta
|
||||
RequiredProviders []*RequiredProviders
|
||||
Encryptions []*config.EncryptionConfig
|
||||
@ -244,17 +244,6 @@ func NewModule(primaryFiles, overrideFiles []*File, call StaticModuleCall, sourc
|
||||
mod.CloudConfig.eval = mod.StaticEvaluator
|
||||
}
|
||||
|
||||
// Process all providers with the static context
|
||||
for _, file := range primaryFiles {
|
||||
fileDiags := mod.appendFileProviders(file)
|
||||
diags = append(diags, fileDiags...)
|
||||
}
|
||||
|
||||
for _, file := range overrideFiles {
|
||||
fileDiags := mod.mergeFileProviders(file)
|
||||
diags = append(diags, fileDiags...)
|
||||
}
|
||||
|
||||
// Process all module calls now that we have the static context
|
||||
for _, mc := range mod.ModuleCalls {
|
||||
mDiags := mc.decodeStaticFields(mod.StaticEvaluator)
|
||||
@ -328,6 +317,29 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics {
|
||||
})
|
||||
}
|
||||
|
||||
for _, pc := range file.ProviderConfigs {
|
||||
key := pc.moduleUniqueKey()
|
||||
if existing, exists := m.ProviderConfigs[key]; exists {
|
||||
if existing.Alias == "" {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate provider configuration",
|
||||
Detail: fmt.Sprintf("A default (non-aliased) provider configuration for %q was already given at %s. If multiple configurations are required, set the \"alias\" argument for alternative configurations.", existing.Name, existing.DeclRange),
|
||||
Subject: &pc.DeclRange,
|
||||
})
|
||||
} else {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate provider configuration",
|
||||
Detail: fmt.Sprintf("A provider configuration for %q with alias %q was already given at %s. Each configuration for the same provider must have a distinct alias.", existing.Name, existing.Alias, existing.DeclRange),
|
||||
Subject: &pc.DeclRange,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
m.ProviderConfigs[key] = pc
|
||||
}
|
||||
|
||||
for _, pm := range file.ProviderMetas {
|
||||
provider := m.ProviderForLocalConfig(addrs.LocalProviderConfig{LocalName: pm.Provider})
|
||||
if existing, exists := m.ProviderMetas[provider]; exists {
|
||||
@ -578,6 +590,38 @@ func (m *Module) mergeFile(file *File) hcl.Diagnostics {
|
||||
}
|
||||
}
|
||||
|
||||
for _, pc := range file.ProviderConfigs {
|
||||
key := pc.moduleUniqueKey()
|
||||
existing, exists := m.ProviderConfigs[key]
|
||||
if pc.Alias == "" {
|
||||
// We allow overriding a non-existing _default_ provider configuration
|
||||
// because the user model is that an absent provider configuration
|
||||
// implies an empty provider configuration, which is what the user
|
||||
// is therefore overriding here.
|
||||
if exists {
|
||||
mergeDiags := existing.merge(pc)
|
||||
diags = append(diags, mergeDiags...)
|
||||
} else {
|
||||
m.ProviderConfigs[key] = pc
|
||||
}
|
||||
} else {
|
||||
// For aliased providers, there must be a base configuration to
|
||||
// override. This allows us to detect and report alias typos
|
||||
// that might otherwise cause the override to not apply.
|
||||
if !exists {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing base provider configuration for override",
|
||||
Detail: fmt.Sprintf("There is no %s provider configuration with the alias %q. An override file can only override an aliased provider configuration that was already defined in a primary configuration file.", pc.Name, pc.Alias),
|
||||
Subject: &pc.DeclRange,
|
||||
})
|
||||
continue
|
||||
}
|
||||
mergeDiags := existing.merge(pc)
|
||||
diags = append(diags, mergeDiags...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(file.Encryptions) != 0 {
|
||||
switch len(file.Encryptions) {
|
||||
case 1:
|
||||
@ -716,85 +760,6 @@ func (m *Module) mergeFile(file *File) hcl.Diagnostics {
|
||||
return diags
|
||||
}
|
||||
|
||||
func (m *Module) appendFileProviders(file *File) hcl.Diagnostics {
|
||||
var diags hcl.Diagnostics
|
||||
for _, pci := range file.ProviderConfigs {
|
||||
pcs, decodeDiags := pci.decodeStaticFields(m.StaticEvaluator)
|
||||
diags = append(diags, decodeDiags...)
|
||||
if decodeDiags.HasErrors() {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, pc := range pcs {
|
||||
key := pc.Addr().StringCompact()
|
||||
if existing, exists := m.ProviderConfigs[key]; exists {
|
||||
if existing.Alias == "" {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate provider configuration",
|
||||
Detail: fmt.Sprintf("A default (non-aliased) provider configuration for %q was already given at %s. If multiple configurations are required, set the \"alias\" argument for alternative configurations.", existing.Name, existing.DeclRange),
|
||||
Subject: &pc.DeclRange,
|
||||
})
|
||||
} else {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate provider configuration",
|
||||
Detail: fmt.Sprintf("A provider configuration for %q with alias %q was already given at %s. Each configuration for the same provider must have a distinct alias.", existing.Name, existing.Alias, existing.DeclRange),
|
||||
Subject: &pc.DeclRange,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
m.ProviderConfigs[key] = pc
|
||||
}
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
func (m *Module) mergeFileProviders(file *File) hcl.Diagnostics {
|
||||
var diags hcl.Diagnostics
|
||||
for _, pci := range file.ProviderConfigs {
|
||||
pcs, decodeDiags := pci.decodeStaticFields(m.StaticEvaluator)
|
||||
diags = append(diags, decodeDiags...)
|
||||
if decodeDiags.HasErrors() {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, pc := range pcs {
|
||||
key := pc.Addr().StringCompact()
|
||||
existing, exists := m.ProviderConfigs[key]
|
||||
if pc.Alias == "" {
|
||||
// We allow overriding a non-existing _default_ provider configuration
|
||||
// because the user model is that an absent provider configuration
|
||||
// implies an empty provider configuration, which is what the user
|
||||
// is therefore overriding here.
|
||||
if exists {
|
||||
mergeDiags := existing.merge(pc)
|
||||
diags = append(diags, mergeDiags...)
|
||||
} else {
|
||||
m.ProviderConfigs[key] = pc
|
||||
}
|
||||
} else {
|
||||
// For aliased providers, there must be a base configuration to
|
||||
// override. This allows us to detect and report alias typos
|
||||
// that might otherwise cause the override to not apply.
|
||||
if !exists {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing base provider configuration for override",
|
||||
Detail: fmt.Sprintf("There is no %s provider configuration with the alias %q. An override file can only override an aliased provider configuration that was already defined in a primary configuration file.", pc.Name, pc.Alias),
|
||||
Subject: &pc.DeclRange,
|
||||
})
|
||||
continue
|
||||
}
|
||||
mergeDiags := existing.merge(pc)
|
||||
diags = append(diags, mergeDiags...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
// gatherProviderLocalNames is a helper function that populatesA a map of
|
||||
// provider FQNs -> provider local names. This information is useful for
|
||||
// user-facing output, which should include both the FQN and LocalName. It must
|
||||
|
@ -13,15 +13,17 @@ import (
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/addrs"
|
||||
"github.com/opentofu/opentofu/internal/instances"
|
||||
"github.com/opentofu/opentofu/internal/lang/evalchecks"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
)
|
||||
|
||||
// ProviderCommon is the common fields between a Provider Block and a Provider
|
||||
type ProviderCommon struct {
|
||||
Name string
|
||||
NameRange hcl.Range
|
||||
// Provider represents a "provider" block in a module or file. A provider
|
||||
// block is a provider configuration, and there can be zero or more
|
||||
// configurations for each actual provider.
|
||||
type Provider struct {
|
||||
Name string
|
||||
NameRange hcl.Range
|
||||
Alias string
|
||||
AliasRange *hcl.Range // nil if no alias set
|
||||
|
||||
Version VersionConstraint
|
||||
|
||||
@ -42,105 +44,7 @@ type ProviderCommon struct {
|
||||
MockResources []*MockResource
|
||||
}
|
||||
|
||||
// ProviderBlock represents a "provider" block in a module or file. A provider
|
||||
// block is a provider configuration
|
||||
type ProviderBlock struct {
|
||||
ProviderCommon
|
||||
AliasExpr hcl.Expression // nil if no alias set
|
||||
AliasRange *hcl.Range // nil if no alias set
|
||||
ForEach hcl.Expression
|
||||
}
|
||||
|
||||
// Provider represents an instance of a "provider" block. Created after
|
||||
// the exvaluation of a provider block containing the specific data
|
||||
// for each instance derived from the evaluation
|
||||
type Provider struct {
|
||||
ProviderCommon
|
||||
Alias string
|
||||
InstanceData instances.RepetitionData
|
||||
}
|
||||
|
||||
// ParseProviderConfigCompact parses the given absolute traversal as a relative
|
||||
// provider address in compact form. The following are examples of traversals
|
||||
// that can be successfully parsed as compact relative provider configuration
|
||||
// addresses:
|
||||
//
|
||||
// - aws
|
||||
// - aws.foo
|
||||
//
|
||||
// This function will panic if given a relative traversal.
|
||||
//
|
||||
// If the returned diagnostics contains errors then the result value is invalid
|
||||
// and must not be used.
|
||||
func ParseProviderConfigCompact(traversal hcl.Traversal) (addrs.LocalProviderConfig, tfdiags.Diagnostics) {
|
||||
// added as a const to keep the linter happy
|
||||
const providerAddrMaxTraversal = 2
|
||||
var diags tfdiags.Diagnostics
|
||||
ret := addrs.LocalProviderConfig{
|
||||
LocalName: traversal.RootName(),
|
||||
}
|
||||
|
||||
if len(traversal) < providerAddrMaxTraversal {
|
||||
// Just a type 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) > providerAddrMaxTraversal {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid provider configuration address",
|
||||
Detail: "Extraneous extra operators after provider configuration address.",
|
||||
Subject: traversal[providerAddrMaxTraversal:].SourceRange().Ptr(),
|
||||
})
|
||||
}
|
||||
|
||||
return ret, diags
|
||||
}
|
||||
|
||||
// ParseProviderConfigCompactStr is a helper wrapper around ParseProviderConfigCompact
|
||||
// that takes a string and parses it with the HCL native syntax traversal parser
|
||||
// before interpreting it.
|
||||
//
|
||||
// This should be used only in specialized situations since it will cause the
|
||||
// created references to not have any meaningful source location information.
|
||||
// If a reference string is coming from a source that should be identified in
|
||||
// error messages then the caller should instead parse it directly using a
|
||||
// suitable function from the HCL API and pass the traversal itself to
|
||||
// ParseProviderConfigCompact.
|
||||
//
|
||||
// Error diagnostics are returned if either the parsing fails or the analysis
|
||||
// of the traversal fails. There is no way for the caller to distinguish the
|
||||
// two kinds of diagnostics programmatically. If error diagnostics are returned
|
||||
// then the returned address is invalid.
|
||||
func ParseProviderConfigCompactStr(str string) (addrs.LocalProviderConfig, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
|
||||
diags = diags.Append(parseDiags)
|
||||
if parseDiags.HasErrors() {
|
||||
return addrs.LocalProviderConfig{}, diags
|
||||
}
|
||||
|
||||
addr, addrDiags := ParseProviderConfigCompact(traversal)
|
||||
diags = diags.Append(addrDiags)
|
||||
return addr, diags
|
||||
}
|
||||
|
||||
func decodeProviderBlock(block *hcl.Block) (*ProviderBlock, hcl.Diagnostics) {
|
||||
func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
content, config, moreDiags := block.Body.PartialContent(providerBlockSchema)
|
||||
@ -158,31 +62,25 @@ func decodeProviderBlock(block *hcl.Block) (*ProviderBlock, hcl.Diagnostics) {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
provider := &ProviderBlock{
|
||||
ProviderCommon: ProviderCommon{
|
||||
Name: name,
|
||||
NameRange: block.LabelRanges[0],
|
||||
Config: config,
|
||||
DeclRange: block.DefRange,
|
||||
},
|
||||
provider := &Provider{
|
||||
Name: name,
|
||||
NameRange: block.LabelRanges[0],
|
||||
Config: config,
|
||||
DeclRange: block.DefRange,
|
||||
}
|
||||
|
||||
if attr, exists := content.Attributes["alias"]; exists {
|
||||
provider.AliasExpr = attr.Expr
|
||||
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &provider.Alias)
|
||||
diags = append(diags, valDiags...)
|
||||
provider.AliasRange = attr.Expr.Range().Ptr()
|
||||
}
|
||||
|
||||
if attr, exists := content.Attributes["for_each"]; exists {
|
||||
provider.ForEach = attr.Expr
|
||||
}
|
||||
|
||||
if provider.AliasExpr != nil && provider.ForEach != nil {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: `Invalid combination of "alias" and "for_each"`,
|
||||
Detail: `The "alias" and "for_each" arguments are mutually-exclusive, only one may be used.`,
|
||||
Subject: provider.AliasExpr.Range().Ptr(),
|
||||
})
|
||||
if !hclsyntax.ValidIdentifier(provider.Alias) {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid provider configuration alias",
|
||||
Detail: fmt.Sprintf("An alias must be a valid name. %s", badIdentifierDetail),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if attr, exists := content.Attributes["version"]; exists {
|
||||
@ -197,8 +95,17 @@ func decodeProviderBlock(block *hcl.Block) (*ProviderBlock, hcl.Diagnostics) {
|
||||
diags = append(diags, versionDiags...)
|
||||
}
|
||||
|
||||
reserveredDiags := checkReservedNames(content)
|
||||
diags = append(diags, reserveredDiags...)
|
||||
// Reserved attribute names
|
||||
for _, name := range []string{"count", "depends_on", "for_each", "source"} {
|
||||
if attr, exists := content.Attributes[name]; exists {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Reserved argument name in provider block",
|
||||
Detail: fmt.Sprintf("The provider argument name %q is reserved for use by OpenTofu in a future version.", name),
|
||||
Subject: &attr.NameRange,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var seenEscapeBlock *hcl.Block
|
||||
for _, block := range content.Blocks {
|
||||
@ -238,20 +145,122 @@ func decodeProviderBlock(block *hcl.Block) (*ProviderBlock, hcl.Diagnostics) {
|
||||
return provider, diags
|
||||
}
|
||||
|
||||
func checkReservedNames(content *hcl.BodyContent) hcl.Diagnostics {
|
||||
var diags hcl.Diagnostics
|
||||
// Reserved attribute names
|
||||
for _, name := range []string{"depends_on", "source", "count"} {
|
||||
if attr, exists := content.Attributes[name]; exists {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Reserved argument name in provider block",
|
||||
Detail: fmt.Sprintf("The provider argument name %q is reserved for use by OpenTofu in a future version.", name),
|
||||
Subject: &attr.NameRange,
|
||||
})
|
||||
}
|
||||
// Addr returns the address of the receiving provider configuration, relative
|
||||
// to its containing module.
|
||||
func (p *Provider) Addr() addrs.LocalProviderConfig {
|
||||
return addrs.LocalProviderConfig{
|
||||
LocalName: p.Name,
|
||||
Alias: p.Alias,
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
func (p *Provider) moduleUniqueKey() string {
|
||||
if p.Alias != "" {
|
||||
return fmt.Sprintf("%s.%s", p.Name, p.Alias)
|
||||
}
|
||||
return p.Name
|
||||
}
|
||||
|
||||
// ParseProviderConfigCompact parses the given absolute traversal as a relative
|
||||
// provider address in compact form. The following are examples of traversals
|
||||
// that can be successfully parsed as compact relative provider configuration
|
||||
// addresses:
|
||||
//
|
||||
// - aws
|
||||
// - aws.foo
|
||||
//
|
||||
// This function will panic if given a relative traversal.
|
||||
//
|
||||
// If the returned diagnostics contains errors then the result value is invalid
|
||||
// and must not be used.
|
||||
func ParseProviderConfigCompact(traversal hcl.Traversal) (addrs.LocalProviderConfig, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
ret := addrs.LocalProviderConfig{
|
||||
LocalName: traversal.RootName(),
|
||||
}
|
||||
|
||||
if len(traversal) < 2 {
|
||||
// Just a type 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
|
||||
}
|
||||
|
||||
// ParseProviderConfigCompactStr is a helper wrapper around ParseProviderConfigCompact
|
||||
// that takes a string and parses it with the HCL native syntax traversal parser
|
||||
// before interpreting it.
|
||||
//
|
||||
// This should be used only in specialized situations since it will cause the
|
||||
// created references to not have any meaningful source location information.
|
||||
// If a reference string is coming from a source that should be identified in
|
||||
// error messages then the caller should instead parse it directly using a
|
||||
// suitable function from the HCL API and pass the traversal itself to
|
||||
// ParseProviderConfigCompact.
|
||||
//
|
||||
// Error diagnostics are returned if either the parsing fails or the analysis
|
||||
// of the traversal fails. There is no way for the caller to distinguish the
|
||||
// two kinds of diagnostics programmatically. If error diagnostics are returned
|
||||
// then the returned address is invalid.
|
||||
func ParseProviderConfigCompactStr(str string) (addrs.LocalProviderConfig, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
|
||||
diags = diags.Append(parseDiags)
|
||||
if parseDiags.HasErrors() {
|
||||
return addrs.LocalProviderConfig{}, diags
|
||||
}
|
||||
|
||||
addr, addrDiags := ParseProviderConfigCompact(traversal)
|
||||
diags = diags.Append(addrDiags)
|
||||
return addr, diags
|
||||
}
|
||||
|
||||
var providerBlockSchema = &hcl.BodySchema{
|
||||
Attributes: []hcl.AttributeSchema{
|
||||
{
|
||||
Name: "alias",
|
||||
},
|
||||
{
|
||||
Name: "version",
|
||||
},
|
||||
|
||||
// Attribute names reserved for future expansion.
|
||||
{Name: "count"},
|
||||
{Name: "depends_on"},
|
||||
{Name: "for_each"},
|
||||
{Name: "source"},
|
||||
},
|
||||
Blocks: []hcl.BlockHeaderSchema{
|
||||
{Type: "_"}, // meta-argument escaping block
|
||||
|
||||
// The rest of these are reserved for future expansion.
|
||||
{Type: "lifecycle"},
|
||||
{Type: "locals"},
|
||||
},
|
||||
}
|
||||
|
||||
// checkProviderNameNormalized verifies that the given string is already
|
||||
@ -281,124 +290,3 @@ func checkProviderNameNormalized(name string, declrange hcl.Range) hcl.Diagnosti
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
// Addr returns the address of the receiving provider configuration, relative
|
||||
// to its containing module.
|
||||
func (p *Provider) Addr() addrs.LocalProviderConfig {
|
||||
return addrs.LocalProviderConfig{
|
||||
LocalName: p.Name,
|
||||
Alias: p.Alias,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ProviderBlock) decodeStaticFields(eval *StaticEvaluator) ([]*Provider, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
if p.ForEach != nil {
|
||||
return p.generateForEachProviders(eval)
|
||||
}
|
||||
|
||||
result := Provider{ProviderCommon: p.ProviderCommon}
|
||||
if p.AliasExpr != nil {
|
||||
if eval != nil {
|
||||
valDiags := eval.DecodeExpression(p.AliasExpr, StaticIdentifier{
|
||||
Module: eval.call.addr,
|
||||
Subject: fmt.Sprintf("provider.%s.alias", p.Name),
|
||||
DeclRange: p.AliasExpr.Range(),
|
||||
}, &result.Alias)
|
||||
diags = append(diags, valDiags...)
|
||||
} else {
|
||||
// Test files don't have a static context
|
||||
valDiags := gohcl.DecodeExpression(p.AliasExpr, nil, &result.Alias)
|
||||
diags = append(diags, valDiags...)
|
||||
}
|
||||
|
||||
if diags.HasErrors() {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
if !hclsyntax.ValidIdentifier(result.Alias) {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid provider configuration alias",
|
||||
Detail: fmt.Sprintf("Alias %q must be a valid name. %s", result.Alias, badIdentifierDetail),
|
||||
Subject: p.AliasExpr.Range().Ptr(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return []*Provider{&result}, diags
|
||||
}
|
||||
|
||||
func (p *ProviderBlock) generateForEachProviders(eval *StaticEvaluator) ([]*Provider, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
if eval == nil {
|
||||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Iteration not allowed in test files",
|
||||
Detail: "for_each was declared as a provider attribute in a test file",
|
||||
Subject: p.ForEach.Range().Ptr(),
|
||||
})
|
||||
}
|
||||
|
||||
forEachRefsFunc := func(refs []*addrs.Reference) (*hcl.EvalContext, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
evalContext, evalDiags := eval.EvalContext(StaticIdentifier{
|
||||
Module: eval.call.addr,
|
||||
Subject: fmt.Sprintf("provider.%s.for_each", p.Name),
|
||||
DeclRange: p.ForEach.Range(),
|
||||
}, refs)
|
||||
return evalContext, diags.Append(evalDiags)
|
||||
}
|
||||
|
||||
forVal, evalDiags := evalchecks.EvaluateForEachExpression(p.ForEach, forEachRefsFunc)
|
||||
diags = append(diags, evalDiags.ToHCL()...)
|
||||
if evalDiags.HasErrors() {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
var out []*Provider
|
||||
for k, v := range forVal {
|
||||
if !hclsyntax.ValidIdentifier(k) {
|
||||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid for_each key alias",
|
||||
Detail: fmt.Sprintf("Alias %q must be a valid name. %s", k, badIdentifierDetail),
|
||||
Subject: p.ForEach.Range().Ptr(),
|
||||
})
|
||||
}
|
||||
|
||||
out = append(out, &Provider{
|
||||
ProviderCommon: p.ProviderCommon,
|
||||
Alias: k,
|
||||
InstanceData: instances.RepetitionData{
|
||||
EachValue: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
return out, diags
|
||||
}
|
||||
|
||||
var providerBlockSchema = &hcl.BodySchema{ //nolint: gochecknoglobals // pre-existing code
|
||||
Attributes: []hcl.AttributeSchema{
|
||||
{
|
||||
Name: "alias",
|
||||
},
|
||||
{
|
||||
Name: "version",
|
||||
},
|
||||
{
|
||||
Name: "for_each",
|
||||
},
|
||||
|
||||
// Attribute names reserved for future expansion.
|
||||
{Name: "count"},
|
||||
{Name: "depends_on"},
|
||||
{Name: "source"},
|
||||
},
|
||||
Blocks: []hcl.BlockHeaderSchema{
|
||||
{Type: "_"}, // meta-argument escaping block
|
||||
|
||||
// The rest of these are reserved for future expansion.
|
||||
{Type: "lifecycle"},
|
||||
{Type: "locals"},
|
||||
},
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
// Copyright (c) The OpenTofu Authors
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) 2023 HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package configs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/addrs"
|
||||
)
|
||||
|
||||
const (
|
||||
providerTestName = "local"
|
||||
)
|
||||
|
||||
func TestNewModule_provider_foreach(t *testing.T) {
|
||||
mod, diags := testModuleFromDir("testdata/providers_foreach")
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Error())
|
||||
}
|
||||
|
||||
p := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "hashicorp", providerTestName)
|
||||
if name, exists := mod.ProviderLocalNames[p]; !exists {
|
||||
t.Fatal("provider FQN hashicorp/local not found")
|
||||
} else if name != providerTestName {
|
||||
t.Fatalf("provider localname mismatch: got %s, want %s", name, providerTestName)
|
||||
}
|
||||
|
||||
if len(mod.ProviderConfigs) != 3 {
|
||||
t.Fatalf("incorrect number of providers: got %d, expected: %d", len(mod.ProviderConfigs), 3)
|
||||
}
|
||||
|
||||
_, foundDev := mod.GetProviderConfig("foo-test", "dev")
|
||||
if !foundDev {
|
||||
t.Fatal("unable to find dev provider")
|
||||
}
|
||||
|
||||
_, foundTest := mod.GetProviderConfig("foo-test", "test")
|
||||
if !foundTest {
|
||||
t.Fatal("unable to find test provider")
|
||||
}
|
||||
|
||||
_, foundProd := mod.GetProviderConfig("foo-test", "prod")
|
||||
if !foundProd {
|
||||
t.Fatal("unable to find prod provider")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewModule_provider_invalid_name(t *testing.T) {
|
||||
mod, diags := testModuleFromDir("testdata/providers_iteration_invalid_name")
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
expected := "Invalid for_each key alias"
|
||||
expectedDetail := "Alias \"0\" must be a valid name. A name must start with a letter or underscore and may contain only letters, digits, underscores, and dashes."
|
||||
|
||||
if gotErr := diags[0].Summary; gotErr != expected {
|
||||
t.Errorf("wrong error, got %q, want %q", gotErr, expected)
|
||||
}
|
||||
if gotErr := diags[0].Detail; gotErr != expectedDetail {
|
||||
t.Errorf("wrong error, got %q, want %q", gotErr, expectedDetail)
|
||||
}
|
||||
|
||||
p := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "hashicorp", providerTestName)
|
||||
if name, exists := mod.ProviderLocalNames[p]; !exists {
|
||||
t.Fatal("provider FQN hashicorp/local not found")
|
||||
} else if name != providerTestName {
|
||||
t.Fatalf("provider localname mismatch: got %s, want %s", name, providerTestName)
|
||||
}
|
||||
|
||||
if len(mod.ProviderConfigs) != 0 {
|
||||
t.Fatalf("incorrect number of providers: got %d, expected: %d", len(mod.ProviderConfigs), 0)
|
||||
}
|
||||
}
|
@ -30,10 +30,10 @@ func TestProviderReservedNames(t *testing.T) {
|
||||
`config.tf:4,13-20: Version constraints inside provider configuration blocks are deprecated; OpenTofu 0.13 and earlier allowed provider version constraints inside the provider configuration block, but that is now deprecated and will be removed in a future version of OpenTofu. To silence this warning, move the provider version constraint into the required_providers block.`,
|
||||
`config.tf:10,3-8: Reserved argument name in provider block; The provider argument name "count" is reserved for use by OpenTofu in a future version.`,
|
||||
`config.tf:11,3-13: Reserved argument name in provider block; The provider argument name "depends_on" is reserved for use by OpenTofu in a future version.`,
|
||||
`config.tf:12,3-11: Reserved argument name in provider block; The provider argument name "for_each" is reserved for use by OpenTofu in a future version.`,
|
||||
`config.tf:14,3-12: Reserved block type name in provider block; The block type name "lifecycle" is reserved for use by OpenTofu in a future version.`,
|
||||
`config.tf:15,3-9: Reserved block type name in provider block; The block type name "locals" is reserved for use by OpenTofu in a future version.`,
|
||||
`config.tf:13,3-9: Reserved argument name in provider block; The provider argument name "source" is reserved for use by OpenTofu in a future version.`,
|
||||
`config.tf:3,13-18: Invalid combination of "alias" and "for_each"; The "alias" and "for_each" arguments are mutually-exclusive, only one may be used.`,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||
Summary: "Provider type mismatch",
|
||||
Detail: fmt.Sprintf(
|
||||
"The provider %q in %s represents provider %q, but %q in the root module represents %q.\n\nThis means the provider definition for %q within %s, or other provider definitions with the same name, have been referenced by multiple run blocks and assigned to different provider types.",
|
||||
provider.Addr().StringCompact(), name, providerType, requirement.Name, requirement.Type, provider.Addr().StringCompact(), name),
|
||||
provider.moduleUniqueKey(), name, providerType, requirement.Name, requirement.Type, provider.moduleUniqueKey(), name),
|
||||
Subject: provider.DeclRange.Ptr(),
|
||||
})
|
||||
}
|
||||
@ -114,7 +114,7 @@ func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||
Summary: "Provider type mismatch",
|
||||
Detail: fmt.Sprintf(
|
||||
"The provider %q in %s represents provider %q, but %q in the root module represents %q.\n\nThis means the provider definition for %q within %s, or other provider definitions with the same name, have been referenced by multiple run blocks and assigned to different provider types.",
|
||||
provider.Addr().StringCompact(), name, providerType, alias.StringCompact(), requirement.Type, provider.Addr().StringCompact(), name),
|
||||
provider.moduleUniqueKey(), name, providerType, alias.StringCompact(), requirement.Type, provider.moduleUniqueKey(), name),
|
||||
Subject: provider.DeclRange.Ptr(),
|
||||
})
|
||||
}
|
||||
@ -129,7 +129,8 @@ func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||
providerType = addrs.NewDefaultProvider(provider.Name)
|
||||
}
|
||||
|
||||
if testProvider, exists := test.Providers[provider.Addr().StringCompact()]; exists {
|
||||
if testProvider, exists := test.Providers[provider.moduleUniqueKey()]; exists {
|
||||
|
||||
testProviderType := testProvider.providerType
|
||||
if testProviderType.IsZero() {
|
||||
testProviderType = addrs.NewDefaultProvider(testProvider.Name)
|
||||
@ -141,7 +142,7 @@ func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||
Summary: "Provider type mismatch",
|
||||
Detail: fmt.Sprintf(
|
||||
"The provider %q in %s represents provider %q, but %q in the root module represents %q.\n\nThis means the provider definition for %q within %s has been referenced by multiple run blocks and assigned to different provider types.",
|
||||
testProvider.Addr().StringCompact(), name, testProviderType, provider.Addr().StringCompact(), providerType, testProvider.Addr().StringCompact(), name),
|
||||
testProvider.moduleUniqueKey(), name, testProviderType, provider.moduleUniqueKey(), providerType, testProvider.moduleUniqueKey(), name),
|
||||
Subject: testProvider.DeclRange.Ptr(),
|
||||
})
|
||||
}
|
||||
@ -177,6 +178,7 @@ func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||
Name: provider.Name,
|
||||
NameRange: provider.NameRange,
|
||||
Alias: provider.Alias,
|
||||
AliasRange: provider.AliasRange,
|
||||
providerType: provider.providerType,
|
||||
},
|
||||
}
|
||||
@ -201,6 +203,7 @@ func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||
Name: provider.Name,
|
||||
NameRange: provider.NameRange,
|
||||
Alias: provider.Alias,
|
||||
AliasRange: provider.AliasRange,
|
||||
providerType: provider.providerType,
|
||||
},
|
||||
}
|
||||
@ -220,7 +223,7 @@ func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||
// better error messages to use these.
|
||||
|
||||
for _, provider := range cfg.Module.ProviderConfigs {
|
||||
key := provider.Addr().StringCompact()
|
||||
key := provider.moduleUniqueKey()
|
||||
|
||||
if testProvider, exists := test.Providers[key]; exists {
|
||||
matchedProviders[key] = PassedProviderConfig{
|
||||
@ -235,6 +238,7 @@ func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||
Name: testProvider.Name,
|
||||
NameRange: testProvider.NameRange,
|
||||
Alias: testProvider.Alias,
|
||||
AliasRange: testProvider.AliasRange,
|
||||
providerType: testProvider.providerType,
|
||||
},
|
||||
}
|
||||
|
@ -100,14 +100,13 @@ func (file *TestFile) getTestProviderOrMock(addr string) (*Provider, bool) {
|
||||
mockProvider, ok := file.MockProviders[addr]
|
||||
if ok {
|
||||
p := &Provider{
|
||||
ProviderCommon: ProviderCommon{
|
||||
Name: mockProvider.Name,
|
||||
NameRange: mockProvider.NameRange,
|
||||
DeclRange: mockProvider.DeclRange,
|
||||
IsMocked: true,
|
||||
MockResources: mockProvider.MockResources,
|
||||
},
|
||||
Alias: mockProvider.Alias,
|
||||
Name: mockProvider.Name,
|
||||
NameRange: mockProvider.NameRange,
|
||||
Alias: mockProvider.Alias,
|
||||
AliasRange: mockProvider.AliasRange,
|
||||
DeclRange: mockProvider.DeclRange,
|
||||
IsMocked: true,
|
||||
MockResources: mockProvider.MockResources,
|
||||
}
|
||||
|
||||
return p, true
|
||||
@ -397,17 +396,10 @@ func loadTestFile(body hcl.Body) (*TestFile, hcl.Diagnostics) {
|
||||
}
|
||||
|
||||
case "provider":
|
||||
providerBlock, providerDiags := decodeProviderBlock(block)
|
||||
provider, providerDiags := decodeProviderBlock(block)
|
||||
diags = append(diags, providerDiags...)
|
||||
if providerBlock != nil {
|
||||
providers, diagsStatic := providerBlock.decodeStaticFields(nil)
|
||||
diags = append(diags, diagsStatic...)
|
||||
if diagsStatic.HasErrors() {
|
||||
continue
|
||||
}
|
||||
for _, provider := range providers {
|
||||
tf.Providers[provider.Addr().StringCompact()] = provider
|
||||
}
|
||||
if provider != nil {
|
||||
tf.Providers[provider.moduleUniqueKey()] = provider
|
||||
}
|
||||
|
||||
case blockNameOverrideResource:
|
||||
|
@ -1,28 +0,0 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
local = {
|
||||
source = "hashicorp/local"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
files = {
|
||||
dev = {
|
||||
filename = "/tmp/dev"
|
||||
content = "who dis?"
|
||||
}
|
||||
test = {
|
||||
filename = "/tmp/test"
|
||||
content = "testing 1 2 3"
|
||||
}
|
||||
prod = {
|
||||
filename = "/tmp/prod"
|
||||
content = "this is a serious string, because it's production"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "foo-test" {
|
||||
for_each = local.files
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
local = {
|
||||
source = "hashicorp/local"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
files = {
|
||||
0 = {
|
||||
filename = "/tmp/0"
|
||||
content = "who dis?"
|
||||
}
|
||||
test = {
|
||||
filename = "/tmp/test"
|
||||
content = "testing 1 2 3"
|
||||
}
|
||||
prod = {
|
||||
filename = "/tmp/prod"
|
||||
content = "this is a serious string, because it's production"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "foo-test" {
|
||||
for_each = local.files
|
||||
}
|
@ -11,7 +11,3 @@ provider "bar" {
|
||||
|
||||
alias = "bar"
|
||||
}
|
||||
|
||||
provider "baz" {
|
||||
for_each = {"a": "first", "b": "second"}
|
||||
}
|
||||
|
@ -34,10 +34,8 @@ func TestBuildProviderConfig(t *testing.T) {
|
||||
},
|
||||
}
|
||||
gotBody := buildProviderConfig(ctx, providerAddr, &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "foo",
|
||||
Config: configBody,
|
||||
},
|
||||
Name: "foo",
|
||||
Config: configBody,
|
||||
})
|
||||
|
||||
schema := &configschema.Block{
|
||||
|
@ -79,9 +79,6 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi
|
||||
}
|
||||
|
||||
data := EvalDataForNoInstanceKey
|
||||
if n.Config != nil {
|
||||
data = n.Config.InstanceData
|
||||
}
|
||||
|
||||
configVal, _, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, data)
|
||||
if evalDiags.HasErrors() {
|
||||
@ -119,9 +116,6 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider prov
|
||||
|
||||
configSchema := resp.Provider.Block
|
||||
data := EvalDataForNoInstanceKey
|
||||
if n.Config != nil {
|
||||
data = n.Config.InstanceData
|
||||
}
|
||||
|
||||
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, data)
|
||||
diags = diags.Append(evalDiags)
|
||||
|
@ -22,12 +22,10 @@ import (
|
||||
|
||||
func TestNodeApplyableProviderExecute(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"user": cty.StringVal("hello"),
|
||||
}),
|
||||
},
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"user": cty.StringVal("hello"),
|
||||
}),
|
||||
}
|
||||
|
||||
schema := &configschema.Block{
|
||||
@ -85,12 +83,10 @@ func TestNodeApplyableProviderExecute(t *testing.T) {
|
||||
|
||||
func TestNodeApplyableProviderExecute_unknownImport(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"test_string": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
},
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"test_string": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
}
|
||||
provider := mockProviderWithConfigSchema(simpleTestSchema())
|
||||
providerAddr := addrs.AbsProviderConfig{
|
||||
@ -122,12 +118,10 @@ func TestNodeApplyableProviderExecute_unknownImport(t *testing.T) {
|
||||
|
||||
func TestNodeApplyableProviderExecute_unknownApply(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"test_string": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
},
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"test_string": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
}
|
||||
provider := mockProviderWithConfigSchema(simpleTestSchema())
|
||||
providerAddr := addrs.AbsProviderConfig{
|
||||
@ -160,12 +154,10 @@ func TestNodeApplyableProviderExecute_unknownApply(t *testing.T) {
|
||||
|
||||
func TestNodeApplyableProviderExecute_sensitive(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"test_string": cty.StringVal("hello").Mark(marks.Sensitive),
|
||||
}),
|
||||
},
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"test_string": cty.StringVal("hello").Mark(marks.Sensitive),
|
||||
}),
|
||||
}
|
||||
provider := mockProviderWithConfigSchema(simpleTestSchema())
|
||||
providerAddr := addrs.AbsProviderConfig{
|
||||
@ -199,12 +191,10 @@ func TestNodeApplyableProviderExecute_sensitive(t *testing.T) {
|
||||
|
||||
func TestNodeApplyableProviderExecute_sensitiveValidate(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"test_string": cty.StringVal("hello").Mark(marks.Sensitive),
|
||||
}),
|
||||
},
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"test_string": cty.StringVal("hello").Mark(marks.Sensitive),
|
||||
}),
|
||||
}
|
||||
provider := mockProviderWithConfigSchema(simpleTestSchema())
|
||||
providerAddr := addrs.AbsProviderConfig{
|
||||
@ -238,10 +228,8 @@ func TestNodeApplyableProviderExecute_sensitiveValidate(t *testing.T) {
|
||||
|
||||
func TestNodeApplyableProviderExecute_emptyValidate(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{}),
|
||||
},
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{}),
|
||||
}
|
||||
provider := mockProviderWithConfigSchema(&configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
@ -286,12 +274,10 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
|
||||
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.StringVal("mars"),
|
||||
}),
|
||||
},
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.StringVal("mars"),
|
||||
}),
|
||||
}
|
||||
|
||||
node := NodeApplyableProvider{
|
||||
@ -309,12 +295,10 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
|
||||
|
||||
t.Run("invalid", func(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.MapValEmpty(cty.String),
|
||||
}),
|
||||
},
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.MapValEmpty(cty.String),
|
||||
}),
|
||||
}
|
||||
|
||||
node := NodeApplyableProvider{
|
||||
@ -372,12 +356,10 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
|
||||
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.StringVal("mars"),
|
||||
}),
|
||||
},
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.StringVal("mars"),
|
||||
}),
|
||||
}
|
||||
|
||||
node := NodeApplyableProvider{
|
||||
@ -411,10 +393,8 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
|
||||
|
||||
t.Run("missing required config", func(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "test",
|
||||
Config: hcl.EmptyBody(),
|
||||
},
|
||||
Name: "test",
|
||||
Config: hcl.EmptyBody(),
|
||||
}
|
||||
node := NodeApplyableProvider{
|
||||
NodeAbstractProvider: &NodeAbstractProvider{
|
||||
@ -465,12 +445,10 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
|
||||
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.StringVal("mars"),
|
||||
}),
|
||||
},
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.StringVal("mars"),
|
||||
}),
|
||||
}
|
||||
|
||||
node := NodeApplyableProvider{
|
||||
@ -504,10 +482,8 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
|
||||
|
||||
t.Run("missing required config", func(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
ProviderCommon: configs.ProviderCommon{
|
||||
Name: "test",
|
||||
Config: hcl.EmptyBody(),
|
||||
},
|
||||
Name: "test",
|
||||
Config: hcl.EmptyBody(),
|
||||
}
|
||||
node := NodeApplyableProvider{
|
||||
NodeAbstractProvider: &NodeAbstractProvider{
|
||||
|
Loading…
Reference in New Issue
Block a user