remove stale dependencies on `state mv`
Clear any Dependencies if there is an entry matching a `state mv` from address. While stale dependencies won't directly effect any current operations, clearing the list will allow them to be recreated in their entirety during refresh. This will help future releases that may rely solely on the pre-calculated dependencies for destruction ordering.
This commit is contained in:
parent
dc178789b2
commit
98c02ac114
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -36,8 +36,9 @@ func TestStateMv(t *testing.T) {
|
||||||
Name: "baz",
|
Name: "baz",
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||||
&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),
|
||||||
)
|
)
|
||||||
|
@ -96,8 +97,9 @@ func TestStateMv_resourceToInstance(t *testing.T) {
|
||||||
Name: "baz",
|
Name: "baz",
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||||
&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),
|
||||||
)
|
)
|
||||||
|
@ -445,8 +447,9 @@ func TestStateMv_backupExplicit(t *testing.T) {
|
||||||
Name: "baz",
|
Name: "baz",
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||||
&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{
|
Type: "test_instance",
|
||||||
"test_instance.foo": &terraform.ResourceState{
|
Name: "foo",
|
||||||
Type: "test_instance",
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||||
Primary: &terraform.InstanceState{
|
&states.ResourceInstanceObjectSrc{
|
||||||
ID: "bar",
|
AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
|
||||||
Attributes: map[string]string{
|
Status: states.ObjectReady,
|
||||||
"foo": "value",
|
|
||||||
"bar": "value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"test_instance.baz": &terraform.ResourceState{
|
|
||||||
Type: "test_instance",
|
|
||||||
Primary: &terraform.InstanceState{
|
|
||||||
ID: "foo",
|
|
||||||
Attributes: map[string]string{
|
|
||||||
"foo": "value",
|
|
||||||
"bar": "value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
|
||||||
}
|
)
|
||||||
|
s.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_instance",
|
||||||
|
Name: "baz",
|
||||||
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||||
|
&states.ResourceInstanceObjectSrc{
|
||||||
|
AttrsJSON: []byte(`{"id":"foo","foo":"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
|
||||||
|
|
Loading…
Reference in New Issue