Skip to content

Commit

Permalink
remove stale dependencies on state mv
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jbardin committed Jan 6, 2020
1 parent dc17878 commit 5d1e3f8
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 36 deletions.
8 changes: 8 additions & 0 deletions command/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -879,3 +879,11 @@ func normalizeJSON(t *testing.T, src []byte) string {
}
return buf.String()
}

func mustResourceAddr(s string) addrs.AbsResource {
addr, diags := addrs.ParseAbsResourceStr(s)
if diags.HasErrors() {
panic(diags.Err())
}
return addr
}
22 changes: 22 additions & 0 deletions command/state_mv.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
))
}

// 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 {
Expand Down
76 changes: 40 additions & 36 deletions command/state_mv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ func TestStateMv(t *testing.T) {
Name: "baz",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
&states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
Status: states.ObjectReady,
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),
)
Expand Down Expand Up @@ -96,8 +97,9 @@ func TestStateMv_resourceToInstance(t *testing.T) {
Name: "baz",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
&states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
Status: states.ObjectReady,
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),
)
Expand Down Expand Up @@ -445,8 +447,9 @@ func TestStateMv_backupExplicit(t *testing.T) {
Name: "baz",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
&states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
Status: states.ObjectReady,
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),
)
Expand Down Expand Up @@ -897,42 +900,40 @@ func TestStateMv_toNewModule(t *testing.T) {
}
testStateOutput(t, stateOutPath2, testStateMvModuleNewModule_stateOut)
}

func TestStateMv_withinBackend(t *testing.T) {
td := tempDir(t)
copy.CopyDir(testFixturePath("backend-unchanged"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()

state := &terraform.State{
Modules: []*terraform.ModuleState{
&terraform.ModuleState{
Path: []string{"root"},
Resources: map[string]*terraform.ResourceState{
"test_instance.foo": &terraform.ResourceState{
Type: "test_instance",
Primary: &terraform.InstanceState{
ID: "bar",
Attributes: map[string]string{
"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",
},
},
},
},
state := states.BuildState(func(s *states.SyncState) {
s.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_instance",
Name: "foo",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
&states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
Status: states.ObjectReady,
},
},
}
addrs.ProviderConfig{Type: "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: "test"}.Absolute(addrs.RootModuleInstance),
)
})

// the local backend state file is "foo"
statePath := "local-state.tfstate"
Expand All @@ -944,7 +945,7 @@ func TestStateMv_withinBackend(t *testing.T) {
}
defer f.Close()

if err := terraform.WriteState(state, f); err != nil {
if err := writeStateForTesting(state, f); err != nil {
t.Fatal(err)
}

Expand Down Expand Up @@ -1057,6 +1058,9 @@ test_instance.baz:
provider = provider.test
bar = value
foo = value
Dependencies:
test_instance.foo
test_instance.foo:
ID = bar
provider = provider.test
Expand Down

0 comments on commit 5d1e3f8

Please # to comment.