fix state mv to work without EachMode

The only situation where `state mv` needs to understand the each mode is
when with resource addresses that may reference a single instance, or a
group of for_each or count instances. In this case we can differentiate
the two by checking the existence of the NoKey instance key.
This commit is contained in:
James Bardin 2020-04-24 21:52:05 -04:00
parent 15a95031e5
commit 2bfaddcf57
2 changed files with 20 additions and 36 deletions

View File

@ -279,10 +279,6 @@ func (c *StateMvCommand) Run(args []string) int {
ssFrom.ForgetResourceInstanceAll(addrFrom)
ssFrom.RemoveResourceIfEmpty(fromResourceAddr)
// since this is moving an instance, we can infer the target
// mode from the address.
toEachMode := eachModeForInstanceKey(addrTo.Resource.Key)
rs := stateTo.Resource(addrTo.ContainingResource())
if rs == nil {
// If we're moving to an address without an index then that
@ -291,15 +287,13 @@ func (c *StateMvCommand) Run(args []string) int {
// address covers both). If there's an index in the
// target then allow creating the new instance here.
resourceAddr := addrTo.ContainingResource()
stateTo.SyncWrapper().SetResourceMeta(
stateTo.SyncWrapper().SetResourceProvider(
resourceAddr,
toEachMode,
fromProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource
)
rs = stateTo.Resource(resourceAddr)
}
rs.EachMode = toEachMode
rs.Instances[addrTo.Resource.Key] = is
}
default:
@ -372,20 +366,6 @@ func (c *StateMvCommand) Run(args []string) int {
return 0
}
func eachModeForInstanceKey(key addrs.InstanceKey) states.EachMode {
switch key.(type) {
case addrs.IntKey:
return states.EachList
case addrs.StringKey:
return states.EachMap
default:
if key == addrs.NoKey {
return states.NoEach
}
panic(fmt.Sprintf("don't know an each mode for instance key %#v", key))
}
}
// sourceObjectAddrs takes a single source object address and expands it to
// potentially multiple objects that need to be handled within it.
//
@ -415,11 +395,13 @@ func (c *StateMvCommand) sourceObjectAddrs(state *states.State, matched addrs.Ta
// terraform state mv aws_instance.foo aws_instance.bar[1]
// That wouldn't be allowed if aws_instance.foo had multiple instances
// since we can't move multiple instances into one.
if rs := state.Resource(addr); rs != nil && rs.EachMode == states.NoEach {
if rs := state.Resource(addr); rs != nil {
if _, ok := rs.Instances[addrs.NoKey]; ok {
ret = append(ret, addr.Instance(addrs.NoKey))
} else {
ret = append(ret, addr)
}
}
default:
ret = append(ret, matched)
}

View File

@ -97,9 +97,10 @@ func TestStateMv(t *testing.T) {
if diags.HasErrors() {
t.Fatal(diags.Err())
}
i := s.Resource(addr)
if i.EachMode != states.EachList {
t.Fatalf("expected each mode List, got %s", i.EachMode)
for key := range s.Resource(addr).Instances {
if _, ok := key.(addrs.IntKey); !ok {
t.Fatalf("expected each mode List, got key %q", key)
}
}
// change from list to map
@ -118,9 +119,10 @@ func TestStateMv(t *testing.T) {
if diags.HasErrors() {
t.Fatal(diags.Err())
}
i = s.Resource(addr)
if i.EachMode != states.EachMap {
t.Fatalf("expected each mode Map, got %s", i.EachMode)
for key := range s.Resource(addr).Instances {
if _, ok := key.(addrs.StringKey); !ok {
t.Fatalf("expected each mode map, found key %q", key)
}
}
// change from from map back to single
@ -139,9 +141,10 @@ func TestStateMv(t *testing.T) {
if diags.HasErrors() {
t.Fatal(diags.Err())
}
i = s.Resource(addr)
if i.EachMode != states.NoEach {
t.Fatalf("expected each mode NoEach, got %s", i.EachMode)
for key := range s.Resource(addr).Instances {
if key != addrs.NoKey {
t.Fatalf("expected no each mode, found key %q", key)
}
}
}
@ -179,13 +182,12 @@ func TestStateMv_resourceToInstance(t *testing.T) {
Module: addrs.RootModule,
},
)
s.SetResourceMeta(
s.SetResourceProvider(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_instance",
Name: "bar",
}.Absolute(addrs.RootModuleInstance),
states.EachList,
addrs.AbsProviderConfig{
Provider: addrs.NewLegacyProvider("test"),
Module: addrs.RootModule,