Merge pull request #23791 from hashicorp/jbardin/state-mv

remove stale dependencies on `state mv`
This commit is contained in:
James Bardin 2020-01-06 16:02:22 -05:00 committed by GitHub
commit ae407060f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 36 deletions

View File

@ -879,3 +879,11 @@ func normalizeJSON(t *testing.T, src []byte) string {
} }
return buf.String() return buf.String()
} }
func mustResourceAddr(s string) addrs.AbsResource {
addr, diags := addrs.ParseAbsResourceStr(s)
if diags.HasErrors() {
panic(diags.Err())
}
return addr
}

View File

@ -314,6 +314,28 @@ func (c *StateMvCommand) Run(args []string) int {
fmt.Sprintf("Cannot move %s: Terraform doesn't know how to move this object.", rawAddrFrom), fmt.Sprintf("Cannot move %s: Terraform doesn't know how to move this object.", rawAddrFrom),
)) ))
} }
// Look for any dependencies that may be effected and
// remove them to ensure they are recreated in full.
for _, mod := range stateTo.Modules {
for _, res := range mod.Resources {
for _, ins := range res.Instances {
if ins.Current == nil {
continue
}
for _, dep := range ins.Current.Dependencies {
// check both directions here, since we may be moving
// an instance which is in a resource, or a module
// which can contain a resource.
if dep.TargetContains(rawAddrFrom) || rawAddrFrom.TargetContains(dep) {
ins.Current.Dependencies = nil
break
}
}
}
}
}
} }
if dryRun { if dryRun {

View File

@ -38,6 +38,7 @@ func TestStateMv(t *testing.T) {
&states.ResourceInstanceObjectSrc{ &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
Status: states.ObjectReady, Status: states.ObjectReady,
Dependencies: []addrs.AbsResource{mustResourceAddr("test_instance.foo")},
}, },
addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
) )
@ -98,6 +99,7 @@ func TestStateMv_resourceToInstance(t *testing.T) {
&states.ResourceInstanceObjectSrc{ &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
Status: states.ObjectReady, Status: states.ObjectReady,
Dependencies: []addrs.AbsResource{mustResourceAddr("test_instance.foo")},
}, },
addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
) )
@ -447,6 +449,7 @@ func TestStateMv_backupExplicit(t *testing.T) {
&states.ResourceInstanceObjectSrc{ &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
Status: states.ObjectReady, Status: states.ObjectReady,
Dependencies: []addrs.AbsResource{mustResourceAddr("test_instance.foo")},
}, },
addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
) )
@ -897,42 +900,40 @@ func TestStateMv_toNewModule(t *testing.T) {
} }
testStateOutput(t, stateOutPath2, testStateMvModuleNewModule_stateOut) testStateOutput(t, stateOutPath2, testStateMvModuleNewModule_stateOut)
} }
func TestStateMv_withinBackend(t *testing.T) { func TestStateMv_withinBackend(t *testing.T) {
td := tempDir(t) td := tempDir(t)
copy.CopyDir(testFixturePath("backend-unchanged"), td) copy.CopyDir(testFixturePath("backend-unchanged"), td)
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
state := &terraform.State{ state := states.BuildState(func(s *states.SyncState) {
Modules: []*terraform.ModuleState{ s.SetResourceInstanceCurrent(
&terraform.ModuleState{ addrs.Resource{
Path: []string{"root"}, Mode: addrs.ManagedResourceMode,
Resources: map[string]*terraform.ResourceState{
"test_instance.foo": &terraform.ResourceState{
Type: "test_instance", Type: "test_instance",
Primary: &terraform.InstanceState{ Name: "foo",
ID: "bar", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
Attributes: map[string]string{ &states.ResourceInstanceObjectSrc{
"foo": "value", AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
"bar": "value", Status: states.ObjectReady,
}, },
}, addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
}, )
s.SetResourceInstanceCurrent(
"test_instance.baz": &terraform.ResourceState{ addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_instance", Type: "test_instance",
Primary: &terraform.InstanceState{ Name: "baz",
ID: "foo", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
Attributes: map[string]string{ &states.ResourceInstanceObjectSrc{
"foo": "value", AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
"bar": "value", Status: states.ObjectReady,
Dependencies: []addrs.AbsResource{mustResourceAddr("test_instance.foo")},
}, },
}, addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
}, )
}, })
},
},
}
// the local backend state file is "foo" // the local backend state file is "foo"
statePath := "local-state.tfstate" statePath := "local-state.tfstate"
@ -944,7 +945,7 @@ func TestStateMv_withinBackend(t *testing.T) {
} }
defer f.Close() defer f.Close()
if err := terraform.WriteState(state, f); err != nil { if err := writeStateForTesting(state, f); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1057,6 +1058,9 @@ test_instance.baz:
provider = provider.test provider = provider.test
bar = value bar = value
foo = value foo = value
Dependencies:
test_instance.foo
test_instance.foo: test_instance.foo:
ID = bar ID = bar
provider = provider.test provider = provider.test