Implement Provider for_each (#2105)

Signed-off-by: ollevche <ollevche@gmail.com>
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
Signed-off-by: Ronny Orot <ronny.orot@gmail.com>
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
Co-authored-by: ollevche <ollevche@gmail.com>
Co-authored-by: Ronny Orot <ronny.orot@gmail.com>
Co-authored-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
Christian Mesh 2024-11-05 18:08:23 -05:00 committed by GitHub
parent 3d4bf29c56
commit fd775f0fe3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
98 changed files with 2371 additions and 468 deletions

View File

@ -30,7 +30,7 @@ linters-settings:
require-specific: true
cyclop:
max-complexity: 15
max-complexity: 20
gocognit:
min-complexity: 50
@ -38,6 +38,14 @@ linters-settings:
goconst:
ignore-tests: true # Is documented to be the default behaviour, but that doesn't seem to be the case
gocritic:
settings:
ifElseChain:
minThreshold: 4
nestif:
min-complexity: 6
issues:
exclude-rules:
- path: (.+)_test.go

View File

@ -17,6 +17,7 @@ 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:

View File

@ -113,8 +113,26 @@ var _ ProviderConfig = AbsProviderConfig{}
// This type of address is typically not used prominently in the UI, except in
// error messages that refer to provider configurations.
func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags.Diagnostics) {
pc, key, diags := ParseAbsProviderConfigInstance(traversal)
if key != NoKey {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider configuration address",
Detail: "A provider address must not include an instance key.",
Subject: traversal.SourceRange().Ptr(),
})
}
return pc, diags
}
// ParseAbsProviderConfigInstance behaves identically to ParseAbsProviderConfig, but additionally
// allows an instance key after the alias.
//
//nolint:mnd // traversals with specific indices
func ParseAbsProviderConfigInstance(traversal hcl.Traversal) (AbsProviderConfig, InstanceKey, tfdiags.Diagnostics) {
modInst, remain, diags := parseModuleInstancePrefix(traversal)
var ret AbsProviderConfig
var key InstanceKey
// Providers cannot resolve within module instances, so verify that there
// are no instance keys in the module path before converting to a Module.
@ -123,10 +141,10 @@ func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider configuration address",
Detail: "Provider address cannot contain module indexes",
Detail: "A provider configuration must not appear in a module instance that uses count or for_each.",
Subject: remain.SourceRange().Ptr(),
})
return ret, diags
return ret, key, diags
}
}
ret.Module = modInst.Module()
@ -138,16 +156,16 @@ func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags
Detail: "Provider address must begin with \"provider.\", followed by a provider type name.",
Subject: remain.SourceRange().Ptr(),
})
return ret, diags
return ret, key, diags
}
if len(remain) > 3 {
if len(remain) > 4 {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider configuration address",
Detail: "Extraneous operators after provider configuration alias.",
Subject: hcl.Traversal(remain[3:]).SourceRange().Ptr(),
Detail: "Extraneous operators after provider configuration reference.",
Subject: remain[4:].SourceRange().Ptr(),
})
return ret, diags
return ret, key, diags
}
if tt, ok := remain[1].(hcl.TraverseIndex); ok {
@ -158,13 +176,13 @@ func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags
Detail: "The prefix \"provider.\" must be followed by a provider type name.",
Subject: remain[1].SourceRange().Ptr(),
})
return ret, diags
return ret, key, diags
}
p, sourceDiags := ParseProviderSourceString(tt.Key.AsString())
ret.Provider = p
if sourceDiags.HasErrors() {
diags = diags.Append(sourceDiags)
return ret, diags
return ret, key, diags
}
} else {
diags = diags.Append(&hcl.Diagnostic{
@ -173,10 +191,10 @@ func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags
Detail: "The prefix \"provider.\" must be followed by a provider type name.",
Subject: remain[1].SourceRange().Ptr(),
})
return ret, diags
return ret, key, diags
}
if len(remain) == 3 {
if len(remain) > 2 {
if tt, ok := remain[2].(hcl.TraverseAttr); ok {
ret.Alias = tt.Name
} else {
@ -186,11 +204,34 @@ func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags
Detail: "Provider type name must be followed by a configuration alias name.",
Subject: remain[2].SourceRange().Ptr(),
})
return ret, diags
return ret, key, diags
}
}
return ret, diags
if len(remain) > 3 {
if tt, ok := remain[3].(hcl.TraverseIndex); ok {
var keyErr error
key, keyErr = ParseInstanceKey(tt.Key)
if keyErr != nil {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider configuration address",
Detail: fmt.Sprintf("Invalid provider instance key: %s.", keyErr.Error()),
Subject: remain[3].SourceRange().Ptr(),
})
}
} else {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider configuration address",
Detail: "A provider configuration alias can be followed only by an instance key in brackets.",
Subject: remain[3].SourceRange().Ptr(),
})
return ret, key, diags
}
}
return ret, key, diags
}
// ParseAbsProviderConfigStr is a helper wrapper around ParseAbsProviderConfig
@ -219,6 +260,17 @@ func ParseAbsProviderConfigStr(str string) (AbsProviderConfig, tfdiags.Diagnosti
diags = diags.Append(addrDiags)
return addr, diags
}
func ParseAbsProviderConfigInstanceStr(str string) (AbsProviderConfig, InstanceKey, 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 AbsProviderConfig{}, nil, diags
}
addr, key, addrDiags := ParseAbsProviderConfigInstance(traversal)
diags = diags.Append(addrDiags)
return addr, key, diags
}
func ParseLegacyAbsProviderConfigStr(str string) (AbsProviderConfig, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
@ -413,3 +465,10 @@ func (pc AbsProviderConfig) String() string {
return strings.Join(parts, ".")
}
func (pc AbsProviderConfig) InstanceString(key InstanceKey) string {
if key == NoKey {
return pc.String()
}
return pc.String() + key.String()
}

View File

@ -15,10 +15,11 @@ import (
"github.com/hashicorp/hcl/v2/hclsyntax"
)
func TestParseAbsProviderConfig(t *testing.T) {
func TestParseAbsProviderConfigInstances(t *testing.T) {
tests := []struct {
Input string
Want AbsProviderConfig
WantKey InstanceKey
WantDiag string
}{
{
@ -31,6 +32,7 @@ func TestParseAbsProviderConfig(t *testing.T) {
Hostname: "registry.opentofu.org",
},
},
NoKey,
``,
},
{
@ -44,6 +46,7 @@ func TestParseAbsProviderConfig(t *testing.T) {
},
Alias: "foo",
},
NoKey,
``,
},
{
@ -56,6 +59,7 @@ func TestParseAbsProviderConfig(t *testing.T) {
Hostname: "registry.opentofu.org",
},
},
NoKey,
``,
},
{
@ -69,56 +73,81 @@ func TestParseAbsProviderConfig(t *testing.T) {
},
Alias: "foo",
},
NoKey,
``,
},
{
`module.baz.provider["registry.opentofu.org/hashicorp/aws"].foo["keystr"]`,
AbsProviderConfig{
Module: Module{"baz"},
Provider: Provider{
Type: "aws",
Namespace: "hashicorp",
Hostname: "registry.opentofu.org",
},
Alias: "foo",
},
StringKey("keystr"),
``,
},
{
`module.baz["foo"].provider["registry.opentofu.org/hashicorp/aws"]`,
AbsProviderConfig{},
`Provider address cannot contain module indexes`,
NoKey,
`A provider configuration must not appear in a module instance that uses count or for_each.`,
},
{
`module.baz[1].provider["registry.opentofu.org/hashicorp/aws"]`,
AbsProviderConfig{},
`Provider address cannot contain module indexes`,
NoKey,
`A provider configuration must not appear in a module instance that uses count or for_each.`,
},
{
`module.baz[1].module.bar.provider["registry.opentofu.org/hashicorp/aws"]`,
AbsProviderConfig{},
`Provider address cannot contain module indexes`,
NoKey,
`A provider configuration must not appear in a module instance that uses count or for_each.`,
},
{
`aws`,
AbsProviderConfig{},
NoKey,
`Provider address must begin with "provider.", followed by a provider type name.`,
},
{
`aws.foo`,
AbsProviderConfig{},
NoKey,
`Provider address must begin with "provider.", followed by a provider type name.`,
},
{
`provider`,
AbsProviderConfig{},
NoKey,
`Provider address must begin with "provider.", followed by a provider type name.`,
},
{
`provider.aws.foo.bar`,
`provider.aws.foo["bar"].baz`,
AbsProviderConfig{},
`Extraneous operators after provider configuration alias.`,
NoKey,
`Extraneous operators after provider configuration reference.`,
},
{
`provider["aws"]["foo"]`,
AbsProviderConfig{},
NoKey,
`Provider type name must be followed by a configuration alias name.`,
},
{
`module.foo`,
AbsProviderConfig{},
NoKey,
`Provider address must begin with "provider.", followed by a provider type name.`,
},
{
`provider[0]`,
AbsProviderConfig{},
NoKey,
`The prefix "provider." must be followed by a provider type name.`,
},
}
@ -134,7 +163,7 @@ func TestParseAbsProviderConfig(t *testing.T) {
return
}
got, diags := ParseAbsProviderConfig(traversal)
got, key, diags := ParseAbsProviderConfigInstance(traversal)
if test.WantDiag != "" {
if len(diags) != 1 {
@ -154,6 +183,10 @@ func TestParseAbsProviderConfig(t *testing.T) {
for _, problem := range deep.Equal(got, test.Want) {
t.Error(problem)
}
if test.WantKey != key {
t.Errorf("Wanted key %s, got key %s", test.WantKey, key)
}
})
}
}

View File

@ -369,6 +369,7 @@ func TestLocal_planDeposedOnly(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
}))
outDir := t.TempDir()
@ -765,6 +766,7 @@ func testPlanState() *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
return state
}
@ -792,6 +794,7 @@ func testPlanState_withDataSource() *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
rootModule.SetResourceInstanceCurrent(
addrs.Resource{
@ -809,6 +812,7 @@ func testPlanState_withDataSource() *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
return state
}
@ -836,6 +840,7 @@ func testPlanState_tainted() *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
return state
}

View File

@ -300,6 +300,7 @@ func testRefreshState() *states.State {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
return state
}

View File

@ -159,6 +159,7 @@ func TestBackendStates(t *testing.T, b Backend) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// write a distinct known state to bar

View File

@ -44,6 +44,7 @@ func TestApply_destroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -149,6 +150,7 @@ func TestApply_destroyApproveNo(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -217,6 +219,7 @@ func TestApply_destroyApproveYes(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -287,6 +290,7 @@ func TestApply_destroyLockedState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -415,6 +419,7 @@ func TestApply_targetedDestroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
},
},
@ -456,6 +461,7 @@ func TestApply_targetedDestroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
},
},
@ -483,6 +489,7 @@ func TestApply_targetedDestroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -499,6 +506,7 @@ func TestApply_targetedDestroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})

View File

@ -1000,6 +1000,7 @@ func TestApply_refresh(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -1067,6 +1068,7 @@ func TestApply_refreshFalse(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -1204,6 +1206,7 @@ func TestApply_state(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -1601,6 +1604,7 @@ func TestApply_backup(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -2128,6 +2132,7 @@ func TestApply_replace(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)

View File

@ -311,6 +311,7 @@ func testState() *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// DeepCopy is used here to ensure our synthetic state matches exactly
// with a state that will have been copied during the command

View File

@ -271,6 +271,7 @@ func basicState(t *testing.T) *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
rootModule.SetResourceInstanceCurrent(
addrs.Resource{
@ -287,6 +288,7 @@ func basicState(t *testing.T) *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
return state
}
@ -323,6 +325,7 @@ func stateWithMoreOutputs(t *testing.T) *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
return state
}
@ -350,6 +353,7 @@ func nestedState(t *testing.T) *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
return state
}
@ -373,6 +377,7 @@ func deposedState(t *testing.T) *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
return state
}
@ -402,6 +407,7 @@ func onlyDeposedState(t *testing.T) *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
rootModule.SetResourceInstanceDeposed(
addrs.Resource{
@ -419,6 +425,7 @@ func onlyDeposedState(t *testing.T) *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
return state
}

View File

@ -631,6 +631,7 @@ func TestMarshalModules_basic(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -646,6 +647,7 @@ func TestMarshalModules_basic(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: childModule.Module(),
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -661,6 +663,7 @@ func TestMarshalModules_basic(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: subModule.Module(),
},
addrs.NoKey,
)
})
moduleMap := make(map[string][]addrs.ModuleInstance)
@ -700,6 +703,7 @@ func TestMarshalModules_nested(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -715,6 +719,7 @@ func TestMarshalModules_nested(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: childModule.Module(),
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -730,6 +735,7 @@ func TestMarshalModules_nested(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: subModule.Module(),
},
addrs.NoKey,
)
})
moduleMap := make(map[string][]addrs.ModuleInstance)
@ -772,6 +778,7 @@ func TestMarshalModules_parent_no_resources(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -787,6 +794,7 @@ func TestMarshalModules_parent_no_resources(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: subModule.Module(),
},
addrs.NoKey,
)
})
got, err := marshalRootModule(testState, testSchemas())

View File

@ -153,6 +153,7 @@ func TestPlan_destroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
outPath := testTempFile(t)
@ -316,6 +317,7 @@ func TestPlan_outPathNoChange(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)
@ -417,6 +419,7 @@ func TestPlan_outBackend(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -1507,6 +1510,7 @@ func TestPlan_replace(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, originalState)

View File

@ -148,6 +148,7 @@ func TestShow_argsWithStateAliasedProvider(t *testing.T) {
Dependencies: []addrs.ConfigResource{},
},
addrs.RootModuleInstance.ProviderConfigAliased(addrs.NewDefaultProvider("test"), "alias"),
addrs.NoKey,
)
})

View File

@ -35,6 +35,7 @@ func TestStateMv(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -51,6 +52,7 @@ func TestStateMv(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -171,6 +173,7 @@ func TestStateMv_backupAndBackupOutOptionsWithNonLocalBackend(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -418,6 +421,7 @@ func TestStateMv_resourceToInstance(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -434,6 +438,7 @@ func TestStateMv_resourceToInstance(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceProvider(
addrs.Resource{
@ -509,6 +514,7 @@ func TestStateMv_resourceToInstanceErr(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceProvider(
addrs.Resource{
@ -578,6 +584,7 @@ func TestStateMv_resourceToInstanceErrInAutomation(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceProvider(
addrs.Resource{
@ -648,6 +655,7 @@ func TestStateMv_instanceToResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -663,6 +671,7 @@ func TestStateMv_instanceToResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -738,6 +747,7 @@ func TestStateMv_instanceToNewResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -811,6 +821,7 @@ func TestStateMv_differentResourceTypes(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -873,6 +884,7 @@ func TestStateMv_explicitWithBackend(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -888,6 +900,7 @@ func TestStateMv_explicitWithBackend(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -951,6 +964,7 @@ func TestStateMv_backupExplicit(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -967,6 +981,7 @@ func TestStateMv_backupExplicit(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -1018,6 +1033,7 @@ func TestStateMv_stateOutNew(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -1074,6 +1090,7 @@ func TestStateMv_stateOutExisting(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, stateSrc)
@ -1093,6 +1110,7 @@ func TestStateMv_stateOutExisting(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
stateOutPath := testStateFile(t, stateDst)
@ -1176,6 +1194,7 @@ func TestStateMv_stateOutNew_count(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -1191,6 +1210,7 @@ func TestStateMv_stateOutNew_count(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -1206,6 +1226,7 @@ func TestStateMv_stateOutNew_count(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -1266,6 +1287,7 @@ func TestStateMv_stateOutNew_largeCount(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
}
s.SetResourceInstanceCurrent(
@ -1282,6 +1304,7 @@ func TestStateMv_stateOutNew_largeCount(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -1338,6 +1361,7 @@ func TestStateMv_stateOutNew_nestedModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -1353,6 +1377,7 @@ func TestStateMv_stateOutNew_nestedModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -1410,6 +1435,7 @@ func TestStateMv_toNewModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -1484,6 +1510,7 @@ func TestStateMv_withinBackend(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -1500,6 +1527,7 @@ func TestStateMv_withinBackend(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -1559,6 +1587,7 @@ func TestStateMv_fromBackendToLocal(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent(
mustResourceAddr("test_instance.baz").Resource.Instance(addrs.NoKey),
@ -1570,6 +1599,7 @@ func TestStateMv_fromBackendToLocal(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// the local backend state file is "foo"
@ -1635,6 +1665,7 @@ func TestStateMv_onlyResourceInModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -1730,6 +1761,7 @@ func TestStateMv_checkRequiredVersion(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -1746,6 +1778,7 @@ func TestStateMv_checkRequiredVersion(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)

View File

@ -33,6 +33,7 @@ func TestStateReplaceProvider(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -48,6 +49,7 @@ func TestStateReplaceProvider(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -63,6 +65,7 @@ func TestStateReplaceProvider(t *testing.T) {
Provider: addrs.NewLegacyProvider("azurerm"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -320,6 +323,7 @@ func TestStateReplaceProvider_checkRequiredVersion(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -335,6 +339,7 @@ func TestStateReplaceProvider_checkRequiredVersion(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -350,6 +355,7 @@ func TestStateReplaceProvider_checkRequiredVersion(t *testing.T) {
Provider: addrs.NewLegacyProvider("azurerm"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})

View File

@ -33,6 +33,7 @@ func TestStateRm(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -48,6 +49,7 @@ func TestStateRm(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -100,6 +102,7 @@ func TestStateRmNotChildModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// This second instance has the same local address as the first but
// is in a child module. Older versions of Terraform would incorrectly
@ -118,6 +121,7 @@ func TestStateRmNotChildModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -191,6 +195,7 @@ func TestStateRmNoArgs(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -206,6 +211,7 @@ func TestStateRmNoArgs(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -252,6 +258,7 @@ func TestStateRmNonExist(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -267,6 +274,7 @@ func TestStateRmNonExist(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -309,6 +317,7 @@ func TestStateRm_backupExplicit(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -324,6 +333,7 @@ func TestStateRm_backupExplicit(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -428,6 +438,7 @@ func TestStateRm_backendState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -443,6 +454,7 @@ func TestStateRm_backendState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -509,6 +521,7 @@ func TestStateRm_checkRequiredVersion(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -524,6 +537,7 @@ func TestStateRm_checkRequiredVersion(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)

View File

@ -172,6 +172,7 @@ func (c *StateShowCommand) Run(args []string) int {
addr.Resource,
is.Current,
absPc,
addrs.NoKey,
)
root, outputs, err := jsonstate.MarshalForRenderer(statefile.New(singleInstance, "", 0), schemas)

View File

@ -34,6 +34,7 @@ func TestStateShow(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -96,6 +97,7 @@ func TestStateShow_multi(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -111,6 +113,7 @@ func TestStateShow_multi(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: submod.Module(),
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -222,6 +225,7 @@ func TestStateShow_configured_provider(t *testing.T) {
Provider: addrs.NewDefaultProvider("test-beta"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -364,6 +368,7 @@ func stateWithSensitiveValueForStateShow() *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})

View File

@ -186,7 +186,7 @@ func (c *TaintCommand) Run(args []string) int {
}
obj.Status = states.ObjectTainted
ss.SetResourceInstanceCurrent(addr, obj, rs.ProviderConfig)
ss.SetResourceInstanceCurrent(addr, obj, rs.ProviderConfig, is.ProviderKey)
if err := stateMgr.WriteState(state); err != nil {
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))

View File

@ -33,6 +33,7 @@ func TestTaint(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -73,6 +74,7 @@ func TestTaint_lockedState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -125,6 +127,7 @@ func TestTaint_backup(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testStateFileDefault(t, state)
@ -169,6 +172,7 @@ func TestTaint_backupDisable(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testStateFileDefault(t, state)
@ -236,6 +240,7 @@ func TestTaint_defaultState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testStateFileDefault(t, state)
@ -278,6 +283,7 @@ func TestTaint_defaultWorkspaceState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testWorkspace := "development"
@ -317,6 +323,7 @@ func TestTaint_missing(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -355,6 +362,7 @@ func TestTaint_missingAllow(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -411,6 +419,7 @@ func TestTaint_stateOut(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testStateFileDefault(t, state)
@ -452,6 +461,7 @@ func TestTaint_module(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -467,6 +477,7 @@ func TestTaint_module(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -513,6 +524,7 @@ func TestTaint_checkRequiredVersion(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
path := testStateFile(t, state)

View File

@ -187,7 +187,7 @@ func (c *UntaintCommand) Run(args []string) int {
}
obj.Status = states.ObjectReady
ss.SetResourceInstanceCurrent(addr, obj, rs.ProviderConfig)
ss.SetResourceInstanceCurrent(addr, obj, rs.ProviderConfig, is.ProviderKey)
if err := stateMgr.WriteState(state); err != nil {
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))

View File

@ -32,6 +32,7 @@ func TestUntaint(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -77,6 +78,7 @@ func TestUntaint_lockedState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -129,6 +131,7 @@ func TestUntaint_backup(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testStateFileDefault(t, state)
@ -184,6 +187,7 @@ func TestUntaint_backupDisable(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testStateFileDefault(t, state)
@ -255,6 +259,7 @@ func TestUntaint_defaultState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testStateFileDefault(t, state)
@ -302,6 +307,7 @@ func TestUntaint_defaultWorkspaceState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testWorkspace := "development"
@ -345,6 +351,7 @@ func TestUntaint_missing(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -383,6 +390,7 @@ func TestUntaint_missingAllow(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)
@ -439,6 +447,7 @@ func TestUntaint_stateOut(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
testStateFileDefault(t, state)
@ -488,6 +497,7 @@ func TestUntaint_module(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -503,6 +513,7 @@ func TestUntaint_module(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
statePath := testStateFile(t, state)

View File

@ -309,6 +309,7 @@ func TestOperation_planNoChanges(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
addrs.NoKey,
)
}),
PriorState: states.NewState(),

View File

@ -233,6 +233,7 @@ func testState() *states.State {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// DeepCopy is used here to ensure our synthetic state matches exactly
// with a state that will have been copied during the command

View File

@ -665,7 +665,7 @@ Plan: 1 to add, 0 to change, 0 to destroy.
Namespace: "hashicorp",
Type: "test",
},
})
}, addrs.NoKey)
}),
Config: &configs.Config{},
Providers: map[addrs.Provider]providers.ProviderSchema{
@ -812,7 +812,7 @@ this time it is very bad
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -825,7 +825,7 @@ this time it is very bad
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -839,7 +839,7 @@ this time it is very bad
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
stdout: `
Warning: first warning
@ -880,7 +880,7 @@ up manually:
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -893,7 +893,7 @@ up manually:
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -907,7 +907,7 @@ up manually:
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
stdout: `
Warning: first warning
@ -954,7 +954,7 @@ up manually:
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("null"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -978,7 +978,7 @@ up manually:
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("null"),
})
}, addrs.NoKey)
}),
stdout: `
Warning: first warning
@ -1096,7 +1096,7 @@ OpenTofu was in the process of creating the following resources for
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.AbsResourceInstance{
@ -1110,7 +1110,7 @@ OpenTofu was in the process of creating the following resources for
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
}),
},
created: nil,
@ -1146,7 +1146,7 @@ test:
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.AbsResourceInstance{
@ -1160,7 +1160,7 @@ test:
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
}),
},
created: nil,
@ -1196,7 +1196,7 @@ OpenTofu has already created the following resources for "setup_block" from
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.AbsResourceInstance{
@ -1210,7 +1210,7 @@ OpenTofu has already created the following resources for "setup_block" from
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
}),
nil: states.BuildState(func(state *states.SyncState) {
state.SetResourceInstanceCurrent(
@ -1225,7 +1225,7 @@ OpenTofu has already created the following resources for "setup_block" from
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.AbsResourceInstance{
@ -1239,7 +1239,7 @@ OpenTofu has already created the following resources for "setup_block" from
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
}),
},
created: []*plans.ResourceInstanceChangeSrc{
@ -2021,7 +2021,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
want: []map[string]interface{}{
{
@ -2060,7 +2060,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -2073,7 +2073,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -2087,7 +2087,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
want: []map[string]interface{}{
{
@ -2157,7 +2157,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -2170,7 +2170,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -2184,7 +2184,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
want: []map[string]interface{}{
{
@ -2266,7 +2266,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("null"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -2290,7 +2290,7 @@ func TestTestJSON_DestroySummary(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("null"),
})
}, addrs.NoKey)
}), want: []map[string]interface{}{
{
"@level": "error",
@ -2864,7 +2864,7 @@ func TestTestJSON_Run(t *testing.T) {
Namespace: "hashicorp",
Type: "test",
},
})
}, addrs.NoKey)
}),
Config: &configs.Config{
Module: &configs.Module{},
@ -3021,7 +3021,7 @@ func TestTestJSON_FatalInterruptSummary(t *testing.T) {
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.AbsResourceInstance{
@ -3035,7 +3035,7 @@ func TestTestJSON_FatalInterruptSummary(t *testing.T) {
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
}),
},
changes: nil,
@ -3074,7 +3074,7 @@ func TestTestJSON_FatalInterruptSummary(t *testing.T) {
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.AbsResourceInstance{
@ -3088,7 +3088,7 @@ func TestTestJSON_FatalInterruptSummary(t *testing.T) {
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
}),
},
changes: nil,
@ -3129,7 +3129,7 @@ func TestTestJSON_FatalInterruptSummary(t *testing.T) {
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.AbsResourceInstance{
@ -3143,7 +3143,7 @@ func TestTestJSON_FatalInterruptSummary(t *testing.T) {
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
}),
nil: states.BuildState(func(state *states.SyncState) {
state.SetResourceInstanceCurrent(
@ -3158,7 +3158,7 @@ func TestTestJSON_FatalInterruptSummary(t *testing.T) {
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.AbsResourceInstance{
@ -3172,7 +3172,7 @@ func TestTestJSON_FatalInterruptSummary(t *testing.T) {
},
},
&states.ResourceInstanceObjectSrc{},
addrs.AbsProviderConfig{})
addrs.AbsProviderConfig{}, addrs.NoKey)
}),
},
changes: []*plans.ResourceInstanceChangeSrc{
@ -3279,7 +3279,7 @@ func TestSaveErroredStateFile(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -3292,7 +3292,7 @@ func TestSaveErroredStateFile(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -3306,7 +3306,7 @@ func TestSaveErroredStateFile(t *testing.T) {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
stderr: `
Writing state to file: errored_test.tfstate
@ -3328,7 +3328,7 @@ Writing state to file: errored_test.tfstate
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("null"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -3352,7 +3352,7 @@ Writing state to file: errored_test.tfstate
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("null"),
})
}, addrs.NoKey)
}),
stderr: `
Writing state to file: errored_test.tfstate
@ -3384,7 +3384,7 @@ Writing state to file: errored_test.tfstate
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
stderr: "",
want: []map[string]interface{}{
@ -3410,7 +3410,7 @@ Writing state to file: errored_test.tfstate
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -3423,7 +3423,7 @@ Writing state to file: errored_test.tfstate
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
state.SetResourceInstanceDeposed(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -3437,7 +3437,7 @@ Writing state to file: errored_test.tfstate
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
stderr: "",
want: []map[string]interface{}{
@ -3463,7 +3463,7 @@ Writing state to file: errored_test.tfstate
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("null"),
})
}, addrs.NoKey)
state.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -3487,7 +3487,7 @@ Writing state to file: errored_test.tfstate
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("null"),
})
}, addrs.NoKey)
}),
stderr: "",
want: []map[string]interface{}{

View File

@ -251,6 +251,7 @@ func TestWorkspace_createWithState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})

View File

@ -250,6 +250,11 @@ func NewModule(primaryFiles, overrideFiles []*File, call StaticModuleCall, sourc
diags = append(diags, mDiags...)
}
for _, pc := range mod.ProviderConfigs {
pDiags := pc.decodeStaticFields(mod.StaticEvaluator)
diags = append(diags, pDiags...)
}
diags = append(diags, checkModuleExperiments(mod)...)
// Generate the FQN -> LocalProviderName map

View File

@ -95,7 +95,7 @@ func TestParserLoadConfigDirSuccess(t *testing.T) {
for _, info := range files {
name := info.Name()
t.Run(fmt.Sprintf("%s as module", name), func(t *testing.T) {
t.Run(name, func(t *testing.T) {
src, err := os.ReadFile(filepath.Join("testdata/valid-files", name))
if err != nil {
t.Fatal(err)

View File

@ -11,8 +11,11 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
"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"
)
@ -42,6 +45,9 @@ type Provider struct {
// testing framework to instantiate test provider wrapper.
IsMocked bool
MockResources []*MockResource
ForEach hcl.Expression
Instances map[addrs.InstanceKey]instances.RepetitionData
}
func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
@ -95,8 +101,21 @@ func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
diags = append(diags, versionDiags...)
}
if attr, exists := content.Attributes["for_each"]; exists {
provider.ForEach = attr.Expr
}
if len(provider.Alias) == 0 && provider.ForEach != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: `Alias required when using "for_each"`,
Detail: `The for_each argument is allowed only for provider configurations with an alias.`,
Subject: provider.ForEach.Range().Ptr(),
})
}
// Reserved attribute names
for _, name := range []string{"count", "depends_on", "for_each", "source"} {
for _, name := range []string{"count", "depends_on", "source"} {
if attr, exists := content.Attributes[name]; exists {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
@ -145,6 +164,38 @@ func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
return provider, diags
}
func (p *Provider) decodeStaticFields(eval *StaticEvaluator) hcl.Diagnostics {
var diags hcl.Diagnostics
if p.ForEach != nil {
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.%s.for_each", p.Name, p.Alias),
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 diags
}
p.Instances = make(map[addrs.InstanceKey]instances.RepetitionData)
for k, v := range forVal {
p.Instances[addrs.StringKey(k)] = instances.RepetitionData{
EachKey: cty.StringVal(k),
EachValue: v,
}
}
}
return diags
}
// Addr returns the address of the receiving provider configuration, relative
// to its containing module.
func (p *Provider) Addr() addrs.LocalProviderConfig {
@ -247,11 +298,13 @@ var providerBlockSchema = &hcl.BodySchema{
{
Name: "version",
},
{
Name: "for_each",
},
// Attribute names reserved for future expansion.
{Name: "count"},
{Name: "depends_on"},
{Name: "for_each"},
{Name: "source"},
},
Blocks: []hcl.BlockHeaderSchema{

View File

@ -30,10 +30,9 @@ 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:12,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:13,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:14,3-9: Reserved block type name in provider block; The block type name "locals" is reserved for use by OpenTofu in a future version.`,
})
}

View File

@ -322,6 +322,8 @@ func validateProviderConfigs(parentCall *ModuleCall, cfg *Config, noProviderConf
// of the configuration block declaration.
configured := map[string]hcl.Range{}
instanced := map[string]bool{}
// the set of configuration_aliases defined in the required_providers
// block, with the fully qualified provider type.
configAliases := map[string]addrs.AbsProviderConfig{}
@ -339,6 +341,8 @@ func validateProviderConfigs(parentCall *ModuleCall, cfg *Config, noProviderConf
} else {
emptyConfigs[name] = pc.DeclRange
}
instanced[name] = len(pc.Instances) != 0
}
if mod.ProviderRequirements != nil {
@ -470,6 +474,37 @@ func validateProviderConfigs(parentCall *ModuleCall, cfg *Config, noProviderConf
}
}
// Validate provider expansion is properly configured
for _, modCall := range mod.ModuleCalls {
for _, passed := range modCall.Providers {
if passed.InChild.KeyExpression != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid module provider configuration",
Detail: "Instance keys are not allowed on the left side of a provider configuration assignment.",
Subject: passed.InChild.KeyExpression.Range().Ptr(),
})
}
isInstanced := instanced[providerName(passed.InParent.Name, passed.InParent.Alias)]
diags = diags.Extend(passed.InParent.InstanceValidation("module", isInstanced))
}
}
// Validate that resources using provider keys are properly configured
checkProviderKeys := func(resourceConfigs map[string]*Resource) {
for _, r := range resourceConfigs {
// We're looking for resources with a specific provider reference
if r.ProviderConfigRef == nil {
continue
}
isInstanced := instanced[providerName(r.ProviderConfigRef.Name, r.ProviderConfigRef.Alias)]
diags = diags.Extend(r.ProviderConfigRef.InstanceValidation("resource", isInstanced))
}
}
checkProviderKeys(mod.ManagedResources)
checkProviderKeys(mod.DataResources)
// Verify that any module calls only refer to named providers, and that
// those providers will have a configuration at runtime. This way we can
// direct users where to add the missing configuration, because the runtime

View File

@ -659,11 +659,31 @@ type ProviderConfigRef struct {
// export this so providers don't need to be re-resolved.
// This same field is also added to the Provider struct.
providerType addrs.Provider
KeyExpression hcl.Expression
}
func decodeProviderConfigRef(expr hcl.Expression, argName string) (*ProviderConfigRef, hcl.Diagnostics) {
var diags hcl.Diagnostics
var keyExpr hcl.Expression
const (
// name.alias[const_key]
nameIndex = 0
aliasIndex = 1
keyIndex = 2
)
var maxTraversalLength = keyIndex + 1
// name.alias[expr_key]
if iex, ok := expr.(*hclsyntax.IndexExpr); ok {
maxTraversalLength = aliasIndex + 1 // expr key found, no const key allowed
keyExpr = iex.Key
expr = iex.Collection
}
var shimDiags hcl.Diagnostics
expr, shimDiags = shimTraversalInString(expr, false)
diags = append(diags, shimDiags...)
@ -677,7 +697,7 @@ func decodeProviderConfigRef(expr hcl.Expression, argName string) (*ProviderConf
diags = append(diags, travDiags...)
}
if len(traversal) < 1 || len(traversal) > 2 {
if len(traversal) == 0 || len(traversal) > maxTraversalLength {
// A provider reference was given as a string literal in the legacy
// configuration language and there are lots of examples out there
// showing that usage, so we'll sniff for that situation here and
@ -696,7 +716,7 @@ func decodeProviderConfigRef(expr hcl.Expression, argName string) (*ProviderConf
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.", argName),
Detail: fmt.Sprintf("The %s argument requires a provider type name, optionally followed by a period and then a configuration alias and optional instance key.", argName),
Subject: expr.Range().Ptr(),
})
return nil, diags
@ -704,25 +724,26 @@ func decodeProviderConfigRef(expr hcl.Expression, argName string) (*ProviderConf
// verify that the provider local name is normalized
name := traversal.RootName()
nameDiags := checkProviderNameNormalized(name, traversal[0].SourceRange())
nameDiags := checkProviderNameNormalized(name, traversal[nameIndex].SourceRange())
diags = append(diags, nameDiags...)
if diags.HasErrors() {
return nil, diags
}
ret := &ProviderConfigRef{
Name: name,
NameRange: traversal[0].SourceRange(),
Name: name,
NameRange: traversal[nameIndex].SourceRange(),
KeyExpression: keyExpr,
}
if len(traversal) > 1 {
aliasStep, ok := traversal[1].(hcl.TraverseAttr)
if len(traversal) > aliasIndex {
aliasStep, ok := traversal[aliasIndex].(hcl.TraverseAttr)
if !ok {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider configuration reference",
Detail: "Provider name must either stand alone or be followed by a period and then a configuration alias.",
Subject: traversal[1].SourceRange().Ptr(),
Subject: traversal[aliasIndex].SourceRange().Ptr(),
})
return ret, diags
}
@ -731,6 +752,30 @@ func decodeProviderConfigRef(expr hcl.Expression, argName string) (*ProviderConf
ret.AliasRange = aliasStep.SourceRange().Ptr()
}
if len(traversal) > keyIndex {
indexStep, ok := traversal[keyIndex].(hcl.TraverseIndex)
if !ok {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider configuration reference",
Detail: "Provider name must either stand alone or be followed by a period and then a configuration alias.",
Subject: traversal[keyIndex].SourceRange().Ptr(),
})
return ret, diags
}
ret.KeyExpression = hcl.StaticExpr(indexStep.Key, traversal.SourceRange())
}
if len(ret.Alias) == 0 && ret.KeyExpression != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider configuration reference",
Detail: "Provider assignment requires an alias when specifying an instance key, in the form of provider.name[instance_key]",
Subject: traversal.SourceRange().Ptr(),
})
}
return ret, diags
}
@ -756,6 +801,39 @@ func (r *ProviderConfigRef) String() string {
return r.Name
}
func (r *ProviderConfigRef) InstanceValidation(blockType string, isInstanced bool) hcl.Diagnostics {
var diags hcl.Diagnostics
summary := fmt.Sprintf("Invalid %s provider configuration", blockType)
if r.KeyExpression != nil {
if r.Alias == "" {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: summary,
Detail: "An instance key can be specified only for a provider configuration which has an alias and uses for_each.",
Subject: r.KeyExpression.Range().Ptr(),
})
}
if !isInstanced {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: summary,
Detail: "An instance key can be specified only for a provider configuration that uses for_each.",
Subject: r.KeyExpression.Range().Ptr(),
})
}
} else if isInstanced {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: summary,
Detail: "A reference to a provider configuration which uses for_each requires an instance key. Passing a collection of provider instances into a child module is not allowed.",
Subject: r.NameRange.Ptr(),
})
}
return diags
}
var commonResourceAttributes = []hcl.AttributeSchema{
{
Name: "count",

View File

@ -16,8 +16,6 @@ import (
)
// This exercises most of the logic in StaticEvaluator and staticScopeData
//
//nolint:cyclop // it's a test
func TestStaticEvaluator_Evaluate(t *testing.T) {
// Synthetic file for building test components
testData := `

View File

@ -7,9 +7,8 @@ provider "test" {
arbitrary = true
# These are all reserved and should generate errors.
count = 3
count = 3
depends_on = ["foo.bar"]
for_each = ["a", "b"]
source = "foo.example.com/baz/bar"
lifecycle {}
locals {}

View File

@ -11,3 +11,8 @@ provider "bar" {
alias = "bar"
}
provider "baz" {
alias = "foo"
for_each = {"a": "first", "b": "second"}
}

View File

@ -59,6 +59,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
emptyResults,
@ -78,6 +79,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -105,6 +107,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -133,6 +136,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -161,6 +165,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -189,6 +194,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -217,6 +223,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("module.boo.module.hoo.foo.from"),
@ -225,6 +232,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -258,6 +266,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -287,6 +296,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -316,6 +326,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -344,6 +355,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("module.boo.foo.to[0]"),
@ -352,6 +364,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -386,6 +399,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("foo.to"),
@ -394,6 +408,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -428,6 +443,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("foo.to[0]"),
@ -436,6 +452,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -470,6 +487,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -499,6 +517,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("foo.from"),
@ -507,6 +526,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -542,6 +562,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("bar.from"),
@ -550,6 +571,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{
@ -584,6 +606,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("foo.from"),
@ -592,6 +615,7 @@ func TestApplyMoves(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerAddr,
addrs.NoKey,
)
}),
MoveResults{

View File

@ -99,41 +99,49 @@ func TestImpliedMoveStatements(t *testing.T) {
resourceAddr("formerly_count").Instance(addrs.IntKey(0)),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
resourceAddr("formerly_count").Instance(addrs.IntKey(1)),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
resourceAddr("now_count").Instance(addrs.NoKey),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
resourceAddr("formerly_count_explicit").Instance(addrs.IntKey(0)),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
resourceAddr("formerly_count_explicit").Instance(addrs.IntKey(1)),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
resourceAddr("now_count_explicit").Instance(addrs.NoKey),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
resourceAddr("now_for_each_formerly_count").Instance(addrs.IntKey(0)),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
resourceAddr("now_for_each_formerly_no_count").Instance(addrs.NoKey),
instObjState(),
providerAddr,
addrs.NoKey,
)
// This "ambiguous" resource is representing a rare but possible
@ -147,11 +155,13 @@ func TestImpliedMoveStatements(t *testing.T) {
resourceAddr("ambiguous").Instance(addrs.NoKey),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
resourceAddr("ambiguous").Instance(addrs.IntKey(0)),
instObjState(),
providerAddr,
addrs.NoKey,
)
// Add two resource nested in a module to ensure we find these
@ -160,11 +170,13 @@ func TestImpliedMoveStatements(t *testing.T) {
nestedResourceAddr("child", "formerly_count").Instance(addrs.IntKey(0)),
instObjState(),
providerAddr,
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
nestedResourceAddr("child", "now_count").Instance(addrs.NoKey),
instObjState(),
providerAddr,
addrs.NoKey,
)
})

View File

@ -45,6 +45,7 @@ func TestSession_basicState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -60,6 +61,7 @@ func TestSession_basicState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})

View File

@ -89,7 +89,7 @@ func (ms *Module) RemoveResource(addr addrs.Resource) {
//
// The provider address is a resource-wide setting and is updated for all other
// instances of the same resource as a side-effect of this call.
func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig, providerKey addrs.InstanceKey) {
rs := ms.Resource(addr.Resource)
// if the resource is nil and the object is nil, don't do anything!
// you'll probably just cause issues
@ -139,6 +139,7 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R
}
// Update the resource's ProviderConfig, in case the provider has updated
rs.ProviderConfig = provider
is.ProviderKey = providerKey
is.Current = obj
}
@ -158,11 +159,12 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R
// is overwritten. Set obj to nil to remove the deposed object altogether. If
// the instance is left with no objects after this operation then it will
// be removed from its containing resource altogether.
func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig, providerKey addrs.InstanceKey) {
ms.SetResourceProvider(addr.Resource, provider)
rs := ms.Resource(addr.Resource)
is := rs.EnsureInstance(addr.Key)
is.ProviderKey = providerKey
if obj != nil {
is.Deposed[key] = obj
} else {

View File

@ -99,6 +99,7 @@ func TestStatePersist(t *testing.T) {
addrs.AbsProviderConfig{
Provider: tfaddr.Provider{Namespace: "local"},
},
addrs.NoKey,
)
return s, func() {}
},

View File

@ -70,6 +70,11 @@ type ResourceInstance struct {
// replaced and are pending destruction due to the create_before_destroy
// lifecycle mode.
Deposed map[DeposedKey]*ResourceInstanceObjectSrc
// ProviderKey, in combination with Resource.ProviderConfig, represents
// the resource instance's provider configuration. This is only set
// when using provider iteration on resources or modules
ProviderKey addrs.InstanceKey
}
// NewResourceInstance constructs and returns a new ResourceInstance, ready to

View File

@ -118,8 +118,9 @@ func (i *ResourceInstance) DeepCopy() *ResourceInstance {
}
return &ResourceInstance{
Current: i.Current.DeepCopy(),
Deposed: deposed,
Current: i.Current.DeepCopy(),
Deposed: deposed,
ProviderKey: i.ProviderKey,
}
}

View File

@ -47,6 +47,7 @@ func TestState(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
@ -254,6 +255,7 @@ func TestStateDeepCopy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
rootModule.SetResourceInstanceCurrent(
addrs.Resource{
@ -288,6 +290,7 @@ func TestStateDeepCopy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
@ -326,6 +329,7 @@ func TestStateHasResourceInstanceObjects(t *testing.T) {
Status: ObjectReady,
},
providerConfig,
addrs.NoKey,
)
},
true,
@ -339,6 +343,7 @@ func TestStateHasResourceInstanceObjects(t *testing.T) {
Status: ObjectReady,
},
childModuleProviderConfig,
addrs.NoKey,
)
},
true,
@ -352,6 +357,7 @@ func TestStateHasResourceInstanceObjects(t *testing.T) {
Status: ObjectTainted,
},
providerConfig,
addrs.NoKey,
)
},
true,
@ -366,6 +372,7 @@ func TestStateHasResourceInstanceObjects(t *testing.T) {
Status: ObjectTainted,
},
providerConfig,
addrs.NoKey,
)
},
true,
@ -384,6 +391,7 @@ func TestStateHasResourceInstanceObjects(t *testing.T) {
Status: ObjectTainted,
},
providerConfig,
addrs.NoKey,
)
s := ss.Lock()
delete(s.Modules[""].Resources["test.foo"].Instances, addrs.NoKey)
@ -400,6 +408,7 @@ func TestStateHasResourceInstanceObjects(t *testing.T) {
Status: ObjectReady,
},
providerConfig,
addrs.NoKey,
)
},
false, // data resources aren't managed resources, so they don't count
@ -437,6 +446,7 @@ func TestState_MoveAbsResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Absolute(addrs.RootModuleInstance)
@ -504,6 +514,7 @@ func TestState_MoveAbsResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
cm.SetResourceInstanceCurrent(
addrs.Resource{
@ -520,6 +531,7 @@ func TestState_MoveAbsResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
@ -569,6 +581,7 @@ func TestState_MoveAbsResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
@ -615,6 +628,7 @@ func TestState_MoveAbsResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
@ -660,6 +674,7 @@ func TestState_MaybeMoveAbsResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Absolute(addrs.RootModuleInstance)
@ -700,6 +715,7 @@ func TestState_MoveAbsResourceInstance(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// src resource from the state above
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
@ -770,6 +786,7 @@ func TestState_MaybeMoveAbsResourceInstance(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// For a little extra fun, let's go from a resource to a resource instance: test_thing.foo to test_thing.bar[1]
@ -816,6 +833,7 @@ func TestState_MoveModuleInstance(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
dstModule := addrs.RootModuleInstance.Child("child", addrs.IntKey(3))
@ -863,6 +881,7 @@ func TestState_MaybeMoveModuleInstance(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
dst := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("b"))
@ -905,6 +924,7 @@ func TestState_MoveModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
moduleInstance := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("a"))
@ -924,6 +944,7 @@ func TestState_MoveModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
_, mc := srcModule.Call()
@ -977,6 +998,7 @@ func TestState_MoveModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
_, dstMC := addrs.RootModule.Child("child").Call()

View File

@ -90,18 +90,29 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
}
}
providerAddr, addrDiags := addrs.ParseAbsProviderConfigStr(rsV4.ProviderConfig)
diags.Append(addrDiags)
if addrDiags.HasErrors() {
// If ParseAbsProviderConfigStr returns an error, the state may have
// been written before Provider FQNs were introduced and the
// AbsProviderConfig string format will need normalization. If so,
// we treat it like a legacy provider (namespace "-") and let the
// provider installer handle detecting the FQN.
var legacyAddrDiags tfdiags.Diagnostics
providerAddr, legacyAddrDiags = addrs.ParseLegacyAbsProviderConfigStr(rsV4.ProviderConfig)
if legacyAddrDiags.HasErrors() {
continue
var providerAddr addrs.AbsProviderConfig
var addrDiags tfdiags.Diagnostics
if rsV4.ProviderConfig != "" {
providerAddr, addrDiags = addrs.ParseAbsProviderConfigStr(rsV4.ProviderConfig)
if addrDiags.HasErrors() {
// If ParseAbsProviderConfigStr returns an error, the state may have
// been written before Provider FQNs were introduced and the
// AbsProviderConfig string format will need normalization. If so,
// we treat it like a legacy provider (namespace "-") and let the
// provider installer handle detecting the FQN.
var legacyAddrDiags tfdiags.Diagnostics
providerAddr, legacyAddrDiags = addrs.ParseLegacyAbsProviderConfigStr(rsV4.ProviderConfig)
if legacyAddrDiags.HasErrors() {
// Neither parse formats are valid, let's report the original error
diags = diags.Append(addrDiags)
continue
}
// Valid legacy address, but may contain warnings
diags = diags.Append(legacyAddrDiags)
} else {
// Valid address, but may contain warnings
diags = diags.Append(addrDiags)
}
}
@ -110,6 +121,9 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
// Ensure the resource container object is present in the state.
ms.SetResourceProvider(rAddr, providerAddr)
// Keep track of instance providers for validation
var instanceProviders []addrs.AbsProviderConfig
for _, isV4 := range rsV4.Instances {
keyRaw := isV4.IndexKey
var key addrs.InstanceKey
@ -137,6 +151,30 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
key = addrs.NoKey
}
if isV4.ProviderConfig != "" && rsV4.ProviderConfig != "" {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Warning,
"Provider field conflict in state",
fmt.Sprintf("Resource %s has a provider address %s, as well as instance %s with provider address %s.", rAddr.Absolute(moduleAddr), rsV4.ProviderConfig, key, isV4.ProviderConfig),
))
}
if isV4.ProviderConfig == "" && rsV4.ProviderConfig == "" {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Provider field missing state",
fmt.Sprintf("Resource %s is missing a provider address, both on the resource and the resource instances.", rAddr.Absolute(moduleAddr)),
))
}
instanceProvider := providerAddr
instanceProviderKey := addrs.NoKey
if isV4.ProviderConfig != "" {
instanceProvider, instanceProviderKey, addrDiags = addrs.ParseAbsProviderConfigInstanceStr(isV4.ProviderConfig)
diags = diags.Append(addrDiags)
instanceProviders = append(instanceProviders, instanceProvider)
}
instAddr := rAddr.Instance(key)
obj := &states.ResourceInstanceObjectSrc{
@ -235,7 +273,7 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
continue
}
ms.SetResourceInstanceDeposed(instAddr, dk, obj, providerAddr)
ms.SetResourceInstanceDeposed(instAddr, dk, obj, instanceProvider, instanceProviderKey)
default:
is := ms.ResourceInstance(instAddr)
if is.HasCurrent() {
@ -247,16 +285,21 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
continue
}
ms.SetResourceInstanceCurrent(instAddr, obj, providerAddr)
ms.SetResourceInstanceCurrent(instAddr, obj, instanceProvider, instanceProviderKey)
}
}
// We repeat this after creating the instances because
// SetResourceInstanceCurrent automatically resets this metadata based
// on the incoming objects. That behavior is useful when we're making
// piecemeal updates to the state during an apply, but when we're
// reading the state file we want to reflect its contents exactly.
ms.SetResourceProvider(rAddr, providerAddr)
// Validate instance providers
for i := 1; i < len(instanceProviders); i++ {
if instanceProviders[i-1].String() != instanceProviders[i].String() {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Provider instance field conflict in state",
fmt.Sprintf("Resource %s has instances with different provider addresses: %q != %q.", rAddr.Absolute(moduleAddr), instanceProviders[i-1], instanceProviders[i]),
))
break
}
}
}
// The root module is special in that we persist its attributes and thus
@ -389,12 +432,25 @@ func writeStateV4(file *File, w io.Writer, enc encryption.StateEncryption) tfdia
continue
}
hasProviderInstanceKeys := false
for _, is := range rs.Instances {
if is.ProviderKey != addrs.NoKey {
hasProviderInstanceKeys = true
break
}
}
var providerConfig string
if !hasProviderInstanceKeys {
providerConfig = rs.ProviderConfig.String()
}
sV4.Resources = append(sV4.Resources, resourceStateV4{
Module: moduleAddr.String(),
Mode: mode,
Type: resourceAddr.Type,
Name: resourceAddr.Name,
ProviderConfig: rs.ProviderConfig.String(),
ProviderConfig: providerConfig,
Instances: []instanceObjectStateV4{},
})
rsV4 := &(sV4.Resources[len(sV4.Resources)-1])
@ -404,7 +460,7 @@ func writeStateV4(file *File, w io.Writer, enc encryption.StateEncryption) tfdia
var objDiags tfdiags.Diagnostics
rsV4.Instances, objDiags = appendInstanceObjectStateV4(
rs, is, key, is.Current, states.NotDeposed,
rsV4.Instances,
rsV4.Instances, hasProviderInstanceKeys,
)
diags = diags.Append(objDiags)
}
@ -412,7 +468,7 @@ func writeStateV4(file *File, w io.Writer, enc encryption.StateEncryption) tfdia
var objDiags tfdiags.Diagnostics
rsV4.Instances, objDiags = appendInstanceObjectStateV4(
rs, is, key, obj, dk,
rsV4.Instances,
rsV4.Instances, hasProviderInstanceKeys,
)
diags = diags.Append(objDiags)
}
@ -452,7 +508,7 @@ func writeStateV4(file *File, w io.Writer, enc encryption.StateEncryption) tfdia
return diags
}
func appendInstanceObjectStateV4(rs *states.Resource, is *states.ResourceInstance, key addrs.InstanceKey, obj *states.ResourceInstanceObjectSrc, deposed states.DeposedKey, isV4s []instanceObjectStateV4) ([]instanceObjectStateV4, tfdiags.Diagnostics) {
func appendInstanceObjectStateV4(rs *states.Resource, is *states.ResourceInstance, key addrs.InstanceKey, obj *states.ResourceInstanceObjectSrc, deposed states.DeposedKey, isV4s []instanceObjectStateV4, hasProviderInstanceKeys bool) ([]instanceObjectStateV4, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var status string
@ -495,6 +551,11 @@ func appendInstanceObjectStateV4(rs *states.Resource, is *states.ResourceInstanc
}
}
var providerConfig string
if hasProviderInstanceKeys {
providerConfig = rs.ProviderConfig.InstanceString(is.ProviderKey)
}
// Extract paths from path value marks
var paths []cty.Path
for _, vm := range obj.AttrSensitivePaths {
@ -509,6 +570,7 @@ func appendInstanceObjectStateV4(rs *states.Resource, is *states.ResourceInstanc
IndexKey: rawKey,
Deposed: string(deposed),
Status: status,
ProviderConfig: providerConfig,
SchemaVersion: obj.SchemaVersion,
AttributesFlat: obj.AttrsFlat,
AttributesRaw: obj.AttrsJSON,
@ -704,20 +766,23 @@ type outputStateV4 struct {
Sensitive bool `json:"sensitive,omitempty"`
}
// Note: the ProviderConfig field is only set on either the resource or the resource instance object
// It should never be set on both
type resourceStateV4 struct {
Module string `json:"module,omitempty"`
Mode string `json:"mode"`
Type string `json:"type"`
Name string `json:"name"`
EachMode string `json:"each,omitempty"`
ProviderConfig string `json:"provider"`
ProviderConfig string `json:"provider,omitempty"`
Instances []instanceObjectStateV4 `json:"instances"`
}
type instanceObjectStateV4 struct {
IndexKey interface{} `json:"index_key,omitempty"`
Status string `json:"status,omitempty"`
Deposed string `json:"deposed,omitempty"`
IndexKey interface{} `json:"index_key,omitempty"`
Status string `json:"status,omitempty"`
Deposed string `json:"deposed,omitempty"`
ProviderConfig string `json:"provider,omitempty"`
SchemaVersion uint64 `json:"schema_version"`
AttributesRaw json.RawMessage `json:"attributes,omitempty"`

View File

@ -273,12 +273,12 @@ func (s *SyncState) RemoveResourceIfEmpty(addr addrs.AbsResource) bool {
//
// If the containing module for this resource or the resource itself are not
// already tracked in state then they will be added as a side-effect.
func (s *SyncState) SetResourceInstanceCurrent(addr addrs.AbsResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
func (s *SyncState) SetResourceInstanceCurrent(addr addrs.AbsResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig, providerKey addrs.InstanceKey) {
s.lock.Lock()
defer s.lock.Unlock()
ms := s.state.EnsureModule(addr.Module)
ms.SetResourceInstanceCurrent(addr.Resource, obj.DeepCopy(), provider)
ms.SetResourceInstanceCurrent(addr.Resource, obj.DeepCopy(), provider, providerKey)
s.maybePruneModule(addr.Module)
}
@ -305,12 +305,12 @@ func (s *SyncState) SetResourceInstanceCurrent(addr addrs.AbsResourceInstance, o
//
// If the containing module for this resource or the resource itself are not
// already tracked in state then they will be added as a side-effect.
func (s *SyncState) SetResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
func (s *SyncState) SetResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig, providerKey addrs.InstanceKey) {
s.lock.Lock()
defer s.lock.Unlock()
ms := s.state.EnsureModule(addr.Module)
ms.SetResourceInstanceDeposed(addr.Resource, key, obj.DeepCopy(), provider)
ms.SetResourceInstanceDeposed(addr.Resource, key, obj.DeepCopy(), provider, providerKey)
s.maybePruneModule(addr.Module)
}
@ -443,7 +443,7 @@ func (s *SyncState) RemovePlannedResourceInstanceObjects() {
if is.Current != nil && is.Current.Status == ObjectPlanned {
// Setting the current instance to nil removes it from the
// state altogether if there are not also deposed instances.
ms.SetResourceInstanceCurrent(instAddr, nil, rs.ProviderConfig)
ms.SetResourceInstanceCurrent(instAddr, nil, rs.ProviderConfig, addrs.NoKey)
}
for dk, obj := range is.Deposed {

View File

@ -294,13 +294,15 @@ func (c *Context) watchStop(walker *ContextGraphWalker) (chan struct{}, <-chan s
// Copy the providers so that a misbehaved blocking Stop doesn't
// completely hang OpenTofu.
walker.providerLock.Lock()
ps := make([]providers.Interface, 0, len(walker.providerCache))
for _, p := range walker.providerCache {
ps = append(ps, p)
toStop := make([]providers.Interface, 0, len(walker.providerCache))
for _, providerMap := range walker.providerCache {
for _, provider := range providerMap {
toStop = append(toStop, provider)
}
}
defer walker.providerLock.Unlock()
for _, p := range ps {
for _, p := range toStop {
// We ignore the error for now since there isn't any reasonable
// action to take if there is an error here, since the stop is still
// advisory: OpenTofu will exit once the graph node completes.

View File

@ -21,11 +21,14 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/checks"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/encryption"
"github.com/opentofu/opentofu/internal/lang/marks"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/states/statefile"
"github.com/opentofu/opentofu/internal/tfdiags"
"github.com/opentofu/opentofu/version"
)
// Test that the PreApply hook is called with the correct deposed key
@ -46,6 +49,7 @@ func TestContext2Apply_createBeforeDestroy_deposedKeyPreApply(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -55,6 +59,7 @@ func TestContext2Apply_createBeforeDestroy_deposedKeyPreApply(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
hook := new(MockHook)
@ -229,7 +234,7 @@ resource "test_instance" "a" {
s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"a","value":"old","type":"test"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
// test_instance.b depended on test_instance.a, and therefor should be
// destroyed before any changes to test_instance.a
@ -237,7 +242,7 @@ resource "test_instance" "a" {
AttrsJSON: []byte(`{"id":"b"}`),
Status: states.ObjectReady,
Dependencies: []addrs.ConfigResource{addrA.ContainingResource().Config()},
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
@ -279,6 +284,7 @@ func TestApply_updateDependencies(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
binAddr.Resource,
@ -290,6 +296,7 @@ func TestApply_updateDependencies(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
bazAddr.Resource,
@ -302,6 +309,7 @@ func TestApply_updateDependencies(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
barAddr.Resource,
@ -310,6 +318,7 @@ func TestApply_updateDependencies(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
m := testModuleInline(t, map[string]string{
@ -428,7 +437,7 @@ resource "test_resource" "b" {
},
},
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey,
)
})
@ -587,6 +596,7 @@ resource "test_object" "x" {
AttrsJSON: []byte(`{"test_string":"deposed"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -765,6 +775,7 @@ resource "test_object" "b" {
AttrsJSON: []byte(`{"test_string":"ok"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.b").Resource,
@ -773,6 +784,7 @@ resource "test_object" "b" {
AttrsJSON: []byte(`{"test_string":"ok"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1475,6 +1487,7 @@ resource "test_object" "x" {
AttrsJSON: []byte(`{"test_string":"ok"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1525,6 +1538,7 @@ resource "test_object" "y" {
AttrsJSON: []byte(`{"test_string":"x"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1681,6 +1695,7 @@ output "from_resource" {
AttrsJSON: []byte(`{"test_string":"wrong_val"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1736,6 +1751,7 @@ output "from_resource" {
AttrsJSON: []byte(`{"test_string":"wrong val"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
mod.SetOutputValue("from_resource", cty.StringVal("wrong val"), false)
@ -1806,6 +1822,7 @@ resource "test_object" "y" {
AttrsJSON: []byte(`{"test_string":"y"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2318,6 +2335,7 @@ func TestContext2Apply_forgetOrphanAndDeposed(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr(addr).Resource,
@ -2328,6 +2346,7 @@ func TestContext2Apply_forgetOrphanAndDeposed(t *testing.T) {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -2358,6 +2377,372 @@ func TestContext2Apply_forgetOrphanAndDeposed(t *testing.T) {
}
}
func TestContext2Apply_providerExpandWithTargetOrExclude(t *testing.T) {
// This test is covering a potentially-tricky interaction between the
// logic that updates the provider instance references for resource
// instances in state snapshots, and the -target/-exclude features which
// cause OpenTofu to skip visiting certain objects.
//
// The main priority is that we never leave the final state snapshot
// in a form that would cause errors or incorrect behavior on a future
// plan/apply round. This test covers the current way we resolve the
// ambiguity at the time of writing -- by updating the provider
// instance addresses of all instances of any resource where at least
// one instance is included in the plan -- but if future changes make
// this test fail then it might be valid to introduce a different rule
// as long as it still guarantees to create a valid final state snapshot.
rsrcFirst := addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "mock",
Name: "first",
}.Absolute(addrs.RootModuleInstance)
rsrcFirstInstA := rsrcFirst.Instance(addrs.StringKey("a"))
rsrcFirstInstB := rsrcFirst.Instance(addrs.StringKey("b"))
rsrcSecond := addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "mock",
Name: "second",
}.Absolute(addrs.RootModuleInstance)
rsrcSecondInstA := rsrcSecond.Instance(addrs.StringKey("a"))
rsrcSecondInstB := rsrcSecond.Instance(addrs.StringKey("b"))
// We use the same test sequence for both -target and -exclude, with
// makeStep2PlanOpts providing whichever filter is appropriate for
// each test.
// For correct operation the plan options must cause OpenTofu to
// skip both instances of mock.second and visit at least one instance
// of mock.first.
runTest := func(t *testing.T, makeStep2PlanOpts func(plans.Mode) *PlanOpts) {
mockProviderAddr := addrs.NewBuiltInProvider("mock")
providerConfigBefore := addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: mockProviderAddr,
Alias: "before",
}
providerConfigAfter := addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: mockProviderAddr,
Alias: "after",
}
normalPlanOpts := &PlanOpts{
Mode: plans.NormalMode,
}
p := &MockProvider{
GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
Provider: providers.Schema{
Block: &configschema.Block{},
},
ResourceTypes: map[string]providers.Schema{
"mock": {
Block: &configschema.Block{},
},
},
},
}
// For this particular test we'll also save state snapshots in JSON format,
// so that we're exercising the state snapshot writer and reader in similar way
// to how OpenTofu CLI would do it, in case its normalization rules and
// consistency checks cause any problems that we can't notice when we're just
// passing pointers to the live data structure.
var stateJSON []byte
readStateSnapshot := func(t *testing.T) *states.State {
t.Helper()
if len(stateJSON) == 0 {
return states.NewState()
}
ret, err := statefile.Read(bytes.NewReader(stateJSON), encryption.StateEncryptionDisabled())
if err != nil {
t.Fatalf("failed to read latest state snapshot: %s", err)
}
return ret.State
}
writeStateSnapshot := func(t *testing.T, state *states.State) {
t.Helper()
f := &statefile.File{
State: state,
TerraformVersion: version.SemVer,
}
buf := bytes.NewBuffer(nil)
err := statefile.Write(f, buf, encryption.StateEncryptionDisabled())
if err != nil {
t.Fatalf("failed to write new state snapshot: %s", err)
}
stateJSON = buf.Bytes()
}
assertResourceInstanceProviderInstance := func(
t *testing.T,
state *states.State,
addr addrs.AbsResourceInstance,
wantConfigAddr addrs.AbsProviderConfig,
wantKey addrs.InstanceKey,
) {
t.Helper()
rsrcAddr := addr.ContainingResource()
r := state.Resource(rsrcAddr)
if r == nil {
t.Fatalf("state has no record of %s", rsrcAddr)
}
ri := r.Instance(addr.Resource.Key)
if ri == nil {
t.Fatalf("state has no record of %s", addr)
}
ok := true
if got, want := r.ProviderConfig, wantConfigAddr; got.String() != want.String() {
t.Errorf(
"%s has incorrect provider configuration address\ngot: %s\nwant: %s",
rsrcAddr, got, want,
)
ok = false
}
if got, want := ri.ProviderKey, wantKey; got != want {
t.Errorf(
"%s has incorrect provider instance key\ngot: %s\nwant: %s",
addr, got, want,
)
ok = false
}
if !ok {
t.FailNow()
}
}
t.Log("Step 1: Apply with a multi-instance provider config and two resources to create our initial state")
{
state := readStateSnapshot(t)
m := testModuleInline(t, map[string]string{
"main.tf": `
terraform {
required_providers {
mock = {
source = "terraform.io/builtin/mock"
}
}
}
locals {
instances = toset(["a", "b"])
}
provider "mock" {
alias = "before"
for_each = local.instances
}
resource "mock" "first" {
# NOTE: This is a bad example to follow in a real config,
# since it would not be possible to remove elements from
# local.instances without encountering an error. We don't
# intend to do that for this test, though.
for_each = local.instances
provider = mock.before[each.key]
}
resource "mock" "second" {
for_each = local.instances
provider = mock.before[each.key]
}
`,
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("mock"): testProviderFuncFixed(p),
},
})
plan, diags := ctx.Plan(m, state, normalPlanOpts)
assertNoErrors(t, diags)
newState, diags := ctx.Apply(plan, m)
assertNoErrors(t, diags)
assertResourceInstanceProviderInstance(
t, newState,
rsrcFirstInstA,
providerConfigBefore, addrs.StringKey("a"),
)
assertResourceInstanceProviderInstance(
t, newState,
rsrcFirstInstB,
providerConfigBefore, addrs.StringKey("b"),
)
assertResourceInstanceProviderInstance(
t, newState,
rsrcSecondInstA,
providerConfigBefore, addrs.StringKey("a"),
)
assertResourceInstanceProviderInstance(
t, newState,
rsrcSecondInstB,
providerConfigBefore, addrs.StringKey("b"),
)
writeStateSnapshot(t, newState)
}
t.Log("Step 2: Change the provider configuration address in config but then apply with some graph nodes excluded")
{
state := readStateSnapshot(t)
m := testModuleInline(t, map[string]string{
"main.tf": `
terraform {
required_providers {
mock = {
source = "terraform.io/builtin/mock"
}
}
}
locals {
instances = toset(["a", "b"])
}
provider "mock" {
alias = "after"
for_each = local.instances
}
resource "mock" "first" {
for_each = local.instances
provider = mock.after[each.key]
}
resource "mock" "second" {
for_each = local.instances
provider = mock.after[each.key]
}
`,
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("mock"): testProviderFuncFixed(p),
},
})
plan, diags := ctx.Plan(m, state, makeStep2PlanOpts(plans.NormalMode))
assertNoErrors(t, diags)
newState, diags := ctx.Apply(plan, m)
assertNoErrors(t, diags)
// Because makeStep2PlanOpts told us to retain at least one
// instance of mock.first, both instances should've been
// updated to refer to the new provider instance addresses.
assertResourceInstanceProviderInstance(
t, newState,
rsrcFirstInstA,
providerConfigAfter, addrs.StringKey("a"),
)
assertResourceInstanceProviderInstance(
t, newState,
rsrcFirstInstB,
providerConfigAfter, addrs.StringKey("b"),
)
// Because makeStep2PlanOpts told us to exclude both instances
// of mock.second, they continue to refer to the original
// provider instance addresses.
assertResourceInstanceProviderInstance(
t, newState,
rsrcSecondInstA,
providerConfigBefore, addrs.StringKey("a"),
)
assertResourceInstanceProviderInstance(
t, newState,
rsrcSecondInstB,
providerConfigBefore, addrs.StringKey("b"),
)
writeStateSnapshot(t, newState)
}
t.Log("Step 3: Remove the mock.first resource completely to destroy both instances using the updated provider config")
{
state := readStateSnapshot(t)
m := testModuleInline(t, map[string]string{
"main.tf": `
terraform {
required_providers {
mock = {
source = "terraform.io/builtin/mock"
}
}
}
locals {
instances = toset(["a", "b"])
}
provider "mock" {
alias = "after"
for_each = local.instances
}
# mock.first intentionally removed, which should succeed
# because the incoming state snapshot should remember that
# it was associated with mock.after .
resource "mock" "second" {
for_each = local.instances
provider = mock.after[each.key]
}
`,
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("mock"): testProviderFuncFixed(p),
},
})
plan, diags := ctx.Plan(m, state, normalPlanOpts)
assertNoErrors(t, diags)
newState, diags := ctx.Apply(plan, m)
assertNoErrors(t, diags)
// The whole resource state for mock.first should've been removed now.
if rs := newState.Resource(rsrcFirst); rs != nil {
t.Errorf("final state still contains %s", rsrcFirst)
}
// We didn't target or exclude anything this time, so we
// should now have both instances of mock.second updated
// to refer to the new provider config.
assertResourceInstanceProviderInstance(
t, newState,
rsrcSecondInstA,
providerConfigAfter, addrs.StringKey("a"),
)
assertResourceInstanceProviderInstance(
t, newState,
rsrcSecondInstB,
providerConfigAfter, addrs.StringKey("b"),
)
writeStateSnapshot(t, newState)
}
}
t.Run("with target", func(t *testing.T) {
runTest(t, func(planMode plans.Mode) *PlanOpts {
return &PlanOpts{
Mode: planMode,
Targets: []addrs.Targetable{
rsrcFirstInstA,
},
}
})
})
t.Run("with exclude", func(t *testing.T) {
runTest(t, func(planMode plans.Mode) *PlanOpts {
return &PlanOpts{
Mode: planMode,
Excludes: []addrs.Targetable{
rsrcSecondInstA,
rsrcSecondInstB,
},
}
})
})
}
// All exclude flag tests in this file, from here forward, are inspired by some counterpart target flag test
// either from this file or from context_apply_test.go
func TestContext2Apply_moduleProviderAliasExcludes(t *testing.T) {
@ -3000,6 +3385,7 @@ func TestContext2Apply_excludedDestroyCountDeps(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-bcd345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -3008,6 +3394,7 @@ func TestContext2Apply_excludedDestroyCountDeps(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-cde345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -3016,6 +3403,7 @@ func TestContext2Apply_excludedDestroyCountDeps(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-def345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -3025,6 +3413,7 @@ func TestContext2Apply_excludedDestroyCountDeps(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3074,6 +3463,7 @@ func TestContext2Apply_excludedDependentDestroyCountDeps(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-bcd345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -3082,6 +3472,7 @@ func TestContext2Apply_excludedDependentDestroyCountDeps(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-cde345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -3090,6 +3481,7 @@ func TestContext2Apply_excludedDependentDestroyCountDeps(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-def345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -3099,6 +3491,7 @@ func TestContext2Apply_excludedDependentDestroyCountDeps(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3154,6 +3547,7 @@ func TestContext2Apply_excludedDestroyModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-bcd345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -3162,6 +3556,7 @@ func TestContext2Apply_excludedDestroyModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
child.SetResourceInstanceCurrent(
@ -3171,6 +3566,7 @@ func TestContext2Apply_excludedDestroyModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-bcd345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -3179,6 +3575,7 @@ func TestContext2Apply_excludedDestroyModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3230,31 +3627,37 @@ func TestContext2Apply_excludedDestroyCountIndex(t *testing.T) {
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
foo,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
foo,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
foo,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
bar,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
bar,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[2]").Resource,
bar,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3552,6 +3955,7 @@ func TestContext2Apply_excludedResourceOrphanModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"abc","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3604,6 +4008,7 @@ func TestContext2Apply_excludedOrphanModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"abc","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3654,6 +4059,7 @@ func TestContext2Apply_excludedWithTaintedInState(t *testing.T) {
AttrsJSON: []byte(`{"id":"ifailedprovisioners"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{

View File

@ -472,7 +472,7 @@ check "error" {
addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
})
}, addrs.NoKey)
}),
plan: map[string]checksTestingStatus{
"error": {
@ -572,7 +572,7 @@ check "passing" {
addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
})
}, addrs.NoKey)
}),
plan: map[string]checksTestingStatus{
"passing": {

View File

@ -462,6 +462,7 @@ func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.child")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
child.SetResourceInstanceCurrent(
@ -471,6 +472,7 @@ func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) {
AttrsJSON: []byte(`{"id":"child"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
{
@ -944,6 +946,7 @@ func TestContext2Apply_createBeforeDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -1013,6 +1016,7 @@ func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) {
CreateBeforeDestroy: true,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -1023,6 +1027,7 @@ func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) {
Dependencies: []addrs.ConfigResource{fooAddr.ContainingResource().Config()},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1072,6 +1077,7 @@ func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo").Resource,
@ -1080,6 +1086,7 @@ func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo", "require_new": "abc"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1133,6 +1140,7 @@ func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
var actual []cty.Value
@ -1194,6 +1202,7 @@ func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
@ -1203,6 +1212,7 @@ func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
@ -1211,6 +1221,7 @@ func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
@ -1220,6 +1231,7 @@ func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1271,6 +1283,7 @@ func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -1280,6 +1293,7 @@ func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1321,6 +1335,7 @@ func TestContext2Apply_destroyComputed(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo", "output": "value"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -1367,6 +1382,7 @@ func testContext2Apply_destroyDependsOn(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo").Resource,
@ -1376,6 +1392,7 @@ func testContext2Apply_destroyDependsOn(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
// Record the order we see Apply
@ -1432,6 +1449,7 @@ func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -1457,6 +1475,7 @@ func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// It is possible for this to be racy, so we loop a number of times
@ -1526,6 +1545,7 @@ func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
addrs.Resource{
@ -1551,6 +1571,7 @@ func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// It is possible for this to be racy, so we loop a number of times
@ -1663,6 +1684,7 @@ func TestContext2Apply_destroyData(t *testing.T) {
AttrsJSON: []byte(`{"id":"-"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/null"]`),
addrs.NoKey,
)
hook := &testHook{}
@ -1722,6 +1744,7 @@ func TestContext2Apply_destroySkipsCBD(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -1730,6 +1753,7 @@ func TestContext2Apply_destroySkipsCBD(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1768,6 +1792,7 @@ func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -1844,6 +1869,7 @@ func getContextForApply_destroyCrossProviders(t *testing.T, m *configs.Config, p
AttrsJSON: []byte(`{"id":"test"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
child.SetResourceInstanceCurrent(
@ -1853,6 +1879,7 @@ func getContextForApply_destroyCrossProviders(t *testing.T, m *configs.Config, p
AttrsJSON: []byte(`{"id": "vpc-aaabbb12", "value":"test"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2199,6 +2226,7 @@ func TestContext2Apply_countDecrease(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -2207,6 +2235,7 @@ func TestContext2Apply_countDecrease(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -2215,6 +2244,7 @@ func TestContext2Apply_countDecrease(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2249,6 +2279,7 @@ func TestContext2Apply_countDecreaseToOneX(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -2257,6 +2288,7 @@ func TestContext2Apply_countDecreaseToOneX(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -2265,6 +2297,7 @@ func TestContext2Apply_countDecreaseToOneX(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2319,6 +2352,7 @@ func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
@ -2327,6 +2361,7 @@ func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz", "type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2395,6 +2430,7 @@ func TestContext2Apply_countTainted(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "type": "aws_instance", "foo": "foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -2652,6 +2688,7 @@ func TestContext2Apply_moduleDestroyOrder(t *testing.T) {
AttrsJSON: []byte(`{"id":"a"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceCurrent(
@ -2662,6 +2699,7 @@ func TestContext2Apply_moduleDestroyOrder(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.a")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2787,7 +2825,7 @@ func TestContext2Apply_orphanResource(t *testing.T) {
s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"foo"}`),
}, providerAddr)
}, providerAddr, addrs.NoKey)
})
if state.String() != want.String() {
@ -2859,6 +2897,7 @@ func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2922,6 +2961,7 @@ func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2962,6 +3002,7 @@ func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3131,6 +3172,7 @@ func TestContext2Apply_moduleProviderCloseNested(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3168,6 +3210,7 @@ func TestContext2Apply_moduleVarRefExisting(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4453,6 +4496,7 @@ func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","require_new":"abc"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4492,6 +4536,7 @@ func TestContext2Apply_error_createBeforeDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "require_new": "abc","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4538,6 +4583,7 @@ func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4596,6 +4642,7 @@ func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
p.PlanResourceChangeFn = testDiffFn
@ -4885,6 +4932,7 @@ func TestContext2Apply_provisionerDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4932,6 +4980,7 @@ func TestContext2Apply_provisionerDestroyFail(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4996,6 +5045,7 @@ func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5063,6 +5113,7 @@ func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5129,6 +5180,7 @@ func TestContext2Apply_provisionerDestroyTainted(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5575,6 +5627,7 @@ func TestContext2Apply_outputDiffVars(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5796,6 +5849,7 @@ func TestContext2Apply_destroyNestedModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5834,6 +5888,7 @@ func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -6233,6 +6288,7 @@ func TestContext2Apply_destroyOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -6271,6 +6327,7 @@ func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -6391,6 +6448,7 @@ func TestContext2Apply_errorDestroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
@ -6523,6 +6581,7 @@ func TestContext2Apply_errorUpdateNullNew(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
@ -6573,6 +6632,7 @@ func TestContext2Apply_errorPartial(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -6657,6 +6717,7 @@ func TestContext2Apply_hookOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -6896,6 +6957,7 @@ func TestContext2Apply_taintX(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -6942,6 +7004,7 @@ func TestContext2Apply_taintDep(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -6951,6 +7014,7 @@ func TestContext2Apply_taintDep(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -6993,6 +7057,7 @@ func TestContext2Apply_taintDepRequiresNew(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -7002,6 +7067,7 @@ func TestContext2Apply_taintDepRequiresNew(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7243,6 +7309,7 @@ func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-bcd345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -7252,6 +7319,7 @@ func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7293,6 +7361,7 @@ func TestContext2Apply_targetedDestroyModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-bcd345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -7301,6 +7370,7 @@ func TestContext2Apply_targetedDestroyModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
child.SetResourceInstanceCurrent(
@ -7310,6 +7380,7 @@ func TestContext2Apply_targetedDestroyModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-bcd345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -7318,6 +7389,7 @@ func TestContext2Apply_targetedDestroyModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7376,31 +7448,37 @@ func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) {
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
foo,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
foo,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
foo,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
bar,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
bar,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[2]").Resource,
bar,
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7654,6 +7732,7 @@ func TestContext2Apply_targetedResourceOrphanModule(t *testing.T) {
AttrsJSON: []byte(`{"id":"abc","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7889,6 +7968,7 @@ func TestContext2Apply_createBefore_depends(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
@ -7915,6 +7995,7 @@ func TestContext2Apply_createBefore_depends(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -8017,6 +8098,7 @@ func TestContext2Apply_singleDestroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
@ -8043,6 +8125,7 @@ func TestContext2Apply_singleDestroy(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -8227,6 +8310,7 @@ func TestContext2Apply_targetedWithTaintedInState(t *testing.T) {
AttrsJSON: []byte(`{"id":"ifailedprovisioners"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -8360,6 +8444,7 @@ func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123","ami":"ami-abcd1234"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -8368,6 +8453,7 @@ func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-bcd234","ami":"i-bcd234"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_eip.foo[0]").Resource,
@ -8386,6 +8472,7 @@ func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_eip.foo[1]").Resource,
@ -8404,6 +8491,7 @@ func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -8830,6 +8918,7 @@ func TestContext2Apply_destroyWithLocals(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetOutputValue("name", cty.StringVal("test-bar"), false)
@ -8925,6 +9014,7 @@ func TestContext2Apply_destroyWithProviders(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"].baz`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -8979,6 +9069,7 @@ func TestContext2Apply_providersFromState(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
aliasedProviderState := states.NewState()
@ -8990,6 +9081,7 @@ func TestContext2Apply_providersFromState(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"].bar`),
addrs.NoKey,
)
moduleProviderState := states.NewState()
@ -9001,6 +9093,7 @@ func TestContext2Apply_providersFromState(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`module.child.provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
for _, tc := range []struct {
@ -9080,6 +9173,7 @@ func TestContext2Apply_plannedInterpolatedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -9130,6 +9224,7 @@ func TestContext2Apply_plannedDestroyInterpolatedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.a[1]").Resource,
@ -9138,6 +9233,7 @@ func TestContext2Apply_plannedDestroyInterpolatedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetOutputValue("out", cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("foo")}), false)
@ -9193,6 +9289,7 @@ func TestContext2Apply_scaleInMultivarRef(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.two").Resource,
@ -9201,6 +9298,7 @@ func TestContext2Apply_scaleInMultivarRef(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -9356,6 +9454,7 @@ func TestContext2Apply_issue19908(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -9473,6 +9572,7 @@ func TestContext2Apply_moduleReplaceCycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
modB := state.EnsureModule(addrs.RootModuleInstance.Child("b", addrs.NoKey))
@ -9490,6 +9590,7 @@ func TestContext2Apply_moduleReplaceCycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
aBefore, _ := plans.NewDynamicValue(
@ -9612,6 +9713,7 @@ func TestContext2Apply_destroyDataCycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("null"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -9637,6 +9739,7 @@ func TestContext2Apply_destroyDataCycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -9652,6 +9755,7 @@ func TestContext2Apply_destroyDataCycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("null"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
Providers := map[addrs.Provider]providers.Factory{
@ -9759,6 +9863,7 @@ func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -9774,6 +9879,7 @@ func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -9789,6 +9895,7 @@ func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
Providers := map[addrs.Provider]providers.Factory{
@ -9964,6 +10071,7 @@ func TestContext2Apply_cbdCycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -9989,6 +10097,7 @@ func TestContext2Apply_cbdCycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -10004,6 +10113,7 @@ func TestContext2Apply_cbdCycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
Providers := map[addrs.Provider]providers.Factory{
@ -11237,6 +11347,7 @@ locals {
CreateBeforeDestroy: true,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.a[1]").Resource,
@ -11247,6 +11358,7 @@ locals {
CreateBeforeDestroy: true,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.b").Resource,
@ -11257,6 +11369,7 @@ locals {
CreateBeforeDestroy: true,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.c").Resource,
@ -11270,6 +11383,7 @@ locals {
CreateBeforeDestroy: true,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
p := testProvider("test")
@ -12181,6 +12295,7 @@ resource "test_resource" "foo" {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -12724,7 +12839,7 @@ func TestContext2Apply_errorRestorePrivateData(t *testing.T) {
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"foo"}`),
Private: []byte("private"),
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
@ -12769,7 +12884,7 @@ func TestContext2Apply_errorRestoreStatus(t *testing.T) {
AttrsJSON: []byte(`{"test_string":"foo"}`),
Private: []byte("private"),
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.b")},
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{

View File

@ -635,18 +635,126 @@ variable "obfmod" {
},
})
diags := ctx.Validate(m)
_, diags := ctx.Plan(m, nil, nil)
if !diags.HasErrors() {
t.Fatal("Expected error!")
}
expected := `Unknown provider function: Provider "module.mod.provider[\"registry.opentofu.org/hashicorp/aws\"]" does not have a function "arn_parse_custom" or has not been configured`
expected := `Function not found in provider: Function "provider::aws::arn_parse_custom" was not registered by provider`
if expected != diags.Err().Error() {
t.Fatalf("Expected error %q, got %q", expected, diags.Err().Error())
}
if p.GetFunctionsCalled {
t.Fatalf("Unexpected function call")
if !p.GetFunctionsCalled {
t.Fatalf("Expected function call")
}
if p.CallFunctionCalled {
t.Fatalf("Unexpected function call")
}
}
// Defaulted stub provider
func TestContext2Functions_providerFunctionsForEachCount(t *testing.T) {
p := testProvider("aws")
addr := addrs.ImpliedProviderForUnqualifiedType("aws")
// Explicitly non-parallel
t.Setenv("foo", "bar")
defer providers.SchemaCache.Remove(addr)
p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
Functions: map[string]providers.FunctionSpec{
"arn_parse": providers.FunctionSpec{
Parameters: []providers.FunctionParameterSpec{{
Name: "arn",
Type: cty.String,
}},
Return: cty.Bool,
},
},
}
p.CallFunctionResponse = &providers.CallFunctionResponse{
Result: cty.True,
}
// SchemaCache is initialzed earlier on in the command package
providers.SchemaCache.Set(addr, *p.GetProviderSchemaResponse)
m := testModuleInline(t, map[string]string{
"main.tf": `
provider "aws" {
for_each = {"a": 1, "b": 2}
alias = "iter"
}
module "mod" {
source = "./mod"
for_each = {"a": 1, "b": 2}
providers = {
aws = aws.iter[each.key]
}
}
`,
"mod/mod.tf": `
terraform {
required_providers {
aws = ">=5.70.0"
}
}
variable "obfmod" {
type = object({
arns = optional(list(string))
})
description = "Configuration for xxx."
validation {
condition = alltrue([
for arn in var.obfmod.arns: can(provider::aws::arn_parse(arn))
])
error_message = "All arns MUST BE a valid AWS ARN format."
}
default = {
arns = [
"arn:partition:service:region:account-id:resource-id",
]
}
}
`,
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
diags := ctx.Validate(m)
if diags.HasErrors() {
t.Fatal(diags.Err())
}
if !p.GetProviderSchemaCalled {
t.Fatalf("Unexpected function call")
}
if p.GetFunctionsCalled {
t.Fatalf("Unexpected function call")
}
if !p.CallFunctionCalled {
t.Fatalf("Unexpected function call")
}
p.GetProviderSchemaCalled = false
p.GetFunctionsCalled = false
p.CallFunctionCalled = false
_, diags = ctx.Plan(m, nil, nil)
if diags.HasErrors() {
t.Fatal(diags.Err())
}
if !p.GetProviderSchemaCalled {
t.Fatalf("Unexpected function call")
}
if p.GetFunctionsCalled {
t.Fatalf("Expected function call")
}
if !p.CallFunctionCalled {
t.Fatalf("Expected function call")
}
}

View File

@ -7,16 +7,20 @@ package tofu
import (
"errors"
"fmt"
"log"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/zclconf/go-cty-debug/ctydebug"
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
)
func TestContextImport_basic(t *testing.T) {
@ -115,6 +119,187 @@ resource "aws_instance" "foo" {
}
}
func TestContextImport_multiInstanceProviderConfig(t *testing.T) {
// This test deals with the situation of importing into a resource instance
// whose resource has a dynamic instance key in its "provider" argument,
// and thus the import step needs to perform dynamic provider instance
// selection to determine exactly which provider instance to use.
m := testModuleInline(t, map[string]string{
"main.tf": `
terraform {
required_providers {
test = {
source = "terraform.io/builtin/test"
}
}
}
provider "test" {
alias = "multi"
for_each = {
a = {}
b = {}
}
marker = each.key
}
resource "test_thing" "test" {
for_each = { "foo" = "a" }
provider = test.multi[each.value]
}
`})
resourceTypeSchema := providers.Schema{
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
"import_marker": {
Type: cty.String,
Computed: true,
},
"refresh_marker": {
Type: cty.String,
Computed: true,
},
},
},
}
providerSchema := &providers.GetProviderSchemaResponse{
Provider: providers.Schema{
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"marker": {
Type: cty.String,
Required: true,
},
},
},
},
ResourceTypes: map[string]providers.Schema{
"test_thing": resourceTypeSchema,
},
}
// Unlike most context tests, this one uses a real factory function so that
// we can instantiate multiple instances and distinguish them.
providerFactory := func() (providers.Interface, error) {
// The following uses log.Printf instead of t.Logf so that the logs can interleave with the
// verbose trace logs produced by the main logic in this package, to make the order of operations clearer.
// To run just this test with trace logs:
// TF_LOG=trace go test ./internal/tofu -run '^TestContextImport_multiInstanceProviderConfig$'
ret := &MockProvider{}
var configuredMarker cty.Value
log.Printf("[TRACE] TestContextImport_multiInstanceProviderConfig: creating new instance of provider 'test' at %p", ret)
ret.GetProviderSchemaResponse = providerSchema
ret.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
configuredMarker = req.Config.GetAttr("marker")
log.Printf("[TRACE] TestContextImport_multiInstanceProviderConfig: ConfigureProvider for %p with marker = %#v", ret, configuredMarker)
return providers.ConfigureProviderResponse{}
}
ret.ImportResourceStateFn = func(req providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
log.Printf("[TRACE] TestContextImport_multiInstanceProviderConfig: ImportResourceState for %p with marker = %#v", ret, configuredMarker)
if configuredMarker == cty.NilVal {
return providers.ImportResourceStateResponse{
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("ImportResourceState before ConfigureProvider")),
}
}
return providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "test_thing",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal(req.ID),
"import_marker": configuredMarker,
"refresh_marker": cty.NullVal(cty.String), // we'll populate this in ReadResource
}),
},
},
}
}
ret.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
log.Printf("[TRACE] TestContextImport_multiInstanceProviderConfig: ReadResource for %p with marker = %#v", ret, configuredMarker)
if configuredMarker == cty.NilVal {
return providers.ReadResourceResponse{
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("ReadResource before ConfigureProvider")),
}
}
return providers.ReadResourceResponse{
NewState: cty.ObjectVal(map[string]cty.Value{
"id": req.PriorState.GetAttr("id"),
"import_marker": req.PriorState.GetAttr("import_marker"),
"refresh_marker": configuredMarker,
}),
}
}
return ret, nil
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("test"): providerFactory,
},
})
existingInstanceKey := addrs.StringKey("foo")
existingInstanceAddr := addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "test_thing", "test", existingInstanceKey,
)
t.Logf("importing into %s, which should succeed because it's configured", existingInstanceAddr)
log.Printf("[TRACE] TestContextImport_multiInstanceProviderConfig: importing into %s, which should succeed because it's configured", existingInstanceAddr)
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*ImportTarget{
{
CommandLineImportTarget: &CommandLineImportTarget{
Addr: existingInstanceAddr,
ID: "fake-import-id",
},
},
},
})
assertNoErrors(t, diags)
resourceState := state.Resource(existingInstanceAddr.ContainingResource())
if got, want := len(resourceState.Instances), 1; got != want {
t.Errorf("unexpected number of instances %d; want %d", got, want)
}
instanceState := resourceState.Instances[existingInstanceKey]
if instanceState == nil {
t.Fatal("no instance with key \"foo\" in final state")
}
if got, want := instanceState.ProviderKey, addrs.StringKey("a"); got != want {
t.Errorf("wrong provider key %s; want %s", got, want)
}
if instanceState.Current == nil {
t.Fatal("final resource instance has no current object")
}
gotObjState, err := instanceState.Current.Decode(resourceTypeSchema.Block.ImpliedType())
if err != nil {
t.Fatalf("failed to decode final resource instance object state: %s", err)
}
wantObjState := &states.ResourceInstanceObject{
Value: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("fake-import-id"),
"import_marker": cty.StringVal("a"),
"refresh_marker": cty.StringVal("a"),
}),
Status: states.ObjectReady,
Dependencies: []addrs.ConfigResource{},
}
if diff := cmp.Diff(wantObjState, gotObjState, ctydebug.CmpOptions); diff != "" {
t.Error("wrong final object state\n" + diff)
}
}
func TestContextImport_importResourceWithSensitiveDataSource(t *testing.T) {
p := testProvider("aws")
m := testModuleInline(t, map[string]string{
@ -218,6 +403,7 @@ func TestContextImport_collision(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})

View File

@ -446,6 +446,7 @@ func TestContext2Input_dataSourceRequiresRefresh(t *testing.T) {
Provider: addrs.NewDefaultProvider("null"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})

View File

@ -860,16 +860,17 @@ func (c *Context) planGraph(config *configs.Config, prevRunState *states.State,
return graph, walkPlan, diags
case plans.RefreshOnlyMode:
graph, diags := (&PlanGraphBuilder{
Config: config,
State: prevRunState,
RootVariableValues: opts.SetVariables,
Plugins: c.plugins,
Targets: opts.Targets,
Excludes: opts.Excludes,
skipRefresh: opts.SkipRefresh,
skipPlanChanges: true, // this activates "refresh only" mode.
Operation: walkPlan,
ExternalReferences: opts.ExternalReferences,
Config: config,
State: prevRunState,
RootVariableValues: opts.SetVariables,
Plugins: c.plugins,
Targets: opts.Targets,
Excludes: opts.Excludes,
skipRefresh: opts.SkipRefresh,
skipPlanChanges: true, // this activates "refresh only" mode.
Operation: walkPlan,
ExternalReferences: opts.ExternalReferences,
ProviderFunctionTracker: providerFunctionTracker,
}).Build(addrs.RootModuleInstance)
return graph, walkPlan, diags
case plans.DestroyMode:

View File

@ -80,7 +80,7 @@ resource "test_object" "a" {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"arg":"previous_run"}`),
Status: states.ObjectTainted,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
@ -209,6 +209,7 @@ data "test_data_source" "foo" {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -251,7 +252,7 @@ output "out" {
s.SetResourceInstanceCurrent(mustResourceInstanceAddr(`data.test_object.a["old"]`), &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"test_string":"foo"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
@ -375,6 +376,7 @@ resource "test_resource" "b" {
AttrsJSON: []byte(`{"id":"a"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustResourceInstanceAddr(`module.mod["old"].test_resource.b`),
@ -382,6 +384,7 @@ resource "test_resource" "b" {
AttrsJSON: []byte(`{"id":"b","value":"d"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
oldDataAddr,
@ -389,6 +392,7 @@ resource "test_resource" "b" {
AttrsJSON: []byte(`{"id":"d"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
})
@ -674,6 +678,7 @@ data "test_data_source" "a" {
AttrsJSON: []byte(`{"id":"boop","valid":false}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
})
@ -886,6 +891,7 @@ resource "test_resource" "b" {
AttrsJSON: []byte(`{"id":"main","valid":false}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
managedAddrB,
@ -893,6 +899,7 @@ resource "test_resource" "b" {
AttrsJSON: []byte(`{"id":"checker","valid":true}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
})
@ -986,7 +993,7 @@ resource "test_object" "a" {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"arg":"before"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
@ -1086,7 +1093,7 @@ resource "test_object" "a" {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"arg":"before"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
@ -1226,7 +1233,7 @@ provider "test" {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"test_string":"foo"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
@ -1262,7 +1269,7 @@ func TestContext2Plan_movedResourceBasic(t *testing.T) {
s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -1326,11 +1333,11 @@ func TestContext2Plan_movedResourceCollision(t *testing.T) {
s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addrZeroKey, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -1432,11 +1439,11 @@ func TestContext2Plan_movedResourceCollisionDestroy(t *testing.T) {
s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addrZeroKey, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -1544,7 +1551,7 @@ func TestContext2Plan_movedResourceUntargeted(t *testing.T) {
s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -1890,12 +1897,12 @@ resource "test_object" "b" {
s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{
// old_list is no longer in the schema
AttrsJSON: []byte(`{"old_list":["used to be","a list here"]}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -1953,12 +1960,12 @@ resource "test_object" "b" {
s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{
// old_list is no longer in the schema
AttrsJSON: []byte(`{"old_list":["used to be","a list here"]}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -2021,7 +2028,7 @@ func TestContext2Plan_movedResourceRefreshOnly(t *testing.T) {
s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -2093,7 +2100,7 @@ func TestContext2Plan_refreshOnlyMode(t *testing.T) {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"arg":"before"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -2229,7 +2236,7 @@ func TestContext2Plan_refreshOnlyMode_deposed(t *testing.T) {
s.SetResourceInstanceDeposed(addr, deposedKey, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"arg":"before"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -2366,11 +2373,11 @@ func TestContext2Plan_refreshOnlyMode_orphan(t *testing.T) {
s.SetResourceInstanceCurrent(addr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"arg":"before"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addr.Instance(addrs.IntKey(1)), &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"arg":"before"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -2583,6 +2590,7 @@ data "test_data_source" "foo" {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.bar").Resource,
@ -2597,6 +2605,7 @@ data "test_data_source" "foo" {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2640,11 +2649,11 @@ func TestContext2Plan_forceReplace(t *testing.T) {
s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -2708,11 +2717,11 @@ func TestContext2Plan_forceReplaceIncompleteAddr(t *testing.T) {
s.SetResourceInstanceCurrent(addr0, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addr1, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -2828,6 +2837,7 @@ output "output" {
AttrsJSON: []byte(`{"id":"foo","value":"a"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
one.SetResourceInstanceCurrent(
mustResourceInstanceAddr(`data.test_data_source.d`).Resource,
@ -2836,6 +2846,7 @@ output "output" {
AttrsJSON: []byte(`{"id":"data"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
two.SetResourceInstanceCurrent(
mustResourceInstanceAddr(`test_resource.x`).Resource,
@ -2844,6 +2855,7 @@ output "output" {
AttrsJSON: []byte(`{"id":"foo","value":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
two.SetResourceInstanceCurrent(
mustResourceInstanceAddr(`data.test_data_source.d`).Resource,
@ -2852,6 +2864,7 @@ output "output" {
AttrsJSON: []byte(`{"id":"data"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2919,7 +2932,7 @@ func TestContext2Plan_moduleExpandOrphansResourceInstance(t *testing.T) {
s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -3094,7 +3107,7 @@ resource "test_resource" "a" {
s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
_, diags := ctx.Plan(m, state, &PlanOpts{
Mode: plans.RefreshOnlyMode,
@ -3163,7 +3176,7 @@ resource "test_resource" "a" {
s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
@ -3216,7 +3229,7 @@ resource "test_resource" "a" {
s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
@ -3888,6 +3901,7 @@ resource "test_object" "b" {
Status: states.ObjectReady,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.b[0]"),
@ -3896,6 +3910,7 @@ resource "test_object" "b" {
Status: states.ObjectReady,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
})
for _, configuration := range configurations {
@ -3977,7 +3992,7 @@ data "test_object" "a" {
s.SetResourceInstanceCurrent(mustResourceInstanceAddr(`data.test_object.a`), &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"old","obj":[{"args":["string"]}]}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
@ -4018,6 +4033,7 @@ resource "test_object" "b" {
Dependencies: []addrs.ConfigResource{mustResourceInstanceAddr("test_object.b").ContainingResource().Config()},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.b").Resource,
@ -4026,6 +4042,7 @@ resource "test_object" "b" {
AttrsJSON: []byte(`{"test_string":"b"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4139,6 +4156,7 @@ resource "test_object" "b" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.a[0]").Resource,
@ -4148,6 +4166,7 @@ resource "test_object" "b" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4318,6 +4337,7 @@ output "out" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
mod.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.a[1]").Resource,
@ -4327,6 +4347,7 @@ output "out" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4461,6 +4482,7 @@ resource "test_object" "a" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -5575,6 +5597,7 @@ import {
AttrsJSON: []byte(`{"test_string":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
@ -7012,7 +7035,7 @@ func TestContext2Plan_removedResourceBasic(t *testing.T) {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceDeposed(
mustResourceInstanceAddr(addr.String()),
desposedKey,
@ -7022,6 +7045,7 @@ func TestContext2Plan_removedResourceBasic(t *testing.T) {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
})
@ -7092,7 +7116,7 @@ func TestContext2Plan_removedModuleBasic(t *testing.T) {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceDeposed(
mustResourceInstanceAddr(addr.String()),
desposedKey,
@ -7102,6 +7126,7 @@ func TestContext2Plan_removedModuleBasic(t *testing.T) {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
})
@ -7174,11 +7199,11 @@ func TestContext2Plan_removedModuleForgetsAllInstances(t *testing.T) {
s.SetResourceInstanceCurrent(addrFirst, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addrSecond, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7240,11 +7265,11 @@ func TestContext2Plan_removedResourceForgetsAllInstances(t *testing.T) {
s.SetResourceInstanceCurrent(addrFirst, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
s.SetResourceInstanceCurrent(addrSecond, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7308,7 +7333,7 @@ func TestContext2Plan_removedResourceInChildModuleFromParentModule(t *testing.T)
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7370,7 +7395,7 @@ func TestContext2Plan_removedResourceInChildModuleFromChildModule(t *testing.T)
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7433,7 +7458,7 @@ func TestContext2Plan_removedResourceInGrandchildModuleFromRootModule(t *testing
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7496,7 +7521,7 @@ func TestContext2Plan_removedChildModuleForgetsResourceInGrandchildModule(t *tes
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7564,7 +7589,7 @@ func TestContext2Plan_movedAndRemovedResourceAtTheSameTime(t *testing.T) {
s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7629,7 +7654,7 @@ func TestContext2Plan_removedResourceButResourceBlockStillExists(t *testing.T) {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7678,7 +7703,7 @@ func TestContext2Plan_removedResourceButResourceBlockStillExistsInChildModule(t
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()
@ -7727,7 +7752,7 @@ func TestContext2Plan_removedModuleButModuleBlockStillExists(t *testing.T) {
s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
p := simpleMockProvider()

View File

@ -95,6 +95,7 @@ func TestContext2Plan_createBefore_deposed(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr("aws_instance.foo").Resource,
@ -104,6 +105,7 @@ func TestContext2Plan_createBefore_deposed(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -810,6 +812,7 @@ func TestContext2Plan_moduleOrphans(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -882,6 +885,7 @@ func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
AttrsJSON: []byte(`{"id":"top","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child1 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child1", addrs.NoKey))
child1.SetResourceInstanceCurrent(
@ -891,6 +895,7 @@ func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child2 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child2", addrs.NoKey))
child2.SetResourceInstanceCurrent(
@ -900,6 +905,7 @@ func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1376,6 +1382,7 @@ func TestContext2Plan_preventDestroy_bad(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1415,6 +1422,7 @@ func TestContext2Plan_preventDestroy_good(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1446,6 +1454,7 @@ func TestContext2Plan_preventDestroy_countBad(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -1454,6 +1463,7 @@ func TestContext2Plan_preventDestroy_countBad(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1502,6 +1512,7 @@ func TestContext2Plan_preventDestroy_countGood(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -1510,6 +1521,7 @@ func TestContext2Plan_preventDestroy_countGood(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc345"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1553,6 +1565,7 @@ func TestContext2Plan_preventDestroy_countGoodNoChange(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123","current":"0","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1584,6 +1597,7 @@ func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -1981,6 +1995,7 @@ func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123","foo":"baz"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2603,6 +2618,7 @@ func TestContext2Plan_countDecreaseToOne(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -2611,6 +2627,7 @@ func TestContext2Plan_countDecreaseToOne(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -2619,6 +2636,7 @@ func TestContext2Plan_countDecreaseToOne(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2703,6 +2721,7 @@ func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance","foo":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2780,6 +2799,7 @@ func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2863,6 +2883,7 @@ func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
@ -2871,6 +2892,7 @@ func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -2971,6 +2993,7 @@ func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","name":"foo 0"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -2979,6 +3002,7 @@ func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","name":"foo 1"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
@ -2987,6 +3011,7 @@ func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 0"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
@ -2995,6 +3020,7 @@ func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 1"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3135,6 +3161,7 @@ func TestContext2Plan_destroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.two").Resource,
@ -3143,6 +3170,7 @@ func TestContext2Plan_destroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3196,6 +3224,7 @@ func TestContext2Plan_moduleDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
child.SetResourceInstanceCurrent(
@ -3205,6 +3234,7 @@ func TestContext2Plan_moduleDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3258,6 +3288,7 @@ func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
AttrsJSON: []byte(`{"id":"a"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
bModule := state.EnsureModule(addrs.RootModuleInstance.Child("b_module", addrs.NoKey))
bModule.SetResourceInstanceCurrent(
@ -3267,6 +3298,7 @@ func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
AttrsJSON: []byte(`{"id":"b"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3320,6 +3352,7 @@ func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar0"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -3328,6 +3361,7 @@ func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar1"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3441,6 +3475,7 @@ func TestContext2Plan_diffVar(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3556,6 +3591,7 @@ func TestContext2Plan_orphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3638,6 +3674,7 @@ func TestContext2Plan_state(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -3740,6 +3777,7 @@ func TestContext2Plan_requiresReplace(t *testing.T) {
AttrsJSON: []byte(`{"v":"hello"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3798,6 +3836,7 @@ func TestContext2Plan_taint(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar").Resource,
@ -3806,6 +3845,7 @@ func TestContext2Plan_taint(t *testing.T) {
AttrsJSON: []byte(`{"id":"baz"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3884,6 +3924,7 @@ func TestContext2Plan_taintIgnoreChanges(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo","vars":"foo","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -3948,6 +3989,7 @@ func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -3956,6 +3998,7 @@ func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -3964,6 +4007,7 @@ func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
for i := 0; i < 100; i++ {
@ -4314,6 +4358,7 @@ func TestContext2Plan_targetedOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-789xyz"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
@ -4322,6 +4367,7 @@ func TestContext2Plan_targetedOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4379,6 +4425,7 @@ func TestContext2Plan_excludedOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-789xyz"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
@ -4387,6 +4434,7 @@ func TestContext2Plan_excludedOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4445,6 +4493,7 @@ func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-789xyz"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
@ -4453,6 +4502,7 @@ func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4507,6 +4557,7 @@ func TestContext2Plan_excludedModuleOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-789xyz"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
@ -4515,6 +4566,7 @@ func TestContext2Plan_excludedModuleOrphan(t *testing.T) {
AttrsJSON: []byte(`{"id":"i-abc123"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -4790,6 +4842,7 @@ func TestContext2Plan_targetedOverTen(t *testing.T) {
AttrsJSON: []byte(attrs),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
}
@ -4844,6 +4897,7 @@ func TestContext2Plan_excludedOverTen(t *testing.T) {
AttrsJSON: []byte(attrs),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
}
@ -4942,6 +4996,7 @@ func TestContext2Plan_ignoreChanges(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5014,6 +5069,7 @@ func TestContext2Plan_ignoreChangesWildcard(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","instance":"t2.micro","type":"aws_instance","foo":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5079,6 +5135,7 @@ func TestContext2Plan_ignoreChangesInMap(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
m := testModule(t, "plan-ignore-changes-in-map")
@ -5136,6 +5193,7 @@ func TestContext2Plan_ignoreChangesSensitive(t *testing.T) {
AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5527,6 +5585,7 @@ func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) {
}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -5598,6 +5657,7 @@ func TestContext2Plan_resourceNestedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo0","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -5606,6 +5666,7 @@ func TestContext2Plan_resourceNestedCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo1","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
@ -5615,6 +5676,7 @@ func TestContext2Plan_resourceNestedCount(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
@ -5624,6 +5686,7 @@ func TestContext2Plan_resourceNestedCount(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.baz[0]").Resource,
@ -5633,6 +5696,7 @@ func TestContext2Plan_resourceNestedCount(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.baz[1]").Resource,
@ -5642,6 +5706,7 @@ func TestContext2Plan_resourceNestedCount(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
@ -6263,6 +6328,7 @@ resource "aws_instance" "foo" {
AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(1))).SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo").Resource,
@ -6271,6 +6337,7 @@ resource "aws_instance" "foo" {
AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
p := testProvider("aws")
@ -6672,6 +6739,7 @@ data "test_data_source" "foo" {}
AttrsJSON: []byte(`{"id":"data_id", "foo":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -6721,6 +6789,7 @@ resource "test_instance" "b" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.b").Resource,
@ -6730,6 +6799,7 @@ resource "test_instance" "b" {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7068,6 +7138,7 @@ resource "test_instance" "a" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7240,6 +7311,7 @@ resource "test_instance" "a" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7303,6 +7375,7 @@ resource "test_instance" "a" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7361,6 +7434,7 @@ resource "test_instance" "a" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7400,6 +7474,7 @@ resource "test_instance" "a" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
// the provider for this data source is no longer in the config, but that
@ -7412,6 +7487,7 @@ resource "test_instance" "a" {
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.opentofu.org/local/test"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -7469,6 +7545,7 @@ resource "test_resource" "foo" {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))

View File

@ -36,6 +36,7 @@ func TestContext2Refresh(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
@ -98,6 +99,7 @@ func TestContext2Refresh_dynamicAttr(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -1435,6 +1437,7 @@ func TestContext2Refresh_orphanModule(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
child.SetResourceInstanceCurrent(
@ -1445,6 +1448,7 @@ func TestContext2Refresh_orphanModule(t *testing.T) {
Dependencies: []addrs.ConfigResource{{Module: addrs.Module{"module.grandchild"}}},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
grandchild := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("grandchild", addrs.NoKey))
testSetResourceInstanceCurrent(grandchild, "aws_instance.baz", `{"id":"i-cde345"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
@ -1574,6 +1578,7 @@ func TestContext2Refresh_schemaUpgradeFlatmap(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -1656,6 +1661,7 @@ func TestContext2Refresh_schemaUpgradeJSON(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -1793,6 +1799,7 @@ func TestRefresh_updateLifecycle(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
m := testModuleInline(t, map[string]string{
@ -1846,6 +1853,7 @@ func TestContext2Refresh_dataSourceOrphan(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
p := testProvider("test")
p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
@ -1936,6 +1944,7 @@ resource "test_resource" "foo" {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{

View File

@ -44,7 +44,7 @@ type EvalContext interface {
// It is an error to initialize the same provider more than once. This
// method will panic if the module instance address of the given provider
// configuration does not match the Path() of the EvalContext.
InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error)
InitProvider(addr addrs.AbsProviderConfig, key addrs.InstanceKey) (providers.Interface, error)
// Provider gets the provider instance with the given address (already
// initialized) or returns nil if the provider isn't initialized.
@ -53,7 +53,7 @@ type EvalContext interface {
// resources in one module are able to use providers from other modules.
// InitProvider must've been called on the EvalContext of the module
// that owns the given provider before calling this method.
Provider(addrs.AbsProviderConfig) providers.Interface
Provider(addrs.AbsProviderConfig, addrs.InstanceKey) providers.Interface
// ProviderSchema retrieves the schema for a particular provider, which
// must have already been initialized with InitProvider.
@ -75,7 +75,7 @@ type EvalContext interface {
//
// This method will panic if the module instance address of the given
// provider configuration does not match the Path() of the EvalContext.
ConfigureProvider(addrs.AbsProviderConfig, cty.Value) tfdiags.Diagnostics
ConfigureProvider(addrs.AbsProviderConfig, addrs.InstanceKey, cty.Value) tfdiags.Diagnostics
// ProviderInput and SetProviderInput are used to configure providers
// from user input.

View File

@ -67,7 +67,7 @@ type BuiltinEvalContext struct {
InputValue UIInput
ProviderLock *sync.Mutex
ProviderCache map[string]providers.Interface
ProviderCache map[string]map[addrs.InstanceKey]providers.Interface
ProviderInputConfig map[string]map[string]cty.Value
ProvisionerLock *sync.Mutex
@ -128,14 +128,18 @@ func (ctx *BuiltinEvalContext) Input() UIInput {
return ctx.InputValue
}
func (ctx *BuiltinEvalContext) InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error) {
func (ctx *BuiltinEvalContext) InitProvider(addr addrs.AbsProviderConfig, providerKey addrs.InstanceKey) (providers.Interface, error) {
ctx.ProviderLock.Lock()
defer ctx.ProviderLock.Unlock()
key := addr.String()
if ctx.ProviderCache[key] == nil {
ctx.ProviderCache[key] = make(map[addrs.InstanceKey]providers.Interface)
}
// If we have already initialized, it is an error
if _, ok := ctx.ProviderCache[key]; ok {
if _, ok := ctx.ProviderCache[key][providerKey]; ok {
return nil, fmt.Errorf("%s is already initialized", addr)
}
@ -156,17 +160,22 @@ func (ctx *BuiltinEvalContext) InitProvider(addr addrs.AbsProviderConfig) (provi
}
}
log.Printf("[TRACE] BuiltinEvalContext: Initialized %q provider for %s", addr.String(), addr)
ctx.ProviderCache[key] = p
log.Printf("[TRACE] BuiltinEvalContext: Initialized %q%s provider for %s", addr.String(), providerKey, addr)
ctx.ProviderCache[key][providerKey] = p
return p, nil
}
func (ctx *BuiltinEvalContext) Provider(addr addrs.AbsProviderConfig) providers.Interface {
func (ctx *BuiltinEvalContext) Provider(addr addrs.AbsProviderConfig, key addrs.InstanceKey) providers.Interface {
ctx.ProviderLock.Lock()
defer ctx.ProviderLock.Unlock()
return ctx.ProviderCache[addr.String()]
pm, ok := ctx.ProviderCache[addr.String()]
if !ok {
return nil
}
return pm[key]
}
func (ctx *BuiltinEvalContext) ProviderSchema(addr addrs.AbsProviderConfig) (providers.ProviderSchema, error) {
@ -177,17 +186,27 @@ func (ctx *BuiltinEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error
ctx.ProviderLock.Lock()
defer ctx.ProviderLock.Unlock()
var diags tfdiags.Diagnostics
key := addr.String()
provider := ctx.ProviderCache[key]
if provider != nil {
providerMap := ctx.ProviderCache[key]
if providerMap != nil {
for _, provider := range providerMap {
err := provider.Close()
if err != nil {
diags = diags.Append(err)
}
}
delete(ctx.ProviderCache, key)
return provider.Close()
}
if diags.HasErrors() {
return diags.Err()
}
return nil
}
func (ctx *BuiltinEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, cfg cty.Value) tfdiags.Diagnostics {
func (ctx *BuiltinEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, providerKey addrs.InstanceKey, cfg cty.Value) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
if !addr.Module.Equal(ctx.Path().Module()) {
// This indicates incorrect use of ConfigureProvider: it should be used
@ -195,9 +214,9 @@ func (ctx *BuiltinEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, c
panic(fmt.Sprintf("%s configured by wrong module %s", addr, ctx.Path()))
}
p := ctx.Provider(addr)
p := ctx.Provider(addr, providerKey)
if p == nil {
diags = diags.Append(fmt.Errorf("%s not initialized", addr))
diags = diags.Append(fmt.Errorf("%s not initialized", addr.InstanceString(providerKey)))
return diags
}
@ -433,7 +452,7 @@ func (ctx *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, source
}
scope := ctx.Evaluator.Scope(data, self, source, func(pf addrs.ProviderFunction, rng tfdiags.SourceRange) (*function.Function, tfdiags.Diagnostics) {
absPc, ok := ctx.ProviderFunctionTracker.Lookup(ctx.PathValue.Module(), pf)
providedBy, ok := ctx.ProviderFunctionTracker.Lookup(ctx.PathValue.Module(), pf)
if !ok {
// This should not be possible if references are tracked correctly
return nil, tfdiags.Diagnostics{}.Append(&hcl.Diagnostic{
@ -444,14 +463,28 @@ func (ctx *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, source
})
}
provider := ctx.Provider(absPc)
var providerKey addrs.InstanceKey
if providedBy.KeyExpression != nil && ctx.Evaluator.Operation != walkValidate {
moduleInstanceForKey := ctx.PathValue[:len(providedBy.KeyModule)]
if !moduleInstanceForKey.Module().Equal(providedBy.KeyModule) {
panic(fmt.Sprintf("Invalid module key expression location %s in function %s", providedBy.KeyModule, pf.String()))
}
var keyDiags tfdiags.Diagnostics
providerKey, keyDiags = resolveProviderModuleInstance(ctx, providedBy.KeyExpression, moduleInstanceForKey, ctx.PathValue.String()+" "+pf.String())
if keyDiags.HasErrors() {
return nil, keyDiags
}
}
provider := ctx.Provider(providedBy.Provider, providerKey)
if provider == nil {
// This should not be possible if references are tracked correctly
return nil, tfdiags.Diagnostics{}.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "BUG: Uninitialized function provider",
Detail: fmt.Sprintf("Provider %q has not yet been initialized", absPc.String()),
Summary: "Uninitialized function provider",
Detail: fmt.Sprintf("Provider %q has not yet been initialized", providedBy.Provider.String()),
Subject: rng.ToHCL().Ptr(),
})
}

View File

@ -63,7 +63,7 @@ func TestBuildingEvalContextInitProvider(t *testing.T) {
ctx := testBuiltinEvalContext(t)
ctx = ctx.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext)
ctx.ProviderLock = &lock
ctx.ProviderCache = make(map[string]providers.Interface)
ctx.ProviderCache = make(map[string]map[addrs.InstanceKey]providers.Interface)
ctx.Plugins = newContextPlugins(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): providers.FactoryFixed(testP),
}, nil)
@ -78,11 +78,11 @@ func TestBuildingEvalContextInitProvider(t *testing.T) {
Alias: "foo",
}
_, err := ctx.InitProvider(providerAddrDefault)
_, err := ctx.InitProvider(providerAddrDefault, addrs.NoKey)
if err != nil {
t.Fatalf("error initializing provider test: %s", err)
}
_, err = ctx.InitProvider(providerAddrAlias)
_, err = ctx.InitProvider(providerAddrAlias, addrs.NoKey)
if err != nil {
t.Fatalf("error initializing provider test.foo: %s", err)
}

View File

@ -183,14 +183,14 @@ func (c *MockEvalContext) Input() UIInput {
return c.InputInput
}
func (c *MockEvalContext) InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error) {
func (c *MockEvalContext) InitProvider(addr addrs.AbsProviderConfig, _ addrs.InstanceKey) (providers.Interface, error) {
c.InitProviderCalled = true
c.InitProviderType = addr.String()
c.InitProviderAddr = addr
return c.InitProviderProvider, c.InitProviderError
}
func (c *MockEvalContext) Provider(addr addrs.AbsProviderConfig) providers.Interface {
func (c *MockEvalContext) Provider(addr addrs.AbsProviderConfig, _ addrs.InstanceKey) providers.Interface {
c.ProviderCalled = true
c.ProviderAddr = addr
return c.ProviderProvider
@ -208,8 +208,7 @@ func (c *MockEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error {
return nil
}
func (c *MockEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, cfg cty.Value) tfdiags.Diagnostics {
func (c *MockEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, _ addrs.InstanceKey, cfg cty.Value) tfdiags.Diagnostics {
c.ConfigureProviderCalled = true
c.ConfigureProviderAddr = addr
c.ConfigureProviderConfig = cfg

View File

@ -15,7 +15,11 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/configs/hcl2shim"
"github.com/opentofu/opentofu/internal/lang"
"github.com/opentofu/opentofu/internal/lang/evalchecks"
"github.com/opentofu/opentofu/internal/lang/marks"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
)
func buildProviderConfig(ctx EvalContext, addr addrs.AbsProviderConfig, config *configs.Provider) hcl.Body {
@ -47,15 +51,75 @@ func buildProviderConfig(ctx EvalContext, addr addrs.AbsProviderConfig, config *
}
}
func resolveProviderResourceInstance(ctx EvalContext, keyExpr hcl.Expression, resourcePath addrs.AbsResourceInstance) (addrs.InstanceKey, tfdiags.Diagnostics) {
keyData := ctx.InstanceExpander().GetResourceInstanceRepetitionData(resourcePath)
keyScope := ctx.EvaluationScope(nil, nil, keyData)
return resolveProviderInstance(keyExpr, keyScope, resourcePath.String())
}
func resolveProviderModuleInstance(ctx EvalContext, keyExpr hcl.Expression, modulePath addrs.ModuleInstance, source string) (addrs.InstanceKey, tfdiags.Diagnostics) {
keyData := ctx.InstanceExpander().GetModuleInstanceRepetitionData(modulePath)
keyScope := ctx.WithPath(modulePath).EvaluationScope(nil, nil, keyData)
return resolveProviderInstance(keyExpr, keyScope, source)
}
func resolveProviderInstance(keyExpr hcl.Expression, keyScope *lang.Scope, source string) (addrs.InstanceKey, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
keyVal, keyDiags := keyScope.EvalExpr(keyExpr, cty.DynamicPseudoType)
diags = diags.Append(keyDiags)
if keyDiags.HasErrors() {
return nil, diags
}
if keyVal.HasMark(marks.Sensitive) {
return nil, diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider instance key",
Detail: "A provider instance key must not be derived from a sensitive value.",
Subject: keyExpr.Range().Ptr(),
Extra: evalchecks.DiagnosticCausedBySensitive(true),
})
}
if keyVal.IsNull() {
return nil, diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider instance key",
Detail: "A provider instance key must not be null.",
Subject: keyExpr.Range().Ptr(),
})
}
if !keyVal.IsKnown() {
return nil, diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider instance key",
Detail: fmt.Sprintf("The provider instance key for %s depends on values that cannot be determined until apply, and so OpenTofu cannot select a provider instance to create a plan for this resource instance.", source),
Subject: keyExpr.Range().Ptr(),
Extra: evalchecks.DiagnosticCausedByUnknown(true),
})
}
parsedKey, parsedErr := addrs.ParseInstanceKey(keyVal)
if parsedErr != nil {
return nil, diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid provider instance key",
Detail: fmt.Sprintf("The given instance key is unsuitable: %s.", tfdiags.FormatError(parsedErr)),
Subject: keyExpr.Range().Ptr(),
})
}
return parsedKey, diags
}
// getProvider returns the providers.Interface and schema for a given provider.
func getProvider(ctx EvalContext, addr addrs.AbsProviderConfig) (providers.Interface, providers.ProviderSchema, error) {
func getProvider(ctx EvalContext, addr addrs.AbsProviderConfig, providerKey addrs.InstanceKey) (providers.Interface, providers.ProviderSchema, error) {
if addr.Provider.Type == "" {
// Should never happen
panic("GetProvider used with uninitialized provider configuration address")
}
provider := ctx.Provider(addr)
provider := ctx.Provider(addr, providerKey)
if provider == nil {
return nil, providers.ProviderSchema{}, fmt.Errorf("provider %s not initialized", addr)
return nil, providers.ProviderSchema{}, fmt.Errorf("provider %s not initialized", addr.InstanceString(providerKey))
}
// Not all callers require a schema, so we will leave checking for a nil
// schema to the callers.

View File

@ -246,6 +246,7 @@ func TestEvaluatorGetResource(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
}).SyncWrapper()
@ -420,6 +421,7 @@ func TestEvaluatorGetResource_changes(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
}).SyncWrapper()

View File

@ -104,6 +104,7 @@ func TestApplyGraphBuilder_depCbd(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -113,6 +114,7 @@ func TestApplyGraphBuilder_depCbd(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
b := &ApplyGraphBuilder{
@ -270,6 +272,7 @@ func TestApplyGraphBuilder_destroyStateOnly(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -279,6 +282,7 @@ func TestApplyGraphBuilder_destroyStateOnly(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
b := &ApplyGraphBuilder{
@ -332,6 +336,7 @@ func TestApplyGraphBuilder_destroyCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"B"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -341,6 +346,7 @@ func TestApplyGraphBuilder_destroyCount(t *testing.T) {
Dependencies: []addrs.ConfigResource{addrA.ContainingResource().Config()},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
b := &ApplyGraphBuilder{
@ -393,6 +399,7 @@ func TestApplyGraphBuilder_moduleDestroy(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
modB := state.EnsureModule(addrs.RootModuleInstance.Child("B", addrs.NoKey))
modB.SetResourceInstanceCurrent(
@ -403,6 +410,7 @@ func TestApplyGraphBuilder_moduleDestroy(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.A.test_object.foo")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
b := &ApplyGraphBuilder{
@ -546,6 +554,7 @@ func TestApplyGraphBuilder_updateFromOrphan(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -571,6 +580,7 @@ func TestApplyGraphBuilder_updateFromOrphan(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
b := &ApplyGraphBuilder{
@ -649,6 +659,7 @@ func TestApplyGraphBuilder_updateFromCBDOrphan(t *testing.T) {
CreateBeforeDestroy: true,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
addrs.Resource{
@ -671,6 +682,7 @@ func TestApplyGraphBuilder_updateFromCBDOrphan(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
b := &ApplyGraphBuilder{
@ -721,6 +733,7 @@ func TestApplyGraphBuilder_orphanedWithProvider(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"].foo`),
addrs.NoKey,
)
b := &ApplyGraphBuilder{

View File

@ -60,7 +60,7 @@ type ContextGraphWalker struct {
variableValues map[string]map[string]cty.Value
providerLock sync.Mutex
providerCache map[string]providers.Interface
providerCache map[string]map[addrs.InstanceKey]providers.Interface
provisionerLock sync.Mutex
provisionerCache map[string]provisioners.Interface
@ -129,7 +129,7 @@ func (w *ContextGraphWalker) EvalContext() EvalContext {
func (w *ContextGraphWalker) init() {
w.contexts = make(map[string]*BuiltinEvalContext)
w.providerCache = make(map[string]providers.Interface)
w.providerCache = make(map[string]map[addrs.InstanceKey]providers.Interface)
w.provisionerCache = make(map[string]provisioners.Interface)
w.variableValues = make(map[string]map[string]cty.Value)

View File

@ -24,6 +24,6 @@ var (
// GraphNodeExecutable
func (n *NodeDestroyableDataResourceInstance) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
log.Printf("[TRACE] NodeDestroyableDataResourceInstance: removing state object for %s", n.Addr)
ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider.ProviderConfig, nil)
return nil
}

View File

@ -28,6 +28,7 @@ func TestNodeDataDestroyExecute(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
ctx := &MockEvalContext{
StateState: state.SyncWrapper(),

View File

@ -73,6 +73,14 @@ func (n *nodeExpandModule) References() []*addrs.Reference {
forEachRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, n.ModuleCall.ForEach)
refs = append(refs, forEachRefs...)
}
for _, passed := range n.ModuleCall.Providers {
if passed.InParent.KeyExpression != nil {
providerRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, passed.InParent.KeyExpression)
refs = append(refs, providerRefs...)
}
}
return refs
}

View File

@ -10,6 +10,7 @@ import (
"log"
"github.com/hashicorp/hcl/v2"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -26,34 +27,74 @@ var (
)
// GraphNodeExecutable
func (n *NodeApplyableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
_, err := ctx.InitProvider(n.Addr)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
}
provider, _, err := getProvider(ctx, n.Addr)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
func (n *NodeApplyableProvider) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
instances, diags := n.initInstances(ctx, op)
for key, provider := range instances {
diags = diags.Append(n.executeInstance(ctx, op, key, provider))
}
return diags
}
func (n *NodeApplyableProvider) initInstances(ctx EvalContext, op walkOperation) (map[addrs.InstanceKey]providers.Interface, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var initKeys []addrs.InstanceKey
// config -> init (different due to validate skipping most for_each logic)
instanceKeys := make(map[addrs.InstanceKey]addrs.InstanceKey)
if n.Config == nil || n.Config.Instances == nil {
initKeys = append(initKeys, addrs.NoKey)
instanceKeys[addrs.NoKey] = addrs.NoKey
} else if op == walkValidate {
// Instances are set AND we are validating
initKeys = append(initKeys, addrs.NoKey)
for key := range n.Config.Instances {
instanceKeys[key] = addrs.NoKey
}
} else {
// Instances are set AND we are not validating
for key := range n.Config.Instances {
initKeys = append(initKeys, key)
instanceKeys[key] = key
}
}
for _, key := range initKeys {
_, err := ctx.InitProvider(n.Addr, key)
diags = diags.Append(err)
}
if diags.HasErrors() {
return nil, diags
}
instances := make(map[addrs.InstanceKey]providers.Interface)
for configKey, initKey := range instanceKeys {
provider, _, err := getProvider(ctx, n.Addr, initKey)
diags = diags.Append(err)
instances[configKey] = provider
}
if diags.HasErrors() {
return nil, diags
}
return instances, diags
}
func (n *NodeApplyableProvider) executeInstance(ctx EvalContext, op walkOperation, providerKey addrs.InstanceKey, provider providers.Interface) tfdiags.Diagnostics {
switch op {
case walkValidate:
log.Printf("[TRACE] NodeApplyableProvider: validating configuration for %s", n.Addr)
return diags.Append(n.ValidateProvider(ctx, provider))
return n.ValidateProvider(ctx, providerKey, provider)
case walkPlan, walkPlanDestroy, walkApply, walkDestroy:
log.Printf("[TRACE] NodeApplyableProvider: configuring %s", n.Addr)
return diags.Append(n.ConfigureProvider(ctx, provider, false))
return n.ConfigureProvider(ctx, providerKey, provider, false)
case walkImport:
log.Printf("[TRACE] NodeApplyableProvider: configuring %s (requiring that configuration is wholly known)", n.Addr)
return diags.Append(n.ConfigureProvider(ctx, provider, true))
return n.ConfigureProvider(ctx, providerKey, provider, true)
}
return diags
return nil
}
func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider providers.Interface) (diags tfdiags.Diagnostics) {
func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, providerKey addrs.InstanceKey, provider providers.Interface) tfdiags.Diagnostics {
configBody := buildProviderConfig(ctx, n.Addr, n.ProviderConfig())
// if a provider config is empty (only an alias), return early and don't continue
@ -65,7 +106,7 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi
}
schemaResp := provider.GetProviderSchema()
diags = diags.Append(schemaResp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
diags := schemaResp.Diagnostics.InConfigBody(configBody, n.Addr.String())
if diags.HasErrors() {
return diags
}
@ -79,6 +120,9 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi
}
data := EvalDataForNoInstanceKey
if n.Config != nil && n.Config.Instances != nil {
data = n.Config.Instances[providerKey]
}
configVal, _, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, data)
if evalDiags.HasErrors() {
@ -103,19 +147,22 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi
// ConfigureProvider configures a provider that is already initialized and retrieved.
// If verifyConfigIsKnown is true, ConfigureProvider will return an error if the
// provider configVal is not wholly known and is meant only for use during import.
func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider providers.Interface, verifyConfigIsKnown bool) (diags tfdiags.Diagnostics) {
func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, providerKey addrs.InstanceKey, provider providers.Interface, verifyConfigIsKnown bool) tfdiags.Diagnostics {
config := n.ProviderConfig()
configBody := buildProviderConfig(ctx, n.Addr, config)
resp := provider.GetProviderSchema()
diags = diags.Append(resp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
diags := resp.Diagnostics.InConfigBody(configBody, n.Addr.String())
if diags.HasErrors() {
return diags
}
configSchema := resp.Provider.Block
data := EvalDataForNoInstanceKey
if n.Config != nil && n.Config.Instances != nil {
data = n.Config.Instances[providerKey]
}
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, data)
diags = diags.Append(evalDiags)
@ -169,7 +216,7 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider prov
log.Printf("[WARN] ValidateProviderConfig from %q changed the config value, but that value is unused", n.Addr)
}
configDiags := ctx.ConfigureProvider(n.Addr, unmarkedConfigVal)
configDiags := ctx.ConfigureProvider(n.Addr, providerKey, unmarkedConfigVal)
diags = diags.Append(configDiags.InConfigBody(configBody, n.Addr.String()))
if diags.HasErrors() && config == nil {
// If there isn't an explicit "provider" block in the configuration,

View File

@ -5,7 +5,10 @@
package tofu
import "github.com/opentofu/opentofu/internal/tfdiags"
import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/tfdiags"
)
// NodeEvalableProvider represents a provider during an "eval" walk.
// This special provider node type just initializes a provider and
@ -19,6 +22,6 @@ var _ GraphNodeExecutable = (*NodeEvalableProvider)(nil)
// GraphNodeExecutable
func (n *NodeEvalableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
_, err := ctx.InitProvider(n.Addr)
_, err := ctx.InitProvider(n.Addr, addrs.NoKey)
return diags.Append(err)
}

View File

@ -287,7 +287,7 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
},
}
diags := node.ValidateProvider(ctx, provider)
diags := node.ValidateProvider(ctx, addrs.NoKey, provider)
if diags.HasErrors() {
t.Errorf("unexpected error with valid config: %s", diags.Err())
}
@ -308,7 +308,7 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
},
}
diags := node.ValidateProvider(ctx, provider)
diags := node.ValidateProvider(ctx, addrs.NoKey, provider)
if !diags.HasErrors() {
t.Error("missing expected error with invalid config")
}
@ -321,7 +321,7 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
},
}
diags := node.ValidateProvider(ctx, provider)
diags := node.ValidateProvider(ctx, addrs.NoKey, provider)
if diags.HasErrors() {
t.Errorf("unexpected error with empty config: %s", diags.Err())
}
@ -369,7 +369,7 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
},
}
diags := node.ConfigureProvider(ctx, provider, false)
diags := node.ConfigureProvider(ctx, addrs.NoKey, provider, false)
if diags.HasErrors() {
t.Errorf("unexpected error with valid config: %s", diags.Err())
}
@ -382,7 +382,7 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
},
}
diags := node.ConfigureProvider(ctx, provider, false)
diags := node.ConfigureProvider(ctx, addrs.NoKey, provider, false)
if !diags.HasErrors() {
t.Fatal("missing expected error with nil config")
}
@ -403,7 +403,7 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
},
}
diags := node.ConfigureProvider(ctx, provider, false)
diags := node.ConfigureProvider(ctx, addrs.NoKey, provider, false)
if !diags.HasErrors() {
t.Fatal("missing expected error with invalid config")
}
@ -458,7 +458,7 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
},
}
diags := node.ConfigureProvider(ctx, provider, false)
diags := node.ConfigureProvider(ctx, addrs.NoKey, provider, false)
if diags.HasErrors() {
t.Errorf("unexpected error with valid config: %s", diags.Err())
}
@ -471,7 +471,7 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
},
}
diags := node.ConfigureProvider(ctx, provider, false)
diags := node.ConfigureProvider(ctx, addrs.NoKey, provider, false)
if !diags.HasErrors() {
t.Fatal("missing expected error with nil config")
}
@ -492,7 +492,7 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
},
}
diags := node.ConfigureProvider(ctx, provider, false)
diags := node.ConfigureProvider(ctx, addrs.NoKey, provider, false)
if !diags.HasErrors() {
t.Fatal("missing expected error with invalid config")
}
@ -518,7 +518,7 @@ func TestGetSchemaError(t *testing.T) {
},
}
diags := node.ConfigureProvider(ctx, provider, false)
diags := node.ConfigureProvider(ctx, addrs.NoKey, provider, false)
for _, d := range diags {
desc := d.Description()
if desc.Address != providerAddr.String() {

View File

@ -77,11 +77,12 @@ type NodeAbstractResource struct {
forceDependsOn bool
// The address of the provider this resource will use
ResolvedProvider addrs.AbsProviderConfig
ResolvedProvider ResolvedProvider
// storedProviderConfig is the provider address retrieved from the
// state. This is defined here for access within the ProvidedBy method, but
// will be set from the embedding instance type when the state is attached.
storedProviderConfig addrs.AbsProviderConfig
storedProviderConfig ResolvedProvider
// This resource may expand into instances which need to be imported.
importTargets []*ImportTarget
@ -293,28 +294,48 @@ func (n *NodeAbstractResource) DependsOn() []*addrs.Reference {
return result
}
func (n *NodeAbstractResource) SetProvider(p addrs.AbsProviderConfig) {
n.ResolvedProvider = p
// GraphNodeProviderConsumer
func (n *NodeAbstractResource) SetProvider(resolved ResolvedProvider) {
n.ResolvedProvider = resolved
}
// GraphNodeProviderConsumer
func (n *NodeAbstractResource) ProvidedBy() addrs.ProviderConfig {
func (n *NodeAbstractResource) ProvidedBy() RequestedProvider {
// Once the provider is fully resolved, we can return the known value.
if n.ResolvedProvider.Provider.Type != "" {
return n.ResolvedProvider
if n.ResolvedProvider.ProviderConfig.Provider.Type != "" {
return RequestedProvider{
ProviderConfig: n.ResolvedProvider.ProviderConfig,
KeyExpression: n.ResolvedProvider.KeyExpression,
KeyModule: n.ResolvedProvider.KeyModule,
KeyResource: n.ResolvedProvider.KeyResource,
KeyExact: n.ResolvedProvider.KeyExact,
}
}
// If we have a config we prefer that above all else
if n.Config != nil {
return n.Config.ProviderConfigAddr()
result := RequestedProvider{
ProviderConfig: n.Config.ProviderConfigAddr(),
}
if n.Config.ProviderConfigRef != nil && n.Config.ProviderConfigRef.KeyExpression != nil {
result.KeyResource = true
result.KeyExpression = n.Config.ProviderConfigRef.KeyExpression
}
return result
}
// See if we have a valid provider config from the state.
if n.storedProviderConfig.Provider.Type != "" {
if n.storedProviderConfig.ProviderConfig.Provider.Type != "" {
// An address from the state must match exactly, since we must ensure
// we refresh/destroy a resource with the same provider configuration
// that created it.
return n.storedProviderConfig
return RequestedProvider{
ProviderConfig: n.storedProviderConfig.ProviderConfig,
KeyExpression: n.storedProviderConfig.KeyExpression,
KeyModule: n.storedProviderConfig.KeyModule,
KeyResource: n.storedProviderConfig.KeyResource,
KeyExact: n.storedProviderConfig.KeyExact,
}
}
// We might have an import target that is providing a specific provider,
@ -325,29 +346,34 @@ func (n *NodeAbstractResource) ProvidedBy() addrs.ProviderConfig {
// of them should be. They should also all have the same provider, so it
// shouldn't matter which we check here, as they'll all give the same.
if n.importTargets[0].Config != nil && n.importTargets[0].Config.ProviderConfigRef != nil {
return addrs.LocalProviderConfig{
LocalName: n.importTargets[0].Config.ProviderConfigRef.Name,
Alias: n.importTargets[0].Config.ProviderConfigRef.Alias,
return RequestedProvider{
ProviderConfig: addrs.LocalProviderConfig{
LocalName: n.importTargets[0].Config.ProviderConfigRef.Name,
Alias: n.importTargets[0].Config.ProviderConfigRef.Alias,
},
// This is where we would specify a key expression if that was supported for import blocks
}
}
}
// No provider configuration found; return a default address
return addrs.LocalProviderConfig{
LocalName: n.Addr.Resource.ImpliedProvider(), // Unused, see ProviderTransformer
return RequestedProvider{
ProviderConfig: addrs.LocalProviderConfig{
LocalName: n.Addr.Resource.ImpliedProvider(), // Unused, see ProviderTransformer
},
}
}
// GraphNodeProviderConsumer
func (n *NodeAbstractResource) Provider() addrs.Provider {
if n.ResolvedProvider.Provider.Type != "" {
return n.ResolvedProvider.Provider
if n.ResolvedProvider.ProviderConfig.Provider.Type != "" {
return n.ResolvedProvider.ProviderConfig.Provider
}
if n.Config != nil {
return n.Config.Provider
}
if n.storedProviderConfig.Provider.Type != "" {
return n.storedProviderConfig.Provider
if n.storedProviderConfig.ProviderConfig.Provider.Type != "" {
return n.storedProviderConfig.ProviderConfig.Provider
}
if len(n.importTargets) > 0 {
@ -460,7 +486,7 @@ func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.Ab
return diags
}
state.SetResourceProvider(addr, n.ResolvedProvider)
state.SetResourceProvider(addr, n.ResolvedProvider.ProviderConfig)
expander.SetResourceCount(addr.Module, n.Addr.Resource, count)
case n.Config != nil && n.Config.ForEach != nil:
@ -472,11 +498,11 @@ func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.Ab
// This method takes care of all of the business logic of updating this
// while ensuring that any existing instances are preserved, etc.
state.SetResourceProvider(addr, n.ResolvedProvider)
state.SetResourceProvider(addr, n.ResolvedProvider.ProviderConfig)
expander.SetResourceForEach(addr.Module, n.Addr.Resource, forEach)
default:
state.SetResourceProvider(addr, n.ResolvedProvider)
state.SetResourceProvider(addr, n.ResolvedProvider.ProviderConfig)
expander.SetResourceSingle(addr.Module, n.Addr.Resource)
}
@ -485,9 +511,9 @@ func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.Ab
// readResourceInstanceState reads the current object for a specific instance in
// the state.
func (n *NodeAbstractResource) readResourceInstanceState(ctx EvalContext, addr addrs.AbsResourceInstance) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
func (n *NodeAbstractResourceInstance) readResourceInstanceState(ctx EvalContext, addr addrs.AbsResourceInstance) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
if err != nil {
diags = diags.Append(err)
return nil, diags
@ -526,9 +552,9 @@ func (n *NodeAbstractResource) readResourceInstanceState(ctx EvalContext, addr a
// readResourceInstanceStateDeposed reads the deposed object for a specific
// instance in the state.
func (n *NodeAbstractResource) readResourceInstanceStateDeposed(ctx EvalContext, addr addrs.AbsResourceInstance, key states.DeposedKey) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
func (n *NodeAbstractResourceInstance) readResourceInstanceStateDeposed(ctx EvalContext, addr addrs.AbsResourceInstance, key states.DeposedKey) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
if err != nil {
diags = diags.Append(err)
return nil, diags

View File

@ -46,6 +46,8 @@ type NodeAbstractResourceInstance struct {
// During import we may generate configuration for a resource, which needs
// to be stored in the final change.
generatedConfigHCL string
ResolvedProviderKey addrs.InstanceKey
}
// NewNodeAbstractResourceInstance creates an abstract resource instance graph
@ -105,6 +107,67 @@ func (n *NodeAbstractResourceInstance) References() []*addrs.Reference {
return nil
}
func (n *NodeAbstractResourceInstance) resolveProvider(ctx EvalContext) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
log.Printf("[TRACE] Resolving provider key for %s", n.Addr)
if n.ResolvedProvider.ProviderConfig.Provider.Type == "" {
return diags.Append(fmt.Errorf("attempting to resolve an unset provider at %s", n.Addr))
}
if n.ResolvedProvider.KeyExact != nil {
// Pass through from state
n.ResolvedProviderKey = n.ResolvedProvider.KeyExact
} else if n.ResolvedProvider.KeyExpression != nil {
if n.ResolvedProvider.KeyResource {
// Resolved from resource instance
n.ResolvedProviderKey, diags = resolveProviderResourceInstance(ctx, n.Config.ProviderConfigRef.KeyExpression, n.Addr)
} else {
// Resolved fro module instance
moduleInstanceForKey := n.Addr.Module[:len(n.ResolvedProvider.KeyModule)]
if !moduleInstanceForKey.Module().Equal(n.ResolvedProvider.KeyModule) {
panic(fmt.Sprintf("Invalid module key expression location %s in resource %s", n.ResolvedProvider.KeyModule, n.Addr))
}
n.ResolvedProviderKey, diags = resolveProviderModuleInstance(ctx, n.ResolvedProvider.KeyExpression, moduleInstanceForKey, n.Addr.String())
}
}
if diags.HasErrors() {
return diags
}
log.Printf("[TRACE] Resolved provider key for %s as %s", n.Addr, n.ResolvedProviderKey)
// This duplicates a lot of getProvider() and should be refactored as the only place to resolve the provider eventually
// This is also quite similar to ProviderTransformer's handling of removed providers for orphaned nodes
if n.ResolvedProvider.ProviderConfig.Provider.Type == "" {
// Should never happen
panic("EnsureProvider used with uninitialized provider configuration address")
}
provider := ctx.Provider(n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
if provider != nil {
// All good
return nil
}
if n.ResolvedProviderKey == nil {
// Probably an OpenTofu bug
return diags.Append(fmt.Errorf("provider %s not initialized for resource %s", n.ResolvedProvider.ProviderConfig.InstanceString(n.ResolvedProviderKey), n.Addr))
}
return diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Provider instance not present",
fmt.Sprintf(
"To work with %s its original provider instance at %s is required, but it has been removed. This occurs when an element is removed from the provider configuration's for_each collection while objects created by that the associated provider instance still exist in the state. Re-add the for_each element to destroy %s, after which you can remove the provider configuration again.\n\nThis is commonly caused by using the same for_each collection both for a resource (or its containing module) and its associated provider configuration. To successfully remove an instance of a resource it must be possible to remove the corresponding element from the resource's for_each collection while retaining the corresponding element in the provider's for_each collection.",
n.Addr, n.ResolvedProvider.ProviderConfig.InstanceString(n.ResolvedProviderKey), n.Addr,
),
))
}
// StateDependencies returns the dependencies which will be saved in the state
// for managed resources, or the most current dependencies for data resources.
func (n *NodeAbstractResourceInstance) StateDependencies() []addrs.ConfigResource {
@ -135,7 +198,10 @@ func (n *NodeAbstractResourceInstance) AttachResourceState(s *states.Resource) {
}
log.Printf("[TRACE] NodeAbstractResourceInstance.AttachResourceState for %s", n.Addr)
n.instanceState = s.Instance(n.Addr.Resource.Key)
n.storedProviderConfig = s.ProviderConfig
n.storedProviderConfig = ResolvedProvider{
ProviderConfig: s.ProviderConfig,
KeyExact: n.instanceState.ProviderKey,
}
}
// readDiff returns the planned change for a particular resource instance
@ -273,7 +339,7 @@ func (n *NodeAbstractResourceInstance) writeResourceInstanceStateDeposed(ctx Eva
// objects you are intending to write.
func (n *NodeAbstractResourceInstance) writeResourceInstanceStateImpl(ctx EvalContext, deposedKey states.DeposedKey, obj *states.ResourceInstanceObject, targetState phaseState) error {
absAddr := n.Addr
_, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := n.getProvider(ctx)
if err != nil {
return err
}
@ -311,11 +377,11 @@ func (n *NodeAbstractResourceInstance) writeResourceInstanceStateImpl(ctx EvalCo
var write func(src *states.ResourceInstanceObjectSrc)
if deposedKey == states.NotDeposed {
write = func(src *states.ResourceInstanceObjectSrc) {
state.SetResourceInstanceCurrent(absAddr, src, n.ResolvedProvider)
state.SetResourceInstanceCurrent(absAddr, src, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
}
} else {
write = func(src *states.ResourceInstanceObjectSrc) {
state.SetResourceInstanceDeposed(absAddr, deposedKey, src, n.ResolvedProvider)
state.SetResourceInstanceDeposed(absAddr, deposedKey, src, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
}
}
@ -364,7 +430,7 @@ func (n *NodeAbstractResourceInstance) planForget(ctx EvalContext, currentState
Before: currentState.Value,
After: nullVal,
},
ProviderAddr: n.ResolvedProvider,
ProviderAddr: n.ResolvedProvider.ProviderConfig,
}
return plan
@ -377,7 +443,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState
absAddr := n.Addr
if n.ResolvedProvider.Provider.Type == "" {
if n.ResolvedProvider.ProviderConfig.Provider.Type == "" {
if deposedKey == "" {
panic(fmt.Sprintf("planDestroy for %s does not have ProviderAddr set", absAddr))
} else {
@ -401,7 +467,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState
Before: cty.NullVal(cty.DynamicPseudoType),
After: cty.NullVal(cty.DynamicPseudoType),
},
ProviderAddr: n.ResolvedProvider,
ProviderAddr: n.ResolvedProvider.ProviderConfig,
}
return noop, nil
}
@ -412,7 +478,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState
// operation.
nullVal := cty.NullVal(unmarkedPriorVal.Type())
provider, _, err := n.getProvider(ctx, n.ResolvedProvider)
provider, _, err := n.getProvider(ctx)
if err != nil {
return plan, diags.Append(err)
}
@ -452,7 +518,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState
"Provider produced invalid plan",
fmt.Sprintf(
"Provider %q planned a non-null destroy value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider.Provider, n.Addr),
n.ResolvedProvider.ProviderConfig, n.Addr),
),
)
return plan, diags
@ -469,7 +535,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState
After: nullVal,
},
Private: resp.PlannedPrivate,
ProviderAddr: n.ResolvedProvider,
ProviderAddr: n.ResolvedProvider.ProviderConfig,
}
return plan, diags
@ -491,7 +557,7 @@ func (n *NodeAbstractResourceInstance) writeChange(ctx EvalContext, change *plan
return nil
}
_, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := n.getProvider(ctx)
if err != nil {
return err
}
@ -542,7 +608,7 @@ func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, deposedKey state
} else {
log.Printf("[TRACE] NodeAbstractResourceInstance.refresh for %s (deposed object %s)", absAddr, deposedKey)
}
provider, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := n.getProvider(ctx)
if err != nil {
return state, diags.Append(err)
}
@ -617,7 +683,7 @@ func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, deposedKey state
"Provider produced invalid object",
fmt.Sprintf(
"Provider %q planned an invalid value for %s during refresh: %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider.Provider.String(), absAddr, tfdiags.FormatError(err),
n.ResolvedProvider.ProviderConfig.String(), absAddr, tfdiags.FormatError(err),
),
))
}
@ -630,7 +696,7 @@ func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, deposedKey state
// We had to fix up this object in some way, and we still need to
// accept any changes for compatibility, so all we can do is log a
// warning about the change.
log.Printf("[WARN] Provider %q produced an invalid new value containing null blocks for %q during refresh\n", n.ResolvedProvider.Provider, n.Addr)
log.Printf("[WARN] Provider %q produced an invalid new value containing null blocks for %q during refresh\n", n.ResolvedProvider.ProviderConfig.Provider, n.Addr)
}
ret := state.DeepCopy()
@ -643,7 +709,7 @@ func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, deposedKey state
// external changes which will be handled by the subsequent plan.
if errs := objchange.AssertObjectCompatible(schema, priorVal, ret.Value); len(errs) > 0 {
var buf strings.Builder
fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s during refresh.", n.ResolvedProvider.Provider.String(), absAddr)
fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s during refresh.", n.ResolvedProvider.ProviderConfig.Provider.String(), absAddr)
for _, err := range errs {
fmt.Fprintf(&buf, "\n - %s", tfdiags.FormatError(err))
}
@ -682,7 +748,7 @@ func (n *NodeAbstractResourceInstance) plan(
var keyData instances.RepetitionData
resource := n.Addr.Resource.Resource
provider, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := n.getProvider(ctx)
if err != nil {
return nil, nil, keyData, diags.Append(err)
}
@ -863,7 +929,7 @@ func (n *NodeAbstractResourceInstance) plan(
"Provider produced invalid plan",
fmt.Sprintf(
"Provider %q planned an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider.Provider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
n.ResolvedProvider.ProviderConfig, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
),
))
}
@ -881,7 +947,7 @@ func (n *NodeAbstractResourceInstance) plan(
var buf strings.Builder
fmt.Fprintf(&buf,
"[WARN] Provider %q produced an invalid plan for %s, but we are tolerating it because it is using the legacy plugin SDK.\n The following problems may be the cause of any confusing errors from downstream operations:",
n.ResolvedProvider.Provider, n.Addr,
n.ResolvedProvider.ProviderConfig, n.Addr,
)
for _, err := range errs {
fmt.Fprintf(&buf, "\n - %s", tfdiags.FormatError(err))
@ -894,7 +960,7 @@ func (n *NodeAbstractResourceInstance) plan(
"Provider produced invalid plan",
fmt.Sprintf(
"Provider %q planned an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider.Provider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
n.ResolvedProvider.ProviderConfig, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
),
))
}
@ -958,7 +1024,7 @@ func (n *NodeAbstractResourceInstance) plan(
"Provider produced invalid plan",
fmt.Sprintf(
"Provider %q has indicated \"requires replacement\" on %s for a non-existent attribute path %#v.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider.Provider, n.Addr, path,
n.ResolvedProvider.ProviderConfig, n.Addr, path,
),
))
continue
@ -1098,7 +1164,7 @@ func (n *NodeAbstractResourceInstance) plan(
"Provider produced invalid plan",
fmt.Sprintf(
"Provider %q planned an invalid value for %s%s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider.Provider, n.Addr, tfdiags.FormatError(err),
n.ResolvedProvider.ProviderConfig, n.Addr, tfdiags.FormatError(err),
),
))
}
@ -1161,7 +1227,7 @@ func (n *NodeAbstractResourceInstance) plan(
Addr: n.Addr,
PrevRunAddr: n.prevRunAddr(ctx),
Private: plannedPrivate,
ProviderAddr: n.ResolvedProvider,
ProviderAddr: n.ResolvedProvider.ProviderConfig,
Change: plans.Change{
Action: action,
Before: priorVal,
@ -1442,7 +1508,7 @@ func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal
config := *n.Config
provider, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := n.getProvider(ctx)
diags = diags.Append(err)
if diags.HasErrors() {
return newVal, diags
@ -1450,7 +1516,7 @@ func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource)
if schema == nil {
// Should be caught during validation, so we don't bother with a pretty error here
diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type))
diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider.ProviderConfig, n.Addr.ContainingResource().Resource.Type))
return newVal, diags
}
@ -1516,7 +1582,7 @@ func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal
"Provider produced invalid object",
fmt.Sprintf(
"Provider %q produced an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
n.ResolvedProvider.ProviderConfig, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
),
))
}
@ -1530,7 +1596,7 @@ func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal
"Provider produced null object",
fmt.Sprintf(
"Provider %q produced a null value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider, n.Addr,
n.ResolvedProvider.ProviderConfig, n.Addr,
),
))
}
@ -1541,7 +1607,7 @@ func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal
"Provider produced invalid object",
fmt.Sprintf(
"Provider %q produced a value for %s that is not wholly known.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider, n.Addr,
n.ResolvedProvider.ProviderConfig, n.Addr,
),
))
@ -1569,17 +1635,17 @@ func (n *NodeAbstractResourceInstance) providerMetas(ctx EvalContext) (cty.Value
var diags tfdiags.Diagnostics
metaConfigVal := cty.NullVal(cty.DynamicPseudoType)
_, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := n.getProvider(ctx)
if err != nil {
return metaConfigVal, diags.Append(err)
}
if n.ProviderMetas != nil {
if m, ok := n.ProviderMetas[n.ResolvedProvider.Provider]; ok && m != nil {
if m, ok := n.ProviderMetas[n.ResolvedProvider.ProviderConfig.Provider]; ok && m != nil {
// if the provider doesn't support this feature, throw an error
if providerSchema.ProviderMeta.Block == nil {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", n.ResolvedProvider.Provider.String()),
Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", n.ResolvedProvider.ProviderConfig.Provider.String()),
Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr.Resource),
Subject: &m.ProviderRange,
})
@ -1607,7 +1673,7 @@ func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, checkRule
var keyData instances.RepetitionData
var configVal cty.Value
_, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := n.getProvider(ctx)
if err != nil {
return nil, nil, keyData, diags.Append(err)
}
@ -1616,7 +1682,7 @@ func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, checkRule
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource)
if schema == nil {
// Should be caught during validation, so we don't bother with a pretty error here
diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type))
diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider.ProviderConfig, n.Addr.ContainingResource().Resource.Type))
return nil, nil, keyData, diags
}
@ -1710,7 +1776,7 @@ func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, checkRule
plannedChange := &plans.ResourceInstanceChange{
Addr: n.Addr,
PrevRunAddr: n.prevRunAddr(ctx),
ProviderAddr: n.ResolvedProvider,
ProviderAddr: n.ResolvedProvider.ProviderConfig,
Change: plans.Change{
Action: plans.Read,
Before: priorVal,
@ -1786,7 +1852,7 @@ func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, checkRule
plannedChange = &plans.ResourceInstanceChange{
Addr: n.Addr,
PrevRunAddr: n.prevRunAddr(ctx),
ProviderAddr: n.ResolvedProvider,
ProviderAddr: n.ResolvedProvider.ProviderConfig,
Change: plans.Change{
Action: plans.Read,
Before: priorVal,
@ -1881,7 +1947,7 @@ func (n *NodeAbstractResourceInstance) applyDataSource(ctx EvalContext, planned
var diags tfdiags.Diagnostics
var keyData instances.RepetitionData
_, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := n.getProvider(ctx)
if err != nil {
return nil, keyData, diags.Append(err)
}
@ -1899,7 +1965,7 @@ func (n *NodeAbstractResourceInstance) applyDataSource(ctx EvalContext, planned
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource)
if schema == nil {
// Should be caught during validation, so we don't bother with a pretty error here
diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type))
diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider.ProviderConfig, n.Addr.ContainingResource().Resource.Type))
return nil, keyData, diags
}
@ -2259,7 +2325,7 @@ func (n *NodeAbstractResourceInstance) apply(
return state, diags
}
provider, providerSchema, err := n.getProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := n.getProvider(ctx)
if err != nil {
return nil, diags.Append(err)
}
@ -2387,7 +2453,7 @@ func (n *NodeAbstractResourceInstance) apply(
"Provider produced invalid object",
fmt.Sprintf(
"Provider %q produced an invalid nil value after apply for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider.String(), n.Addr.String(),
n.ResolvedProvider.ProviderConfig.String(), n.Addr.String(),
),
))
}
@ -2400,7 +2466,7 @@ func (n *NodeAbstractResourceInstance) apply(
"Provider produced invalid object",
fmt.Sprintf(
"Provider %q produced an invalid value after apply for %s. The result cannot not be saved in the OpenTofu state.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.ResolvedProvider.String(), tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
n.ResolvedProvider.ProviderConfig.String(), tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
),
))
}
@ -2470,7 +2536,7 @@ func (n *NodeAbstractResourceInstance) apply(
// to notice in the logs if an inconsistency beyond the type system
// leads to a downstream provider failure.
var buf strings.Builder
fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s, but we are tolerating it because it is using the legacy plugin SDK.\n The following problems may be the cause of any confusing errors from downstream operations:", n.ResolvedProvider.String(), n.Addr)
fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s, but we are tolerating it because it is using the legacy plugin SDK.\n The following problems may be the cause of any confusing errors from downstream operations:", n.ResolvedProvider.ProviderConfig.String(), n.Addr)
for _, err := range errs {
fmt.Fprintf(&buf, "\n - %s", tfdiags.FormatError(err))
}
@ -2490,7 +2556,7 @@ func (n *NodeAbstractResourceInstance) apply(
"Provider produced inconsistent result after apply",
fmt.Sprintf(
"When applying changes to %s, provider %q produced an unexpected new value: %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
n.Addr, n.ResolvedProvider.String(), tfdiags.FormatError(err),
n.Addr, n.ResolvedProvider.ProviderConfig.String(), tfdiags.FormatError(err),
),
))
}
@ -2579,8 +2645,8 @@ func resourceInstancePrevRunAddr(ctx EvalContext, currentAddr addrs.AbsResourceI
return table.OldAddr(currentAddr)
}
func (n *NodeAbstractResourceInstance) getProvider(ctx EvalContext, addr addrs.AbsProviderConfig) (providers.Interface, providers.ProviderSchema, error) {
underlyingProvider, schema, err := getProvider(ctx, addr)
func (n *NodeAbstractResourceInstance) getProvider(ctx EvalContext) (providers.Interface, providers.ProviderSchema, error) {
underlyingProvider, schema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
if err != nil {
return nil, providers.ProviderSchema{}, err
}

View File

@ -131,9 +131,11 @@ func TestNodeAbstractResourceInstanceProvider(t *testing.T) {
// function. (This would not be valid for some other functions.)
Addr: test.Addr,
NodeAbstractResource: NodeAbstractResource{
Addr: test.Addr.ConfigResource(),
Config: test.Config,
storedProviderConfig: test.StoredProviderConfig,
Addr: test.Addr.ConfigResource(),
Config: test.Config,
storedProviderConfig: ResolvedProvider{
ProviderConfig: test.StoredProviderConfig,
},
},
}
got := node.Provider()
@ -170,7 +172,7 @@ func TestNodeAbstractResourceInstance_WriteResourceInstanceState(t *testing.T) {
Addr: mustResourceInstanceAddr("aws_instance.foo"),
// instanceState: obj,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}
ctx.ProviderProvider = mockProvider

View File

@ -145,7 +145,7 @@ func TestNodeAbstractResourceSetProvider(t *testing.T) {
p := node.ProvidedBy()
// the implied non-exact provider should be "terraform"
lpc, ok := p.(addrs.LocalProviderConfig)
lpc, ok := p.ProviderConfig.(addrs.LocalProviderConfig)
if !ok {
t.Fatalf("expected LocalProviderConfig, got %#v\n", p)
}
@ -165,10 +165,10 @@ func TestNodeAbstractResourceSetProvider(t *testing.T) {
Alias: "test",
}
node.SetProvider(resolved)
node.SetProvider(ResolvedProvider{ProviderConfig: resolved})
p = node.ProvidedBy()
apc, ok := p.(addrs.AbsProviderConfig)
apc, ok := p.ProviderConfig.(addrs.AbsProviderConfig)
if !ok {
t.Fatalf("expected AbsProviderConfig, got %#v\n", p)
}
@ -193,7 +193,7 @@ func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) {
tests := map[string]struct {
State *states.State
Node *NodeAbstractResource
Node *NodeAbstractResourceInstance
ExpectedInstanceId string
}{
"ReadState gets primary instance state": {
@ -211,12 +211,12 @@ func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) {
s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.NoKey), &states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"i-abc123"}`),
}, providerAddr)
}, providerAddr, addrs.NoKey)
}),
Node: &NodeAbstractResource{
Node: &NodeAbstractResourceInstance{NodeAbstractResource: NodeAbstractResource{
Addr: mustConfigResourceAddr("aws_instance.bar"),
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
}},
ExpectedInstanceId: "i-abc123",
},
}
@ -230,7 +230,7 @@ func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) {
ctx.ProviderProvider = providers.Interface(mockProvider)
got, readDiags := test.Node.readResourceInstanceState(ctx, test.Node.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
got, readDiags := test.Node.readResourceInstanceState(ctx, test.Node.NodeAbstractResource.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
if readDiags.HasErrors() {
t.Fatalf("[%s] Got err: %#v", k, readDiags.Err())
}
@ -259,7 +259,7 @@ func TestNodeAbstractResource_ReadResourceInstanceStateDeposed(t *testing.T) {
tests := map[string]struct {
State *states.State
Node *NodeAbstractResource
Node *NodeAbstractResourceInstance
ExpectedInstanceId string
}{
"ReadStateDeposed gets deposed instance": {
@ -277,12 +277,12 @@ func TestNodeAbstractResource_ReadResourceInstanceStateDeposed(t *testing.T) {
s.SetResourceInstanceDeposed(oneAddr.Instance(addrs.NoKey), states.DeposedKey("00000001"), &states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"i-abc123"}`),
}, providerAddr)
}, providerAddr, addrs.NoKey)
}),
Node: &NodeAbstractResource{
Node: &NodeAbstractResourceInstance{NodeAbstractResource: NodeAbstractResource{
Addr: mustConfigResourceAddr("aws_instance.bar"),
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
},
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
}},
ExpectedInstanceId: "i-abc123",
},
}
@ -296,7 +296,7 @@ func TestNodeAbstractResource_ReadResourceInstanceStateDeposed(t *testing.T) {
key := states.DeposedKey("00000001") // shim from legacy state assigns 0th deposed index this key
got, readDiags := test.Node.readResourceInstanceStateDeposed(ctx, test.Node.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), key)
got, readDiags := test.Node.readResourceInstanceStateDeposed(ctx, test.Node.NodeAbstractResource.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), key)
if readDiags.HasErrors() {
t.Fatalf("[%s] Got err: %#v", k, readDiags.Err())
}

View File

@ -141,6 +141,11 @@ func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperatio
return diags
}
diags = n.resolveProvider(ctx)
if diags.HasErrors() {
return diags
}
// Eval info is different depending on what kind of resource this is
switch n.Config.Mode {
case addrs.ManagedResourceMode:
@ -153,7 +158,7 @@ func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperatio
}
func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
@ -221,7 +226,7 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
var deposedKey states.DeposedKey
addr := n.ResourceInstanceAddr().Resource
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
@ -443,7 +448,7 @@ func (n *NodeApplyableResourceInstance) checkPlannedChange(ctx EvalContext, plan
"Provider produced inconsistent final plan",
fmt.Sprintf(
"When expanding the plan for %s to include new values learned so far during apply, provider %q changed the planned action from %s to %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
absAddr, n.ResolvedProvider.Provider.String(),
absAddr, n.ResolvedProvider.ProviderConfig.Provider.String(),
plannedChange.Action, actualChange.Action,
),
))
@ -457,7 +462,7 @@ func (n *NodeApplyableResourceInstance) checkPlannedChange(ctx EvalContext, plan
"Provider produced inconsistent final plan",
fmt.Sprintf(
"When expanding the plan for %s to include new values learned so far during apply, provider %q produced an invalid new value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
absAddr, n.ResolvedProvider.Provider.String(), tfdiags.FormatError(err),
absAddr, n.ResolvedProvider.ProviderConfig.Provider.String(), tfdiags.FormatError(err),
),
))
}

View File

@ -53,10 +53,10 @@ func TestNodeExpandApplyableResourceExecute(t *testing.T) {
Type: "test_instance",
Name: "foo",
},
ResolvedProvider: addrs.AbsProviderConfig{
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
}},
},
}
diags := node.Execute(ctx, walkApply)

View File

@ -328,12 +328,12 @@ func (n *NodeDestroyDeposedResourceInstanceObject) writeResourceInstanceState(ct
if obj == nil {
// No need to encode anything: we'll just write it directly.
state.SetResourceInstanceDeposed(absAddr, key, nil, n.ResolvedProvider)
state.SetResourceInstanceDeposed(absAddr, key, nil, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
log.Printf("[TRACE] writeResourceInstanceStateDeposed: removing state object for %s deposed %s", absAddr, key)
return nil
}
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
if err != nil {
return err
}
@ -351,7 +351,7 @@ func (n *NodeDestroyDeposedResourceInstanceObject) writeResourceInstanceState(ct
}
log.Printf("[TRACE] writeResourceInstanceStateDeposed: writing state object for %s deposed %s", absAddr, key)
state.SetResourceInstanceDeposed(absAddr, key, src, n.ResolvedProvider)
state.SetResourceInstanceDeposed(absAddr, key, src, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
return nil
}

View File

@ -96,7 +96,7 @@ func TestNodePlanDeposedResourceInstanceObject_Execute(t *testing.T) {
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: absResource,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`)},
},
},
DeposedKey: deposedKey,
@ -133,7 +133,7 @@ func TestNodeDestroyDeposedResourceInstanceObject_Execute(t *testing.T) {
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: absResource,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`)},
},
},
DeposedKey: deposedKey,
@ -174,7 +174,7 @@ func TestNodeDestroyDeposedResourceInstanceObject_WriteResourceInstanceState(t *
node := &NodeDestroyDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
Addr: mustResourceInstanceAddr("aws_instance.foo"),
},
@ -206,7 +206,7 @@ func TestNodeDestroyDeposedResourceInstanceObject_ExecuteMissingState(t *testing
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: mustResourceInstanceAddr("test_object.foo"),
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`)},
},
},
DeposedKey: states.NewDeposedKey(),
@ -229,7 +229,7 @@ func TestNodeForgetDeposedResourceInstanceObject_Execute(t *testing.T) {
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: absResource,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`)},
},
},
DeposedKey: deposedKey,
@ -261,6 +261,7 @@ func initMockEvalContext(resourceAddrs string, deposedKey states.DeposedKey) (*M
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
schema := providers.ProviderSchema{

View File

@ -49,10 +49,10 @@ func (n *NodeDestroyResourceInstance) Name() string {
return n.ResourceInstanceAddr().String() + " (destroy)"
}
func (n *NodeDestroyResourceInstance) ProvidedBy() addrs.ProviderConfig {
func (n *NodeDestroyResourceInstance) ProvidedBy() RequestedProvider {
if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
// indicate that this node does not require a configured provider
return nil
return RequestedProvider{}
}
return n.NodeAbstractResourceInstance.ProvidedBy()
}
@ -143,6 +143,10 @@ func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation)
// Eval info is different depending on what kind of resource this is
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
diags = n.resolveProvider(ctx)
if diags.HasErrors() {
return diags
}
return n.managedResourceExecute(ctx)
case addrs.DataResourceMode:
return n.dataResourceExecute(ctx)
@ -164,7 +168,7 @@ func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (d
var changeApply *plans.ResourceInstanceChange
var state *states.ResourceInstanceObject
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
@ -234,6 +238,6 @@ func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (d
func (n *NodeDestroyResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
log.Printf("[TRACE] NodeDestroyResourceInstance: removing state object for %s", n.Addr)
ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
return diags.Append(updateStateHook(ctx))
}

View File

@ -18,9 +18,10 @@ import (
)
type graphNodeImportState struct {
Addr addrs.AbsResourceInstance // Addr is the resource address to import into
ID string // ID is the ID to import as
ResolvedProvider addrs.AbsProviderConfig // provider node address after resolution
Addr addrs.AbsResourceInstance // Addr is the resource address to import into
ID string // ID is the ID to import as
ResolvedProvider ResolvedProvider // provider node address after resolution
ResolvedProviderKey addrs.InstanceKey // resolved from ResolvedProviderKeyExpr+ResolvedProviderKeyPath in method Execute
Schema *configschema.Block // Schema for processing the configuration body
SchemaVersion uint64 // Schema version of "Schema", as decided by the provider
@ -41,20 +42,26 @@ func (n *graphNodeImportState) Name() string {
}
// GraphNodeProviderConsumer
func (n *graphNodeImportState) ProvidedBy() addrs.ProviderConfig {
func (n *graphNodeImportState) ProvidedBy() RequestedProvider {
// This has already been resolved by nodeExpandPlannableResource
return n.ResolvedProvider
return RequestedProvider{
ProviderConfig: n.ResolvedProvider.ProviderConfig,
KeyExpression: n.ResolvedProvider.KeyExpression,
KeyModule: n.ResolvedProvider.KeyModule,
KeyResource: n.ResolvedProvider.KeyResource,
KeyExact: n.ResolvedProvider.KeyExact,
}
}
// GraphNodeProviderConsumer
func (n *graphNodeImportState) Provider() addrs.Provider {
// This has already been resolved by nodeExpandPlannableResource
return n.ResolvedProvider.Provider
return n.ResolvedProvider.ProviderConfig.Provider
}
// GraphNodeProviderConsumer
func (n *graphNodeImportState) SetProvider(addr addrs.AbsProviderConfig) {
n.ResolvedProvider = addr
func (n *graphNodeImportState) SetProvider(resolved ResolvedProvider) {
n.ResolvedProvider = resolved
}
// GraphNodeModuleInstance
@ -72,7 +79,27 @@ func (n *graphNodeImportState) Execute(ctx EvalContext, op walkOperation) (diags
// Reset our states
n.states = nil
provider, _, err := getProvider(ctx, n.ResolvedProvider)
// FIXME, yuck: borrowing some logic that's currently only available for the abstract resource instance
// node, even though graphNodeImportState doesn't actually embed that type for some reason.
// Let's factor this logic out somewhere that's explicitly shareable.
asAbsNode := &NodeAbstractResourceInstance{
Addr: n.Addr,
NodeAbstractResource: NodeAbstractResource{
Addr: n.Addr.ConfigResource(),
Config: n.Config,
Schema: n.Schema,
SchemaVersion: n.SchemaVersion,
ResolvedProvider: n.ResolvedProvider,
},
}
diags = diags.Append(asAbsNode.resolveProvider(ctx))
if diags.HasErrors() {
return diags
}
n.ResolvedProviderKey = asAbsNode.ResolvedProviderKey
log.Printf("[TRACE] graphNodeImportState: importing using %s instance %s", n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
provider, _, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
@ -172,12 +199,13 @@ func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
// safe.
for i, state := range n.states {
g.Add(&graphNodeImportStateSub{
TargetAddr: addrs[i],
State: state,
ResolvedProvider: n.ResolvedProvider,
Schema: n.Schema,
SchemaVersion: n.SchemaVersion,
Config: n.Config,
TargetAddr: addrs[i],
State: state,
ResolvedProvider: n.ResolvedProvider,
ResolvedProviderKey: n.ResolvedProviderKey,
Schema: n.Schema,
SchemaVersion: n.SchemaVersion,
Config: n.Config,
})
}
@ -191,14 +219,14 @@ func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
// and is part of the subgraph. This node is responsible for refreshing
// and adding a resource to the state once it is imported.
type graphNodeImportStateSub struct {
TargetAddr addrs.AbsResourceInstance
State providers.ImportedResource
ResolvedProvider addrs.AbsProviderConfig
TargetAddr addrs.AbsResourceInstance
State providers.ImportedResource
ResolvedProvider ResolvedProvider
ResolvedProviderKey addrs.InstanceKey // the dynamic instance ResolvedProvider
Schema *configschema.Block // Schema for processing the configuration body
SchemaVersion uint64 // Schema version of "Schema", as decided by the provider
Config *configs.Resource // Config is the resource in the config
}
var (
@ -230,6 +258,7 @@ func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) (di
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: n.ResolvedProvider,
},
ResolvedProviderKey: n.ResolvedProviderKey,
}
state, refreshDiags := riNode.refresh(ctx, states.NotDeposed, state)
diags = diags.Append(refreshDiags)

View File

@ -128,6 +128,7 @@ func (n *nodeExpandPlannableResource) DynamicExpand(ctx EvalContext) (*Graph, er
// Add the config and state since we don't do that via transforms
a.Config = n.Config
a.ResolvedProvider = n.ResolvedProvider
// ResolvedProviderKey set in AttachResourceState
a.Schema = n.Schema
a.ProvisionerSchemas = n.ProvisionerSchemas
a.ProviderMetas = n.ProviderMetas
@ -380,6 +381,7 @@ func (n *nodeExpandPlannableResource) resourceInstanceSubgraph(ctx EvalContext,
// Add the config and state since we don't do that via transforms
a.Config = n.Config
a.ResolvedProvider = n.ResolvedProvider
// ResolvedProviderKey will be set during AttachResourceState
a.Schema = n.Schema
a.ProvisionerSchemas = n.ProvisionerSchemas
a.ProviderMetas = n.ProviderMetas
@ -427,6 +429,6 @@ func (n *nodeExpandPlannableResource) resourceInstanceSubgraph(ctx EvalContext,
Steps: steps,
Name: "nodeExpandPlannableResource",
}
graph, diags := b.Build(addr.Module)
return graph, diags.ErrWithWarnings()
graph, graphDiags := b.Build(addr.Module)
return graph, diags.Append(graphDiags).ErrWithWarnings()
}

View File

@ -121,7 +121,7 @@ func (n *NodePlanDestroyableResourceInstance) dataResourceExecute(ctx EvalContex
Before: cty.NullVal(cty.DynamicPseudoType),
After: cty.NullVal(cty.DynamicPseudoType),
},
ProviderAddr: n.ResolvedProvider,
ProviderAddr: n.ResolvedProvider.ProviderConfig,
}
return diags.Append(n.writeChange(ctx, change, ""))
}

View File

@ -86,6 +86,11 @@ var (
func (n *NodePlannableResourceInstance) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
addr := n.ResourceInstanceAddr()
diags := n.resolveProvider(ctx)
if diags.HasErrors() {
return diags
}
// Eval info is different depending on what kind of resource this is
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
@ -103,7 +108,7 @@ func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) (di
var change *plans.ResourceInstanceChange
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
@ -164,7 +169,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
checkRuleSeverity = tfdiags.Warning
}
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
diags = diags.Append(err)
if diags.HasErrors() {
return diags
@ -294,7 +299,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
change := &plans.ResourceInstanceChange{
Addr: n.Addr,
PrevRunAddr: n.prevRunAddr(ctx),
ProviderAddr: n.ResolvedProvider,
ProviderAddr: n.ResolvedProvider.ProviderConfig,
Change: plans.Change{
// we only need a placeholder, so this will be a NoOp
Action: plans.NoOp,
@ -532,6 +537,7 @@ func (n *NodePlannableResourceInstance) importState(ctx EvalContext, addr addrs.
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: n.ResolvedProvider,
},
ResolvedProviderKey: n.ResolvedProviderKey,
}
instanceRefreshState, refreshDiags := riNode.refresh(ctx, states.NotDeposed, importedState)
diags = diags.Append(refreshDiags)
@ -632,7 +638,7 @@ func (n *NodePlannableResourceInstance) importState(ctx EvalContext, addr addrs.
Name: n.Addr.Resource.Resource.Name,
Config: remain,
Managed: &configs.ManagedResource{},
Provider: n.ResolvedProvider.Provider,
Provider: n.ResolvedProvider.ProviderConfig.Provider,
}
}
@ -675,8 +681,8 @@ func (n *NodePlannableResourceInstance) generateHCLStringAttributes(addr addrs.A
)
providerAddr := addrs.LocalProviderConfig{
LocalName: n.ResolvedProvider.Provider.Type,
Alias: n.ResolvedProvider.Alias,
LocalName: n.ResolvedProvider.ProviderConfig.Provider.Type,
Alias: n.ResolvedProvider.ProviderConfig.Alias,
}
return genconfig.GenerateResourceContents(addr, filteredSchema, providerAddr, state.Value)

View File

@ -57,6 +57,10 @@ func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOp
// Eval info is different depending on what kind of resource this is
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
diags := n.resolveProvider(ctx)
if diags.HasErrors() {
return diags
}
return n.managedResourceExecute(ctx)
case addrs.DataResourceMode:
return n.dataResourceExecute(ctx)
@ -65,10 +69,10 @@ func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOp
}
}
func (n *NodePlannableResourceInstanceOrphan) ProvidedBy() addrs.ProviderConfig {
func (n *NodePlannableResourceInstanceOrphan) ProvidedBy() RequestedProvider {
if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
// indicate that this node does not require a configured provider
return nil
return RequestedProvider{}
}
return n.NodeAbstractResourceInstance.ProvidedBy()
}
@ -80,10 +84,10 @@ func (n *NodePlannableResourceInstanceOrphan) dataResourceExecute(ctx EvalContex
// we need to update both the refresh state to refresh the current data
// source, and the working state for plan-time evaluations.
refreshState := ctx.RefreshState()
refreshState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
refreshState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
workingState := ctx.State()
workingState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
workingState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider.ProviderConfig, n.ResolvedProviderKey)
return nil
}

View File

@ -108,6 +108,7 @@ func TestNodeResourcePlanOrphan_Execute(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
schema := providers.ProviderSchema{
@ -142,10 +143,10 @@ func TestNodeResourcePlanOrphan_Execute(t *testing.T) {
node := NodePlannableResourceInstanceOrphan{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: addrs.AbsProviderConfig{
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
}},
},
Addr: absResource,
},
@ -188,6 +189,7 @@ func TestNodeResourcePlanOrphanExecute_alreadyDeleted(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
refreshState := state.DeepCopy()
prevRunState := state.DeepCopy()
@ -217,10 +219,10 @@ func TestNodeResourcePlanOrphanExecute_alreadyDeleted(t *testing.T) {
node := NodePlannableResourceInstanceOrphan{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: addrs.AbsProviderConfig{
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
}},
},
Addr: mustResourceInstanceAddr("test_object.foo"),
},
@ -270,6 +272,7 @@ func TestNodeResourcePlanOrphanExecute_deposed(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
refreshState := state.DeepCopy()
prevRunState := state.DeepCopy()
@ -299,10 +302,10 @@ func TestNodeResourcePlanOrphanExecute_deposed(t *testing.T) {
node := NodePlannableResourceInstanceOrphan{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: addrs.AbsProviderConfig{
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
}},
},
Addr: mustResourceInstanceAddr("test_object.foo"),
},

View File

@ -282,7 +282,7 @@ var connectionBlockSupersetSchema = &configschema.Block{
func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider.ProviderConfig, addrs.NoKey) // Provider Instance Keys are ignored during validate
diags = diags.Append(err)
if diags.HasErrors() {
return diags

View File

@ -189,7 +189,7 @@ func TestNodeValidatableResource_ValidateResource_managedResource(t *testing.T)
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}
@ -257,7 +257,7 @@ func TestNodeValidatableResource_ValidateResource_managedResourceCount(t *testin
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}
@ -303,7 +303,7 @@ func TestNodeValidatableResource_ValidateResource_dataSource(t *testing.T) {
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}
@ -339,7 +339,7 @@ func TestNodeValidatableResource_ValidateResource_valid(t *testing.T) {
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_object.foo"),
Config: rc,
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}
@ -376,7 +376,7 @@ func TestNodeValidatableResource_ValidateResource_warningsAndErrorsPassedThrough
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}
@ -438,7 +438,7 @@ func TestNodeValidatableResource_ValidateResource_invalidDependsOn(t *testing.T)
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}
@ -522,7 +522,7 @@ func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesNonexisten
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}
@ -605,7 +605,7 @@ func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesComputed(t
NodeAbstractResource: &NodeAbstractResource{
Addr: mustConfigResourceAddr("test_foo.bar"),
Config: rc,
ResolvedProvider: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
ResolvedProvider: ResolvedProvider{ProviderConfig: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)},
},
}

View File

@ -155,6 +155,7 @@ func testSetResourceInstanceCurrent(module *states.Module, resource, attrsJson,
AttrsJSON: []byte(attrsJson),
},
mustProviderConfig(provider),
addrs.NoKey,
)
}
@ -168,6 +169,7 @@ func testSetResourceInstanceTainted(module *states.Module, resource, attrsJson,
AttrsJSON: []byte(attrsJson),
},
mustProviderConfig(provider),
addrs.NoKey,
)
}

View File

@ -65,7 +65,7 @@ run "test_case" {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
provider: &MockProvider{
GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
@ -123,7 +123,7 @@ run "test_case" {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
provider: &MockProvider{
GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
@ -183,7 +183,7 @@ run "test_case" {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
variables: InputValues{
"value": {
@ -240,7 +240,7 @@ run "test_case" {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
provider: &MockProvider{
GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
@ -303,7 +303,7 @@ run "test_case" {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
provider: &MockProvider{
GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
@ -403,7 +403,7 @@ run "test_case" {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
plan: &plans.Plan{
Changes: &plans.Changes{
@ -479,7 +479,7 @@ run "test_case" {
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
})
}, addrs.NoKey)
}),
plan: &plans.Plan{
Changes: &plans.Changes{

View File

@ -105,6 +105,7 @@ func TestCBDEdgeTransformer(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -114,6 +115,7 @@ func TestCBDEdgeTransformer(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
g := cbdTestGraph(t, "transform-destroy-cbd-edge-basic", changes, state)
@ -166,6 +168,7 @@ func TestCBDEdgeTransformerMulti(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -174,6 +177,7 @@ func TestCBDEdgeTransformerMulti(t *testing.T) {
AttrsJSON: []byte(`{"id":"B"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.C").Resource,
@ -186,6 +190,7 @@ func TestCBDEdgeTransformerMulti(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
g := cbdTestGraph(t, "transform-destroy-cbd-edge-multi", changes, state)
@ -242,6 +247,7 @@ func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B[0]").Resource,
@ -251,6 +257,7 @@ func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B[1]").Resource,
@ -260,6 +267,7 @@ func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
g := cbdTestGraph(t, "transform-cbd-destroy-edge-count", changes, state)
@ -319,6 +327,7 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.A[1]").Resource,
@ -327,6 +336,7 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B[0]").Resource,
@ -336,6 +346,7 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B[1]").Resource,
@ -345,6 +356,7 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
g := cbdTestGraph(t, "transform-cbd-destroy-edge-both-count", changes, state)

View File

@ -102,7 +102,7 @@ func (t *DestroyEdgeTransformer) tryInterProviderDestroyEdge(g *Graph, from, to
// from the same provider instance.
getComparableProvider := func(pc GraphNodeProviderConsumer) string {
p := pc.ProvidedBy()
switch p := p.(type) {
switch p := p.ProviderConfig.(type) {
case addrs.AbsProviderConfig:
return p.String()
case addrs.LocalProviderConfig:

View File

@ -33,6 +33,7 @@ func TestDestroyEdgeTransformer_basic(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -42,6 +43,7 @@ func TestDestroyEdgeTransformer_basic(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
t.Fatal(err)
@ -74,6 +76,7 @@ func TestDestroyEdgeTransformer_multi(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -83,6 +86,7 @@ func TestDestroyEdgeTransformer_multi(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.C").Resource,
@ -95,6 +99,7 @@ func TestDestroyEdgeTransformer_multi(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
@ -143,6 +148,7 @@ func TestDestroyEdgeTransformer_module(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.test_object.b")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.b").Resource,
@ -151,6 +157,7 @@ func TestDestroyEdgeTransformer_module(t *testing.T) {
AttrsJSON: []byte(`{"id":"b","test_string":"x"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
@ -186,6 +193,7 @@ func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) {
AttrsJSON: []byte(`{"id":"a"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.b").Resource,
@ -197,6 +205,7 @@ func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
child.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.c").Resource,
@ -209,6 +218,7 @@ func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) {
},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
}
@ -269,6 +279,7 @@ func TestDestroyEdgeTransformer_destroyThenUpdate(t *testing.T) {
AttrsJSON: []byte(`{"id":"A","test_string":"old"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -278,6 +289,7 @@ func TestDestroyEdgeTransformer_destroyThenUpdate(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
@ -367,6 +379,7 @@ func TestPruneUnusedNodesTransformer_rootModuleOutputValues(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
providerCfgAddr,
addrs.NoKey,
)
})
changes := plans.NewChanges()
@ -461,6 +474,7 @@ func TestDestroyEdgeTransformer_noOp(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.B").Resource,
@ -470,6 +484,7 @@ func TestDestroyEdgeTransformer_noOp(t *testing.T) {
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.C").Resource,
@ -480,6 +495,7 @@ func TestDestroyEdgeTransformer_noOp(t *testing.T) {
mustConfigResourceAddr("test_object.B")},
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
@ -540,6 +556,7 @@ func TestDestroyEdgeTransformer_dataDependsOn(t *testing.T) {
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
addrs.NoKey,
)
if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {

View File

@ -46,10 +46,10 @@ func TestGraphNodeImportStateExecute(t *testing.T) {
Name: "foo",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
ID: "bar",
ResolvedProvider: addrs.AbsProviderConfig{
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
}},
}
diags := node.Execute(ctx, walkImport)
@ -102,10 +102,10 @@ func TestGraphNodeImportStateSubExecute(t *testing.T) {
Name: "foo",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
State: importedResource,
ResolvedProvider: addrs.AbsProviderConfig{
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
}},
}
diags := node.Execute(ctx, walkImport)
if diags.HasErrors() {
@ -164,10 +164,10 @@ func TestGraphNodeImportStateSubExecuteNull(t *testing.T) {
Name: "foo",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
State: importedResource,
ResolvedProvider: addrs.AbsProviderConfig{
ResolvedProvider: ResolvedProvider{ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
}},
}
diags := node.Execute(ctx, walkImport)
if !diags.HasErrors() {

View File

@ -23,6 +23,7 @@ func TestOrphanResourceCountTransformer(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
@ -31,6 +32,7 @@ func TestOrphanResourceCountTransformer(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -39,6 +41,7 @@ func TestOrphanResourceCountTransformer(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
g := Graph{Path: addrs.RootModuleInstance}
@ -74,6 +77,7 @@ func TestOrphanResourceCountTransformer_zero(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
@ -82,6 +86,7 @@ func TestOrphanResourceCountTransformer_zero(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -90,6 +95,7 @@ func TestOrphanResourceCountTransformer_zero(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
g := Graph{Path: addrs.RootModuleInstance}
@ -125,6 +131,7 @@ func TestOrphanResourceCountTransformer_oneIndex(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
@ -133,6 +140,7 @@ func TestOrphanResourceCountTransformer_oneIndex(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -141,6 +149,7 @@ func TestOrphanResourceCountTransformer_oneIndex(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
g := Graph{Path: addrs.RootModuleInstance}
@ -176,6 +185,7 @@ func TestOrphanResourceCountTransformer_deposed(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
@ -184,6 +194,7 @@ func TestOrphanResourceCountTransformer_deposed(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
@ -192,6 +203,7 @@ func TestOrphanResourceCountTransformer_deposed(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
@ -201,6 +213,7 @@ func TestOrphanResourceCountTransformer_deposed(t *testing.T) {
AttrsJSON: []byte(`{"id":"foo"}`),
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
g := Graph{Path: addrs.RootModuleInstance}
@ -246,6 +259,7 @@ func TestOrphanResourceCountTransformer_ForEachEdgesAdded(t *testing.T) {
Status: states.ObjectReady,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
// NoKey'd resource
@ -262,6 +276,7 @@ func TestOrphanResourceCountTransformer_ForEachEdgesAdded(t *testing.T) {
Status: states.ObjectReady,
},
mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
addrs.NoKey,
)
})

View File

@ -35,6 +35,7 @@ func TestOrphanResourceInstanceTransformer(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// The orphan
@ -54,6 +55,7 @@ func TestOrphanResourceInstanceTransformer(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
// A deposed orphan should not be handled by this transformer
@ -74,6 +76,7 @@ func TestOrphanResourceInstanceTransformer(t *testing.T) {
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -123,6 +126,7 @@ func TestOrphanResourceInstanceTransformer_countGood(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -140,6 +144,7 @@ func TestOrphanResourceInstanceTransformer_countGood(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -188,6 +193,7 @@ func TestOrphanResourceInstanceTransformer_countBad(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -205,6 +211,7 @@ func TestOrphanResourceInstanceTransformer_countBad(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})
@ -253,6 +260,7 @@ func TestOrphanResourceInstanceTransformer_modules(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
addrs.Resource{
@ -270,6 +278,7 @@ func TestOrphanResourceInstanceTransformer_modules(t *testing.T) {
Provider: addrs.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
addrs.NoKey,
)
})

View File

@ -13,7 +13,6 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/dag"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
)
@ -62,6 +61,22 @@ type GraphNodeCloseProvider interface {
CloseProviderAddr() addrs.AbsProviderConfig
}
type RequestedProvider struct {
ProviderConfig addrs.ProviderConfig
KeyExpression hcl.Expression
KeyModule addrs.Module
KeyResource bool
KeyExact addrs.InstanceKey
}
type ResolvedProvider struct {
ProviderConfig addrs.AbsProviderConfig
KeyExpression hcl.Expression
KeyModule addrs.Module
KeyResource bool
KeyExact addrs.InstanceKey
}
// GraphNodeProviderConsumer is an interface that nodes that require
// a provider must implement. ProvidedBy must return the address of the provider
// to use, which will be resolved to a configuration either in the same module
@ -80,13 +95,13 @@ type GraphNodeProviderConsumer interface {
// resolved elsewhere and must be referenced directly. No inheritence
// logic is allowed.
// Examples: state, resource instance (resolved),
ProvidedBy() addrs.ProviderConfig
ProvidedBy() RequestedProvider
// Provider() returns the Provider FQN for the node.
Provider() (provider addrs.Provider)
// Set the resolved provider address for this resource.
SetProvider(addrs.AbsProviderConfig)
SetProvider(ResolvedProvider)
}
// ProviderTransformer is a GraphTransformer that maps resources to providers
@ -114,11 +129,11 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
continue
}
req := pv.ProvidedBy()
if req == nil {
if req.ProviderConfig == nil {
// no provider is required
continue
}
switch providerAddr := req.(type) {
switch providerAddr := req.ProviderConfig.(type) {
case addrs.AbsProviderConfig:
target := m[providerAddr.String()]
if target == nil {
@ -148,10 +163,18 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
// error instead.
if p, ok := target.(*graphNodeProxyProvider); ok {
target = p.Target()
// We are ignoring p.keyExpr here for now
}
log.Printf("[DEBUG] ProviderTransformer: %q (%T) needs exactly %s", dag.VertexName(v), v, dag.VertexName(target))
pv.SetProvider(target.ProviderAddr())
pv.SetProvider(ResolvedProvider{
ProviderConfig: target.ProviderAddr(),
// Pass through key data
KeyExpression: req.KeyExpression,
KeyModule: req.KeyModule,
KeyResource: req.KeyResource,
KeyExact: req.KeyExact,
})
g.Connect(dag.BasicEdge(v, target))
case addrs.LocalProviderConfig:
// We assume that the value returned from Provider() has already been
@ -197,13 +220,30 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
continue
}
resolved := ResolvedProvider{
KeyResource: req.KeyResource,
KeyExpression: req.KeyExpression,
}
// see if this is a proxy provider pointing to another concrete config
if p, ok := target.(*graphNodeProxyProvider); ok {
target = p.Target()
targetExpr, targetPath := p.TargetExpr()
if targetExpr != nil {
if resolved.KeyResource {
// Module key and resource key are both required. This is not allowed!
diags = diags.Append(fmt.Errorf("provider instance key provided for both resource and module at %q, this is a bug and should be reported", dag.VertexName(v)))
continue
}
resolved.KeyExpression = targetExpr
resolved.KeyModule = targetPath
}
}
resolved.ProviderConfig = target.ProviderAddr()
log.Printf("[DEBUG] ProviderTransformer: %q (%T) needs %s", dag.VertexName(v), v, dag.VertexName(target))
pv.SetProvider(target.ProviderAddr())
pv.SetProvider(resolved)
g.Connect(dag.BasicEdge(v, target))
default:
panic(fmt.Sprintf("BUG: Invalid provider address type %T for %#v", req, req))
@ -222,20 +262,26 @@ type ProviderFunctionReference struct {
ProviderAlias string
}
type FunctionProvidedBy struct {
Provider addrs.AbsProviderConfig
KeyModule addrs.Module
KeyExpression hcl.Expression
}
// ProviderFunctionMapping maps a provider used by functions at a given location in the graph to the actual AbsProviderConfig
// that's required. This is due to the provider inheritence logic and proxy logic in the below
// transformer needing to be known in other parts of the application.
// Ideally, this would not be needed and be built like the ProviderTransformer. Unfortunately, it's
// a significant refactor to get to that point which adds a lot of complexity.
type ProviderFunctionMapping map[ProviderFunctionReference]addrs.AbsProviderConfig
type ProviderFunctionMapping map[ProviderFunctionReference]FunctionProvidedBy
func (m ProviderFunctionMapping) Lookup(module addrs.Module, pf addrs.ProviderFunction) (addrs.AbsProviderConfig, bool) {
addr, ok := m[ProviderFunctionReference{
func (m ProviderFunctionMapping) Lookup(module addrs.Module, pf addrs.ProviderFunction) (FunctionProvidedBy, bool) {
providedBy, ok := m[ProviderFunctionReference{
ModulePath: module.String(),
ProviderName: pf.ProviderName,
ProviderAlias: pf.ProviderAlias,
}]
return addr, ok
return providedBy, ok
}
// ProviderFunctionTransformer is a GraphTransformer that maps nodes which reference functions to providers
@ -318,32 +364,8 @@ func (t *ProviderFunctionTransformer) Transform(g *Graph) error {
// Providers with configuration will already exist within the graph and can be directly referenced
log.Printf("[TRACE] ProviderFunctionTransformer: exact match for %s serving %s", absPc, dag.VertexName(v))
} else {
// At this point, all provider schemas should be loaded. We
// can now check to see if configuration is optional for this function.
providerSchema, ok := providers.SchemaCache.Get(absPc.Provider)
if !ok {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Unknown provider for function",
Detail: fmt.Sprintf("Provider %q does not have it's schema initialized", absPc.Provider),
Subject: ref.SourceRange.ToHCL().Ptr(),
})
continue
}
_, functionOk := providerSchema.Functions[pf.Function]
if !functionOk {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Unknown provider function",
Detail: fmt.Sprintf("Provider %q does not have a function %q or has not been configured", absPc, pf.Function),
Subject: ref.SourceRange.ToHCL().Ptr(),
})
continue
}
// If this provider doesn't need to be configured then we can just
// stub it out with an init-only provider node, which will just
// start up the provider and fetch its schema.
// If this provider doesn't exist, stub it out with an init-only provider node
// This works for unconfigured functions only, but that validation is elsewhere
stubAddr := addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: absPc.Provider,
@ -364,9 +386,13 @@ func (t *ProviderFunctionTransformer) Transform(g *Graph) error {
}
}
var targetExpr hcl.Expression
var targetPath addrs.Module
// see if this is a proxy provider pointing to another concrete config
if p, ok := provider.(*graphNodeProxyProvider); ok {
provider = p.Target()
targetExpr, targetPath = p.TargetExpr()
}
log.Printf("[DEBUG] ProviderFunctionTransformer: %q (%T) needs %s", dag.VertexName(v), v, dag.VertexName(provider))
@ -374,7 +400,11 @@ func (t *ProviderFunctionTransformer) Transform(g *Graph) error {
// Save for future lookups
providerReferences[key] = provider
t.ProviderFunctionTracker[key] = provider.ProviderAddr()
t.ProviderFunctionTracker[key] = FunctionProvidedBy{
Provider: provider.ProviderAddr(),
KeyModule: targetPath,
KeyExpression: targetExpr,
}
}
}
}
@ -585,8 +615,9 @@ func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.Do
// configurations, and are removed after all the resources have been connected
// to their providers.
type graphNodeProxyProvider struct {
addr addrs.AbsProviderConfig
target GraphNodeProvider
addr addrs.AbsProviderConfig
target GraphNodeProvider
keyExpr hcl.Expression
}
var (
@ -616,6 +647,25 @@ func (n *graphNodeProxyProvider) Target() GraphNodeProvider {
}
}
// Find the *single* keyExpression that is used in the provider
// chain. This is not ideal, but it works with current constraints on this feature
func (n *graphNodeProxyProvider) TargetExpr() (hcl.Expression, addrs.Module) {
switch t := n.target.(type) {
case *graphNodeProxyProvider:
targetExpr, targetPath := t.TargetExpr()
if targetExpr != nil && n.keyExpr != nil {
// This should have already been handled during provider validation
panic(fmt.Sprintf("BUG: Only one key expression allowed in module provider chain: %q", n.Name()))
}
if n.keyExpr != nil {
return n.keyExpr, n.ModulePath()
}
return targetExpr, targetPath
default:
return n.keyExpr, n.ModulePath()
}
}
// ProviderConfigTransformer adds all provider nodes from the configuration and
// attaches the configs.
type ProviderConfigTransformer struct {
@ -816,8 +866,9 @@ func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, c *configs.Confi
}
proxy := &graphNodeProxyProvider{
addr: fullAddr,
target: parentProvider,
addr: fullAddr,
target: parentProvider,
keyExpr: pair.InParent.KeyExpression,
}
concreteProvider := t.providers[fullName]

View File

@ -57,6 +57,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.terraform.io/hashicorp/random"),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("aws_instance.example"),
@ -65,6 +66,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.terraform.io/hashicorp/aws"),
addrs.NoKey,
)
}),
},
@ -76,6 +78,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("aws_instance.example"),
@ -84,6 +87,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"),
addrs.NoKey,
)
}),
},
@ -99,6 +103,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.terraform.io/hashicorp/random"),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("aws_instance.example"),
@ -107,6 +112,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.terraform.io/hashicorp/aws"),
addrs.NoKey,
)
}),
},
@ -118,6 +124,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("aws_instance.example"),
@ -126,6 +133,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.terraform.io/hashicorp/aws"),
addrs.NoKey,
)
}),
},
@ -141,6 +149,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("aws_instance.example"),
@ -149,6 +158,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"),
addrs.NoKey,
)
}),
},
@ -160,6 +170,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("aws_instance.example"),
@ -168,6 +179,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"),
addrs.NoKey,
)
}),
},
@ -183,6 +195,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.terraform.io/hashicorp/random"),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("aws_instance.example"),
@ -191,6 +204,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.terraform.io/hashicorp/aws"),
addrs.NoKey,
)
}),
},
@ -202,6 +216,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
addrs.NoKey,
)
s.SetResourceInstanceCurrent(
mustParseInstAddr("aws_instance.example"),
@ -210,6 +225,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
AttrsJSON: []byte(`{}`),
},
makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"),
addrs.NoKey,
)
}),
},