states: new `Move` funcs for Resource, ResourceInstance, and ModuleInstances (#29068)
* states: add MoveAbsResource and MoveAbsResourceInstance state functions and corresponding syncState wrapper functions. * states: add MoveModuleInstance and MaybeMoveModuleInstance * addrs: adding a new function, ModuleInstance.IsDeclaredByCall, which returns true if the receiver is an instance of the given AbsModuleCall.
This commit is contained in:
parent
5a34825fc1
commit
43f698dc9d
|
@ -496,6 +496,28 @@ func (m ModuleInstance) absMoveableSigil() {
|
||||||
// ModuleInstance is moveable
|
// ModuleInstance is moveable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsDeclaredByCall returns true if the receiver is an instance of the given
|
||||||
|
// AbsModuleCall.
|
||||||
|
func (m ModuleInstance) IsDeclaredByCall(other AbsModuleCall) bool {
|
||||||
|
// Compare len(m) to len(other.Module+1) because the final module instance
|
||||||
|
// step in other is stored in the AbsModuleCall.Call
|
||||||
|
if len(m) > len(other.Module)+1 || len(m) == 0 && len(other.Module) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the other's ModuleInstance matches the receiver.
|
||||||
|
inst, lastStep := other.Module, other.Call
|
||||||
|
for i := range inst {
|
||||||
|
if inst[i] != m[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now compare the final step of the received with the other Call, where
|
||||||
|
// only the name needs to match.
|
||||||
|
return lastStep.Name == m[len(m)-1].Name
|
||||||
|
}
|
||||||
|
|
||||||
func (s ModuleInstanceStep) String() string {
|
func (s ModuleInstanceStep) String() string {
|
||||||
if s.InstanceKey != NoKey {
|
if s.InstanceKey != NoKey {
|
||||||
return s.Name + s.InstanceKey.String()
|
return s.Name + s.InstanceKey.String()
|
||||||
|
|
|
@ -91,3 +91,80 @@ func BenchmarkStringLong(b *testing.B) {
|
||||||
addr.String()
|
addr.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestModuleInstance_IsDeclaredByCall(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
instance ModuleInstance
|
||||||
|
call AbsModuleCall
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
ModuleInstance{},
|
||||||
|
AbsModuleCall{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustParseModuleInstanceStr("module.child"),
|
||||||
|
AbsModuleCall{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ModuleInstance{},
|
||||||
|
AbsModuleCall{
|
||||||
|
RootModuleInstance,
|
||||||
|
ModuleCall{Name: "child"},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustParseModuleInstanceStr("module.child"),
|
||||||
|
AbsModuleCall{ // module.child
|
||||||
|
RootModuleInstance,
|
||||||
|
ModuleCall{Name: "child"},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustParseModuleInstanceStr(`module.child`),
|
||||||
|
AbsModuleCall{ // module.kinder.module.child
|
||||||
|
mustParseModuleInstanceStr("module.kinder"),
|
||||||
|
ModuleCall{Name: "child"},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustParseModuleInstanceStr("module.kinder"),
|
||||||
|
// module.kinder.module.child contains module.kinder, but is not itself an instance of module.kinder
|
||||||
|
AbsModuleCall{
|
||||||
|
mustParseModuleInstanceStr("module.kinder"),
|
||||||
|
ModuleCall{Name: "child"},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustParseModuleInstanceStr("module.child"),
|
||||||
|
AbsModuleCall{
|
||||||
|
mustParseModuleInstanceStr(`module.kinder["a"]`),
|
||||||
|
ModuleCall{Name: "kinder"},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(fmt.Sprintf("%q.IsCallInstance(%q)", test.instance, test.call.String()), func(t *testing.T) {
|
||||||
|
got := test.instance.IsDeclaredByCall(test.call)
|
||||||
|
if got != test.want {
|
||||||
|
t.Fatal("wrong result")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustParseModuleInstanceStr(str string) ModuleInstance {
|
||||||
|
mi, err := ParseModuleInstanceStr(str)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return mi
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package states
|
package states
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
@ -296,3 +297,245 @@ func (s *State) SyncWrapper() *SyncState {
|
||||||
state: s,
|
state: s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MoveAbsResource moves the given src AbsResource's current state to the new
|
||||||
|
// dst address. This will panic if the src AbsResource does not exist in state,
|
||||||
|
// or if there is already a resource at the dst address. It is the caller's
|
||||||
|
// responsibility to verify the validity of the move (for example, that the src
|
||||||
|
// and dst are compatible types).
|
||||||
|
func (s *State) MoveAbsResource(src, dst addrs.AbsResource) {
|
||||||
|
// verify that the src address exists and the dst address does not
|
||||||
|
rs := s.Resource(src)
|
||||||
|
if rs == nil {
|
||||||
|
panic(fmt.Sprintf("no state for src address %s", src.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
ds := s.Resource(dst)
|
||||||
|
if ds != nil {
|
||||||
|
panic(fmt.Sprintf("dst resource %s already exists", dst.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
ms := s.Module(src.Module)
|
||||||
|
ms.RemoveResource(src.Resource)
|
||||||
|
|
||||||
|
// Remove the module if it is empty (and not root) after removing the
|
||||||
|
// resource.
|
||||||
|
if !ms.Addr.IsRoot() && ms.empty() {
|
||||||
|
s.RemoveModule(src.Module)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the address before adding it to the state
|
||||||
|
rs.Addr = dst
|
||||||
|
s.EnsureModule(dst.Module).Resources[dst.Resource.String()] = rs
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaybeMoveAbsResource moves the given src AbsResource's current state to the
|
||||||
|
// new dst address. This function will succeed if both the src address does not
|
||||||
|
// exist in state and the dst address does; the return value indicates whether
|
||||||
|
// or not the move occured. This function will panic if either the src does not
|
||||||
|
// exist or the dst does exist (but not both).
|
||||||
|
func (s *State) MaybeMoveAbsResource(src, dst addrs.AbsResource) bool {
|
||||||
|
// Get the source and destinatation addresses from state.
|
||||||
|
rs := s.Resource(src)
|
||||||
|
ds := s.Resource(dst)
|
||||||
|
|
||||||
|
// Normal case: the src exists in state, dst does not
|
||||||
|
if rs != nil && ds == nil {
|
||||||
|
s.MoveAbsResource(src, dst)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs == nil && ds != nil {
|
||||||
|
// The source is not in state, the destination is. This is not
|
||||||
|
// guaranteed to be idempotent since we aren't tracking exact moves, but
|
||||||
|
// it's useful information for the caller.
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
panic("invalid move")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveAbsResourceInstance moves the given src AbsResourceInstance's current state to
|
||||||
|
// the new dst address. This will panic if the src AbsResourceInstance does not
|
||||||
|
// exist in state, or if there is already a resource at the dst address. It is
|
||||||
|
// the caller's responsibility to verify the validity of the move (for example,
|
||||||
|
// that the src and dst are compatible types).
|
||||||
|
func (s *State) MoveAbsResourceInstance(src, dst addrs.AbsResourceInstance) {
|
||||||
|
srcInstanceState := s.ResourceInstance(src)
|
||||||
|
if srcInstanceState == nil {
|
||||||
|
panic(fmt.Sprintf("no state for src address %s", src.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
dstInstanceState := s.ResourceInstance(dst)
|
||||||
|
if dstInstanceState != nil {
|
||||||
|
panic(fmt.Sprintf("dst resource %s already exists", dst.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
srcResourceState := s.Resource(src.ContainingResource())
|
||||||
|
srcProviderAddr := srcResourceState.ProviderConfig
|
||||||
|
dstResourceAddr := dst.ContainingResource()
|
||||||
|
|
||||||
|
// Remove the source resource instance from the module's state, and then the
|
||||||
|
// module if empty.
|
||||||
|
ms := s.Module(src.Module)
|
||||||
|
ms.ForgetResourceInstanceAll(src.Resource)
|
||||||
|
if !ms.Addr.IsRoot() && ms.empty() {
|
||||||
|
s.RemoveModule(src.Module)
|
||||||
|
}
|
||||||
|
|
||||||
|
dstModule := s.EnsureModule(dst.Module)
|
||||||
|
|
||||||
|
// See if there is already a resource we can add this instance to.
|
||||||
|
dstResourceState := s.Resource(dstResourceAddr)
|
||||||
|
if dstResourceState == nil {
|
||||||
|
// If we're moving to an address without an index then that
|
||||||
|
// suggests the user's intent is to establish both the
|
||||||
|
// resource and the instance at the same time (since the
|
||||||
|
// address covers both). If there's an index in the
|
||||||
|
// target then allow creating the new instance here.
|
||||||
|
dstModule.SetResourceProvider(
|
||||||
|
dstResourceAddr.Resource,
|
||||||
|
srcProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource
|
||||||
|
)
|
||||||
|
dstResourceState = dstModule.Resource(dstResourceAddr.Resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
dstResourceState.Instances[dst.Resource.Key] = srcInstanceState
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaybeMoveAbsResourceInstance moves the given src AbsResourceInstance's
|
||||||
|
// current state to the new dst address. This function will succeed if both the
|
||||||
|
// src address does not exist in state and the dst address does; the return
|
||||||
|
// value indicates whether or not the move occured. This function will panic if
|
||||||
|
// either the src does not exist or the dst does exist (but not both).
|
||||||
|
func (s *State) MaybeMoveAbsResourceInstance(src, dst addrs.AbsResourceInstance) bool {
|
||||||
|
// get the src and dst resource instances from state
|
||||||
|
rs := s.ResourceInstance(src)
|
||||||
|
ds := s.ResourceInstance(dst)
|
||||||
|
|
||||||
|
// Normal case: the src exists in state, dst does not
|
||||||
|
if rs != nil && ds == nil {
|
||||||
|
s.MoveAbsResourceInstance(src, dst)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs == nil && ds != nil {
|
||||||
|
// The source is not in state, the destination is. This is not
|
||||||
|
// guaranteed to be idempotent since we aren't tracking exact moves, but
|
||||||
|
// it's useful information.
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
panic("invalid move")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveModuleInstance moves the given src ModuleInstance's current state to the
|
||||||
|
// new dst address. This will panic if the src ModuleInstance does not
|
||||||
|
// exist in state, or if there is already a resource at the dst address. It is
|
||||||
|
// the caller's responsibility to verify the validity of the move.
|
||||||
|
func (s *State) MoveModuleInstance(src, dst addrs.ModuleInstance) {
|
||||||
|
if src.IsRoot() || dst.IsRoot() {
|
||||||
|
panic("cannot move to or from root module")
|
||||||
|
}
|
||||||
|
|
||||||
|
srcMod := s.Module(src)
|
||||||
|
if srcMod == nil {
|
||||||
|
panic(fmt.Sprintf("no state for src module %s", src.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
dstMod := s.Module(dst)
|
||||||
|
if dstMod != nil {
|
||||||
|
panic(fmt.Sprintf("dst module %s already exists in state", dst.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
s.RemoveModule(src)
|
||||||
|
|
||||||
|
srcMod.Addr = dst
|
||||||
|
s.EnsureModule(dst)
|
||||||
|
s.Modules[dst.String()] = srcMod
|
||||||
|
|
||||||
|
// Update any Resource's addresses.
|
||||||
|
if srcMod.Resources != nil {
|
||||||
|
for _, r := range srcMod.Resources {
|
||||||
|
r.Addr.Module = dst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update any OutputValues's addresses.
|
||||||
|
if srcMod.OutputValues != nil {
|
||||||
|
for _, ov := range srcMod.OutputValues {
|
||||||
|
ov.Addr.Module = dst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaybeMoveModuleInstance moves the given src ModuleInstance's current state to
|
||||||
|
// the new dst address. This function will succeed if both the src address does
|
||||||
|
// not exist in state and the dst address does; the return value indicates
|
||||||
|
// whether or not the move occured. This function will panic if either the src
|
||||||
|
// does not exist or the dst does exist (but not both).
|
||||||
|
func (s *State) MaybeMoveModuleInstance(src, dst addrs.ModuleInstance) bool {
|
||||||
|
if src.IsRoot() || dst.IsRoot() {
|
||||||
|
panic("cannot move to or from root module")
|
||||||
|
}
|
||||||
|
|
||||||
|
srcMod := s.Module(src)
|
||||||
|
dstMod := s.Module(dst)
|
||||||
|
|
||||||
|
// Normal case: the src exists in state, dst does not
|
||||||
|
if srcMod != nil && dstMod == nil {
|
||||||
|
s.MoveModuleInstance(src, dst)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcMod == nil || src.IsRoot() && dstMod != nil {
|
||||||
|
// The source is not in state, the destination is. This is not
|
||||||
|
// guaranteed to be idempotent since we aren't tracking exact moves, but
|
||||||
|
// it's useful information.
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
panic("invalid move")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveModule takes a source and destination addrs.Module address, and moves all
|
||||||
|
// state Modules which are contained by the src address to the new address.
|
||||||
|
func (s *State) MoveModule(src, dst addrs.AbsModuleCall) {
|
||||||
|
if src.Module.IsRoot() || dst.Module.IsRoot() {
|
||||||
|
panic("cannot move to or from root module")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modules only exist as ModuleInstances in state, so we need to check each
|
||||||
|
// state Module and see if it is contained by the src address to get a full
|
||||||
|
// list of modules to move.
|
||||||
|
var srcMIs []*Module
|
||||||
|
for _, module := range s.Modules {
|
||||||
|
if !module.Addr.IsRoot() {
|
||||||
|
if src.Module.TargetContains(module.Addr) {
|
||||||
|
srcMIs = append(srcMIs, module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(srcMIs) == 0 {
|
||||||
|
panic(fmt.Sprintf("no matching module instances found for src module %s", src.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ms := range srcMIs {
|
||||||
|
newInst := make(addrs.ModuleInstance, len(ms.Addr))
|
||||||
|
copy(newInst, ms.Addr)
|
||||||
|
if ms.Addr.IsDeclaredByCall(src) {
|
||||||
|
// Easy case: we just need to update the last step with the new name
|
||||||
|
newInst[len(newInst)-1].Name = dst.Call.Name
|
||||||
|
} else {
|
||||||
|
// Trickier: this Module is a submodule. we need to find and update
|
||||||
|
// only that appropriate step
|
||||||
|
for s := range newInst {
|
||||||
|
if newInst[s].Name == src.Call.Name {
|
||||||
|
newInst[s].Name = dst.Call.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.MoveModuleInstance(ms.Addr, newInst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package states
|
package states
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -292,3 +293,597 @@ func TestStateDeepCopy(t *testing.T) {
|
||||||
t.Fatalf("\nexpected:\n%q\ngot:\n%q\n", state, stateCopy)
|
t.Fatalf("\nexpected:\n%q\ngot:\n%q\n", state, stateCopy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestState_MoveAbsResource(t *testing.T) {
|
||||||
|
// Set up a starter state for the embedded tests, which should start from a copy of this state.
|
||||||
|
state := NewState()
|
||||||
|
rootModule := state.RootModule()
|
||||||
|
rootModule.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.IntKey(0)),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Absolute(addrs.RootModuleInstance)
|
||||||
|
|
||||||
|
t.Run("basic move", func(t *testing.T) {
|
||||||
|
s := state.DeepCopy()
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "bar"}.Absolute(addrs.RootModuleInstance)
|
||||||
|
|
||||||
|
s.MoveAbsResource(src, dst)
|
||||||
|
|
||||||
|
if s.Empty() {
|
||||||
|
t.Fatal("unexpected empty state")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.RootModule().Resources) != 1 {
|
||||||
|
t.Fatalf("wrong number of resources in state; expected 1, found %d", len(state.RootModule().Resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.Resource(dst)
|
||||||
|
if got.Addr.Resource != dst.Resource {
|
||||||
|
t.Fatalf("dst resource not in state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("move to new module", func(t *testing.T) {
|
||||||
|
s := state.DeepCopy()
|
||||||
|
dstModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("one"))
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "bar"}.Absolute(dstModule)
|
||||||
|
|
||||||
|
s.MoveAbsResource(src, dst)
|
||||||
|
|
||||||
|
if s.Empty() {
|
||||||
|
t.Fatal("unexpected empty state")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Module(dstModule) == nil {
|
||||||
|
t.Fatalf("child module %s not in state", dstModule.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.Module(dstModule).Resources) != 1 {
|
||||||
|
t.Fatalf("wrong number of resources in state; expected 1, found %d", len(s.Module(dstModule).Resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.Resource(dst)
|
||||||
|
if got.Addr.Resource != dst.Resource {
|
||||||
|
t.Fatalf("dst resource not in state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("from a child module to root", func(t *testing.T) {
|
||||||
|
s := state.DeepCopy()
|
||||||
|
srcModule := addrs.RootModuleInstance.Child("kinder", addrs.NoKey)
|
||||||
|
cm := s.EnsureModule(srcModule)
|
||||||
|
cm.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "child",
|
||||||
|
}.Instance(addrs.IntKey(0)), // Moving the AbsResouce moves all instances
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
cm.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "child",
|
||||||
|
}.Instance(addrs.IntKey(1)), // Moving the AbsResouce moves all instances
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(addrs.RootModuleInstance)
|
||||||
|
s.MoveAbsResource(src, dst)
|
||||||
|
|
||||||
|
if s.Empty() {
|
||||||
|
t.Fatal("unexpected empty state")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The child module should have been removed after removing its only resource
|
||||||
|
if s.Module(srcModule) != nil {
|
||||||
|
t.Fatalf("child module %s was not removed from state after mv", srcModule.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.RootModule().Resources) != 2 {
|
||||||
|
t.Fatalf("wrong number of resources in state; expected 2, found %d", len(s.RootModule().Resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.Resource(dst).Instances) != 2 {
|
||||||
|
t.Fatalf("wrong number of resource instances for dst, got %d expected 2", len(s.Resource(dst).Instances))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.Resource(dst)
|
||||||
|
if got.Addr.Resource != dst.Resource {
|
||||||
|
t.Fatalf("dst resource not in state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("module to new module", func(t *testing.T) {
|
||||||
|
s := NewState()
|
||||||
|
srcModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("exists"))
|
||||||
|
dstModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("new"))
|
||||||
|
cm := s.EnsureModule(srcModule)
|
||||||
|
cm.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "child",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(dstModule)
|
||||||
|
s.MoveAbsResource(src, dst)
|
||||||
|
|
||||||
|
if s.Empty() {
|
||||||
|
t.Fatal("unexpected empty state")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The child module should have been removed after removing its only resource
|
||||||
|
if s.Module(srcModule) != nil {
|
||||||
|
t.Fatalf("child module %s was not removed from state after mv", srcModule.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
gotMod := s.Module(dstModule)
|
||||||
|
if len(gotMod.Resources) != 1 {
|
||||||
|
t.Fatalf("wrong number of resources in state; expected 1, found %d", len(gotMod.Resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.Resource(dst)
|
||||||
|
if got.Addr.Resource != dst.Resource {
|
||||||
|
t.Fatalf("dst resource not in state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("module to new module", func(t *testing.T) {
|
||||||
|
s := NewState()
|
||||||
|
srcModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("exists"))
|
||||||
|
dstModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("new"))
|
||||||
|
cm := s.EnsureModule(srcModule)
|
||||||
|
cm.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "child",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(dstModule)
|
||||||
|
s.MoveAbsResource(src, dst)
|
||||||
|
|
||||||
|
if s.Empty() {
|
||||||
|
t.Fatal("unexpected empty state")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The child module should have been removed after removing its only resource
|
||||||
|
if s.Module(srcModule) != nil {
|
||||||
|
t.Fatalf("child module %s was not removed from state after mv", srcModule.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
gotMod := s.Module(dstModule)
|
||||||
|
if len(gotMod.Resources) != 1 {
|
||||||
|
t.Fatalf("wrong number of resources in state; expected 1, found %d", len(gotMod.Resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.Resource(dst)
|
||||||
|
if got.Addr.Resource != dst.Resource {
|
||||||
|
t.Fatalf("dst resource not in state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestState_MaybeMoveAbsResource(t *testing.T) {
|
||||||
|
state := NewState()
|
||||||
|
rootModule := state.RootModule()
|
||||||
|
rootModule.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.IntKey(0)),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Absolute(addrs.RootModuleInstance)
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "bar"}.Absolute(addrs.RootModuleInstance)
|
||||||
|
|
||||||
|
// First move, success
|
||||||
|
t.Run("first move", func(t *testing.T) {
|
||||||
|
moved := state.MaybeMoveAbsResource(src, dst)
|
||||||
|
if !moved {
|
||||||
|
t.Fatal("wrong result")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Trying to move a resource that doesn't exist in state to a resource which does exist should be a noop.
|
||||||
|
t.Run("noop", func(t *testing.T) {
|
||||||
|
moved := state.MaybeMoveAbsResource(src, dst)
|
||||||
|
if moved {
|
||||||
|
t.Fatal("wrong result")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestState_MoveAbsResourceInstance(t *testing.T) {
|
||||||
|
state := NewState()
|
||||||
|
rootModule := state.RootModule()
|
||||||
|
rootModule.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
// src resource from the state above
|
||||||
|
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
||||||
|
|
||||||
|
t.Run("resource to resource instance", func(t *testing.T) {
|
||||||
|
s := state.DeepCopy()
|
||||||
|
// For a little extra fun, move a resource to a resource instance: test_thing.foo to test_thing.foo[1]
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance)
|
||||||
|
|
||||||
|
s.MoveAbsResourceInstance(src, dst)
|
||||||
|
|
||||||
|
if s.Empty() {
|
||||||
|
t.Fatal("unexpected empty state")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.RootModule().Resources) != 1 {
|
||||||
|
t.Fatalf("wrong number of resources in state; expected 1, found %d", len(state.RootModule().Resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.ResourceInstance(dst)
|
||||||
|
if got == nil {
|
||||||
|
t.Fatalf("dst resource not in state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("move to new module", func(t *testing.T) {
|
||||||
|
s := state.DeepCopy()
|
||||||
|
// test_thing.foo to module.kinder.test_thing.foo["baz"]
|
||||||
|
dstModule := addrs.RootModuleInstance.Child("kinder", addrs.NoKey)
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.IntKey(1)).Absolute(dstModule)
|
||||||
|
|
||||||
|
s.MoveAbsResourceInstance(src, dst)
|
||||||
|
|
||||||
|
if s.Empty() {
|
||||||
|
t.Fatal("unexpected empty state")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Module(dstModule) == nil {
|
||||||
|
t.Fatalf("child module %s not in state", dstModule.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.Module(dstModule).Resources) != 1 {
|
||||||
|
t.Fatalf("wrong number of resources in state; expected 1, found %d", len(s.Module(dstModule).Resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.ResourceInstance(dst)
|
||||||
|
if got == nil {
|
||||||
|
t.Fatalf("dst resource not in state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestState_MaybeMoveAbsResourceInstance(t *testing.T) {
|
||||||
|
state := NewState()
|
||||||
|
rootModule := state.RootModule()
|
||||||
|
rootModule.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// For a little extra fun, let's go from a resource to a resource instance: test_thing.foo to test_thing.bar[1]
|
||||||
|
src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
||||||
|
dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance)
|
||||||
|
|
||||||
|
// First move, success
|
||||||
|
t.Run("first move", func(t *testing.T) {
|
||||||
|
moved := state.MaybeMoveAbsResourceInstance(src, dst)
|
||||||
|
if !moved {
|
||||||
|
t.Fatal("wrong result")
|
||||||
|
}
|
||||||
|
got := state.ResourceInstance(dst)
|
||||||
|
if got == nil {
|
||||||
|
t.Fatal("destination resource instance not in state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Moving a resource instance that doesn't exist in state to a resource which does exist should be a noop.
|
||||||
|
t.Run("noop", func(t *testing.T) {
|
||||||
|
moved := state.MaybeMoveAbsResourceInstance(src, dst)
|
||||||
|
if moved {
|
||||||
|
t.Fatal("wrong result")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestState_MoveModuleInstance(t *testing.T) {
|
||||||
|
state := NewState()
|
||||||
|
srcModule := addrs.RootModuleInstance.Child("kinder", addrs.NoKey)
|
||||||
|
m := state.EnsureModule(srcModule)
|
||||||
|
m.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
dstModule := addrs.RootModuleInstance.Child("child", addrs.IntKey(3))
|
||||||
|
state.MoveModuleInstance(srcModule, dstModule)
|
||||||
|
|
||||||
|
// srcModule should have been removed, dstModule should exist and have one resource
|
||||||
|
if len(state.Modules) != 2 { // kinder[3] and root
|
||||||
|
t.Fatalf("wrong number of modules in state. Expected 2, got %d", len(state.Modules))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := state.Module(dstModule)
|
||||||
|
if got == nil {
|
||||||
|
t.Fatal("dstModule not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
gone := state.Module(srcModule)
|
||||||
|
if gone != nil {
|
||||||
|
t.Fatal("srcModule not removed from state")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := got.Resource(mustAbsResourceAddr("test_thing.foo").Resource)
|
||||||
|
if r.Addr.Module.String() != dstModule.String() {
|
||||||
|
fmt.Println(r.Addr.Module.String())
|
||||||
|
t.Fatal("resource address was not updated")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestState_MaybeMoveModuleInstance(t *testing.T) {
|
||||||
|
state := NewState()
|
||||||
|
src := addrs.RootModuleInstance.Child("child", addrs.StringKey("a"))
|
||||||
|
cm := state.EnsureModule(src)
|
||||||
|
cm.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
dst := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("b"))
|
||||||
|
|
||||||
|
// First move, success
|
||||||
|
t.Run("first move", func(t *testing.T) {
|
||||||
|
moved := state.MaybeMoveModuleInstance(src, dst)
|
||||||
|
if !moved {
|
||||||
|
t.Fatal("wrong result")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Second move, should be a noop
|
||||||
|
t.Run("noop", func(t *testing.T) {
|
||||||
|
moved := state.MaybeMoveModuleInstance(src, dst)
|
||||||
|
if moved {
|
||||||
|
t.Fatal("wrong result")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestState_MoveModule(t *testing.T) {
|
||||||
|
// For this test, add two module instances (kinder and kinder["a"]).
|
||||||
|
// MoveModule(kinder) should move both instances.
|
||||||
|
state := NewState() // starter state, should be copied by the subtests.
|
||||||
|
srcModule := addrs.RootModule.Child("kinder")
|
||||||
|
m := state.EnsureModule(srcModule.UnkeyedInstanceShim())
|
||||||
|
m.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
moduleInstance := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("a"))
|
||||||
|
mi := state.EnsureModule(moduleInstance)
|
||||||
|
mi.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
_, mc := srcModule.Call()
|
||||||
|
src := mc.Absolute(addrs.RootModuleInstance.Child("kinder", addrs.NoKey))
|
||||||
|
|
||||||
|
t.Run("basic", func(t *testing.T) {
|
||||||
|
s := state.DeepCopy()
|
||||||
|
_, dstMC := addrs.RootModule.Child("child").Call()
|
||||||
|
dst := dstMC.Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
||||||
|
s.MoveModule(src, dst)
|
||||||
|
|
||||||
|
// srcModule should have been removed, dstModule should exist and have one resource
|
||||||
|
if len(s.Modules) != 3 { // child, child["a"] and root
|
||||||
|
t.Fatalf("wrong number of modules in state. Expected 3, got %d", len(s.Modules))
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.Module(dst.Module)
|
||||||
|
if got == nil {
|
||||||
|
t.Fatal("dstModule not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
got = s.Module(addrs.RootModuleInstance.Child("child", addrs.StringKey("a")))
|
||||||
|
if got == nil {
|
||||||
|
t.Fatal("dstModule instance \"a\" not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
gone := s.Module(srcModule.UnkeyedInstanceShim())
|
||||||
|
if gone != nil {
|
||||||
|
t.Fatal("srcModule not removed from state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested modules", func(t *testing.T) {
|
||||||
|
s := state.DeepCopy()
|
||||||
|
|
||||||
|
// add a child module to module.kinder
|
||||||
|
mi := mustParseModuleInstanceStr(`module.kinder.module.grand[1]`)
|
||||||
|
m := s.EnsureModule(mi)
|
||||||
|
m.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "foo",
|
||||||
|
}.Instance(addrs.NoKey),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
},
|
||||||
|
addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
_, dstMC := addrs.RootModule.Child("child").Call()
|
||||||
|
dst := dstMC.Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
||||||
|
s.MoveModule(src, dst)
|
||||||
|
|
||||||
|
moved := s.Module(addrs.RootModuleInstance.Child("child", addrs.StringKey("a")))
|
||||||
|
if moved == nil {
|
||||||
|
t.Fatal("dstModule not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The nested module's relative address should also have been updated
|
||||||
|
nested := s.Module(mustParseModuleInstanceStr(`module.child.module.grand[1]`))
|
||||||
|
if nested == nil {
|
||||||
|
t.Fatal("nested child module of src wasn't moved")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustParseModuleInstanceStr(str string) addrs.ModuleInstance {
|
||||||
|
addr, diags := addrs.ParseModuleInstanceStr(str)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
panic(diags.Err())
|
||||||
|
}
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustAbsResourceAddr(s string) addrs.AbsResource {
|
||||||
|
addr, diags := addrs.ParseAbsResourceStr(s)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
panic(diags.Err())
|
||||||
|
}
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
|
@ -554,3 +554,45 @@ func (s *SyncState) maybePruneModule(addr addrs.ModuleInstance) {
|
||||||
s.state.RemoveModule(addr)
|
s.state.RemoveModule(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SyncState) MoveAbsResource(src, dst addrs.AbsResource) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.state.MoveAbsResource(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SyncState) MaybeMoveAbsResource(src, dst addrs.AbsResource) bool {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
return s.state.MaybeMoveAbsResource(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SyncState) MoveResourceInstance(src, dst addrs.AbsResourceInstance) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.state.MoveAbsResourceInstance(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SyncState) MaybeMoveResourceInstance(src, dst addrs.AbsResourceInstance) bool {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
return s.state.MaybeMoveAbsResourceInstance(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SyncState) MoveModuleInstance(src, dst addrs.ModuleInstance) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.state.MoveModuleInstance(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SyncState) MaybeMoveModuleInstance(src, dst addrs.ModuleInstance) bool {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
return s.state.MaybeMoveModuleInstance(src, dst)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue