Skip to content

Commit b691bce

Browse files
authored
Merge pull request #108 from apgrucza/unique-key
feat(resource): interface method for unique-key
2 parents 01e6611 + 19923b4 commit b691bce

File tree

3 files changed

+64
-9
lines changed

3 files changed

+64
-9
lines changed

pkg/queue/item.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,27 @@ func (i *Item) Equals(o resource.Resource) bool {
113113
return false
114114
}
115115

116-
iGetter, iOK := i.Resource.(resource.PropertyGetter)
117-
oGetter, oOK := o.(resource.PropertyGetter)
118-
if iOK != oOK {
119-
return false
120-
}
116+
// Compare unique keys if present
117+
iKeyGetter, iOK := i.Resource.(resource.UniqueKeyGetter)
118+
oKeyGetter, oOK := o.(resource.UniqueKeyGetter)
121119
if iOK && oOK {
122-
return iGetter.Properties().Equals(oGetter.Properties())
120+
return iKeyGetter.UniqueKey() == oKeyGetter.UniqueKey()
123121
}
124122

123+
// Fall back to legacy string comparison (may not handle case where resource is recreated during nuke)
125124
iStringer, iOK := i.Resource.(resource.LegacyStringer)
126125
oStringer, oOK := o.(resource.LegacyStringer)
127-
if iOK != oOK {
128-
return false
129-
}
130126
if iOK && oOK {
131127
return iStringer.String() == oStringer.String()
132128
}
133129

130+
// Fall back to property comparison (does not handle case where properties change during nuke)
131+
iPropertyGetter, iOK := i.Resource.(resource.PropertyGetter)
132+
oPropertyGetter, oOK := o.(resource.PropertyGetter)
133+
if iOK && oOK {
134+
return iPropertyGetter.Properties().Equals(oPropertyGetter.Properties())
135+
}
136+
134137
return false
135138
}
136139

pkg/queue/item_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,45 @@ func Test_ItemEqualStringer(t *testing.T) {
281281

282282
// ------------------------------------------------------------------------
283283

284+
type TestItemResourceUniqueKey struct {
285+
ID string
286+
State string
287+
}
288+
289+
func (r *TestItemResourceUniqueKey) Remove(_ context.Context) error {
290+
return nil
291+
}
292+
func (r *TestItemResourceUniqueKey) Properties() types.Properties {
293+
return types.NewProperties().Set("ID", r.ID).Set("State", r.State)
294+
}
295+
func (r *TestItemResourceUniqueKey) UniqueKey() string {
296+
return r.ID
297+
}
298+
299+
func Test_ItemEqualUniqueKey(t *testing.T) {
300+
r1 := &TestItemResourceUniqueKey{
301+
ID: "i-01b489457a60298dd",
302+
State: "running",
303+
}
304+
305+
r2 := &TestItemResourceUniqueKey{
306+
ID: "i-01b489457a60298dd", // Same ID
307+
State: "stopping", // Different state (should be ignored)
308+
}
309+
310+
i := &Item{Resource: r1}
311+
assert.True(t, i.Equals(r2), "Resources with same UniqueKey should be equal")
312+
313+
r3 := &TestItemResourceUniqueKey{
314+
ID: "i-1234567890abcdef0", // Different ID
315+
State: "running", // Same state (should be ignored)
316+
}
317+
318+
assert.False(t, i.Equals(r3), "Resources with different UniqueKey should not be equal")
319+
}
320+
321+
// ------------------------------------------------------------------------
322+
284323
type TestItemResourceNothing struct{}
285324

286325
func (r *TestItemResourceNothing) Remove(_ context.Context) error {

pkg/resource/resource.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
// Package resource provides a way to interact with resources. This provides multiple interfaces to test against
22
// as resources can optionally implement these interfaces.
3+
//
4+
// All new resources should implement Properties() and UniqueKey(), but not String(). Without UniqueKey(), libnuke
5+
// attempts to use Properties() to match resources, which does not work if any of the properties change in value during
6+
// the run. UniqueKey() is also useful in older resources that still implement String(), to prevent libnuke from
7+
// mistakenly identifying resources that were recreated with the same String() value after being nuked.
38
package resource
49

510
import (
@@ -33,6 +38,14 @@ type SettingsGetter interface {
3338
Settings(setting *settings.Setting)
3439
}
3540

41+
// UniqueKeyGetter is an interface that allows a resource to provide a key that uniquely identifies an instance of a
42+
// resource. UniqueKey() can return any field that uniquely identifies the resource and whose value is random or non-
43+
// deterministic. For example, an EC2 instance ID (i-1234567890abcdef0), or resource name with creation time appended.
44+
type UniqueKeyGetter interface {
45+
Resource
46+
UniqueKey() string
47+
}
48+
3649
// HandleWaitHook is an interface that allows a resource to handle waiting for a resource to be deleted.
3750
// This is useful for resources that may take a while to delete, typically where the delete operation happens
3851
// asynchronously from the initial delete command. This allows libnuke to not block during the delete operation.

0 commit comments

Comments
 (0)