Skip to content
This repository has been archived by the owner on Jul 9, 2024. It is now read-only.

Commit

Permalink
framework/resource: call destroy if SetState manually called
Browse files Browse the repository at this point in the history
Fixes #37

This calls Destroy properly on a resource if SetState is manually
called. There is a big limitation here in that we don't know the exact
proper destroy order to call, but argmapper gets us most likely correct
due to state dependencies. And, as the comment in the code states, the
ordering doesn't matter for any practical use case we have today since
all manual SetStates today are single resources. Hopefully we switch
everything to resource manager soon so this doesn't matter.
  • Loading branch information
mitchellh committed Aug 10, 2021
1 parent 3366194 commit 337d14c
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 2 deletions.
25 changes: 23 additions & 2 deletions framework/resource/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,29 @@ func (m *Manager) DestroyAll(args ...interface{}) error {

cs := m.createState
if cs == nil || len(cs.Order) == 0 {
// We have no creation that was ever done so we have nothing to destroy.
return nil
// If we have no creation order, then we fall back to checking
// manually for state set on each resource. Note this has a huge
// limitation in that our Order is probably wrong. For the case we're
// implementing this for, the order doesn't matter so this works,
// and hopefully by the time ordering matters everything is swapped
// over to the resource manager.
for n, r := range m.resources {
if r.State() == nil {
continue
}

// We have state, so we want to destroy this.
if cs == nil {
cs = &createState{}
}

cs.Order = append(cs.Order, n)
}

// Still empty? Then we do nothing
if cs == nil || len(cs.Order) == 0 {
return nil
}
}

var finalInputs []argmapper.Value
Expand Down
52 changes: 52 additions & 0 deletions framework/resource/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,58 @@ func TestManagerDestroyAll_noDestroyFunc(t *testing.T) {
require.Equal([]string{"B"}, destroyOrder)
}

func TestManagerDestroyAll_loadState(t *testing.T) {
require := require.New(t)

// init is a function so that we can reinitialize an empty manager
// for this test to test loading state
var destroyOrder []string
var destroyState int32
init := func() *Manager {
return NewManager(
WithResource(NewResource(
WithName("A"),
WithState(&testproto.Data{}),
WithCreate(func(s *testproto.Data, v int32) error {
s.Number = v
return nil
}),
WithDestroy(func(s *testproto.Data) error {
destroyOrder = append(destroyOrder, "A")
destroyState = s.Number
return nil
}),
)),

WithResource(NewResource(
WithName("B"),
WithState(&testState{}),
WithCreate(func(s *testproto.Data) error {
return nil
}),
WithDestroy(func() error {
destroyOrder = append(destroyOrder, "B")
return nil
}),
)),
)
}

// Create manager
m := init()

// Manually set some destroy state
require.NoError(m.Resource("A").SetState(&testproto.Data{Number: 42}))
require.NoError(m.Resource("B").SetState(&testState{}))

// Destroy
require.NoError(m.DestroyAll())

// Ensure we destroyed
require.Equal([]string{"B", "A"}, destroyOrder)
require.Equal(destroyState, int32(42))
}

// TestStatus_Manager tests the Manager's ability to call resource status
// methods and present them for creating a report
func TestStatus_Manager(t *testing.T) {
Expand Down

0 comments on commit 337d14c

Please sign in to comment.