Allow moving instances to new resources
If a state mv target happens to be a resource that doesn't exist, allow the creation of the new resource inferring the EachMode from the target address.
This commit is contained in:
parent
ba9cb786c3
commit
a5cb36b34c
|
@ -278,7 +278,9 @@ func (c *StateMvCommand) Run(args []string) int {
|
|||
c.Ui.Output(fmt.Sprintf("%s %q to %q", prefix, addrFrom.String(), args[1]))
|
||||
if !dryRun {
|
||||
fromResourceAddr := addrFrom.ContainingResource()
|
||||
fromProviderAddr := ssFrom.Resource(fromResourceAddr).ProviderConfig
|
||||
fromResource := ssFrom.Resource(fromResourceAddr)
|
||||
fromProviderAddr := fromResource.ProviderConfig
|
||||
fromEachMode := fromResource.EachMode
|
||||
ssFrom.ForgetResourceInstanceAll(addrFrom)
|
||||
ssFrom.RemoveResourceIfEmpty(fromResourceAddr)
|
||||
|
||||
|
@ -287,22 +289,17 @@ func (c *StateMvCommand) Run(args []string) int {
|
|||
// 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), but if there's an index in the
|
||||
// target then the resource must already exist.
|
||||
// address covers both). If there's an index in the
|
||||
// target then allow creating the new instance here,
|
||||
// inferring the mode from how the new address was parsed.
|
||||
if addrTo.Resource.Key != addrs.NoKey {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
msgInvalidTarget,
|
||||
fmt.Sprintf("Cannot move to %s: %s does not exist in the current state.", addrTo, addrTo.ContainingResource()),
|
||||
))
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
fromEachMode = eachModeForInstanceKey(addrTo.Resource.Key)
|
||||
}
|
||||
|
||||
resourceAddr := addrTo.ContainingResource()
|
||||
stateTo.SyncWrapper().SetResourceMeta(
|
||||
resourceAddr,
|
||||
states.NoEach,
|
||||
fromEachMode,
|
||||
fromProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource
|
||||
)
|
||||
rs = stateTo.Resource(resourceAddr)
|
||||
|
@ -358,6 +355,20 @@ 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.
|
||||
//
|
||||
|
|
|
@ -237,6 +237,74 @@ test_instance.foo.0:
|
|||
`)
|
||||
}
|
||||
|
||||
func TestStateMv_instanceToNewResource(t *testing.T) {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance),
|
||||
)
|
||||
})
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
"test_instance.foo[0]",
|
||||
"test_instance.bar[\"new\"]",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
// Test it is correct
|
||||
testStateOutput(t, statePath, `
|
||||
test_instance.bar["new"]:
|
||||
ID = bar
|
||||
provider = provider.test
|
||||
bar = value
|
||||
foo = value
|
||||
`)
|
||||
|
||||
// now move the instance to a new resource in a new module
|
||||
args = []string{
|
||||
"-state", statePath,
|
||||
"test_instance.bar[\"new\"]",
|
||||
"module.test.test_instance.baz[\"new\"]",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
// Test it is correct
|
||||
testStateOutput(t, statePath, `
|
||||
<no state>
|
||||
module.test:
|
||||
test_instance.baz["new"]:
|
||||
ID = bar
|
||||
provider = provider.test
|
||||
bar = value
|
||||
foo = value
|
||||
`)
|
||||
}
|
||||
|
||||
func TestStateMv_differentResourceTypes(t *testing.T) {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
|
|
Loading…
Reference in New Issue