Skip to content

Commit aaac20f

Browse files
authored
resource: misc finalizer apis (hashicorp#19474)
1 parent a72f868 commit aaac20f

File tree

8 files changed

+126
-0
lines changed

8 files changed

+126
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ require (
2424
github.com/aws/aws-sdk-go v1.44.289
2525
github.com/coredns/coredns v1.10.1
2626
github.com/coreos/go-oidc v2.1.0+incompatible
27+
github.com/deckarep/golang-set/v2 v2.3.1
2728
github.com/docker/go-connections v0.4.0
2829
github.com/envoyproxy/go-control-plane v0.11.1
2930
github.com/envoyproxy/go-control-plane/xdsmatcher v0.0.0-20230524161521-aaaacbfbe53e

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
210210
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
211211
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
212212
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
213+
github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A=
214+
github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
213215
github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661 h1:lrWnAyy/F72MbxIxFUzKmcMCdt9Oi8RzpAxzTNQHD7o=
214216
github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
215217
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=

internal/resource/resource.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,23 @@ import (
77
"fmt"
88
"strings"
99

10+
mapset "github.com/deckarep/golang-set/v2"
11+
1012
"github.com/hashicorp/consul/agent/dns"
13+
"github.com/hashicorp/consul/proto-public/pbresource"
1114
)
1215

16+
// MaxNameLength is the maximum length of a resource name.
1317
const MaxNameLength = 63
1418

19+
// DeletionTimestampKey is the key in a resource's metadata that stores the timestamp
20+
// when a resource was marked for deletion. This only applies to resources with finalizers.
21+
const DeletionTimestampKey = "deletionTimestamp"
22+
23+
// FinalizerKey is the key in resource's metadata that stores the whitespace separated
24+
// list of finalizers.
25+
const FinalizerKey = "finalizers"
26+
1527
// ValidateName returns an error a name is not a valid resource name.
1628
// The error will contain reference to what constitutes a valid resource name.
1729
func ValidateName(name string) error {
@@ -20,3 +32,55 @@ func ValidateName(name string) error {
2032
}
2133
return nil
2234
}
35+
36+
// IsMarkedForDeletion returns true if a resource has been marked for deletion,
37+
// false otherwise.
38+
func IsMarkedForDeletion(res *pbresource.Resource) bool {
39+
if res.Metadata == nil {
40+
return false
41+
}
42+
_, ok := res.Metadata[DeletionTimestampKey]
43+
return ok
44+
}
45+
46+
// HasFinalizers returns true if a resource has one or more finalizers, false otherwise.
47+
func HasFinalizers(res *pbresource.Resource) bool {
48+
return GetFinalizers(res).Cardinality() >= 1
49+
}
50+
51+
// HasFinalizer returns true if a resource has a given finalizers, false otherwise.
52+
func HasFinalizer(res *pbresource.Resource, finalizer string) bool {
53+
return GetFinalizers(res).Contains(finalizer)
54+
}
55+
56+
// AddFinalizer adds a finalizer to the given resource.
57+
func AddFinalizer(res *pbresource.Resource, finalizer string) {
58+
finalizerSet := GetFinalizers(res)
59+
finalizerSet.Add(finalizer)
60+
if res.Metadata == nil {
61+
res.Metadata = map[string]string{}
62+
}
63+
res.Metadata[FinalizerKey] = strings.Join(finalizerSet.ToSlice(), " ")
64+
}
65+
66+
// RemoveFinalizer removes a finalizer from the given resource.
67+
func RemoveFinalizer(res *pbresource.Resource, finalizer string) {
68+
finalizerSet := GetFinalizers(res)
69+
finalizerSet.Remove(finalizer)
70+
if res.Metadata == nil {
71+
res.Metadata = map[string]string{}
72+
}
73+
res.Metadata[FinalizerKey] = strings.Join(finalizerSet.ToSlice(), " ")
74+
}
75+
76+
// GetFinalizers returns the set of finalizers for the given resource.
77+
func GetFinalizers(res *pbresource.Resource) mapset.Set[string] {
78+
if res.Metadata == nil {
79+
return mapset.NewSet[string]()
80+
}
81+
finalizers, ok := res.Metadata[FinalizerKey]
82+
if !ok {
83+
return mapset.NewSet[string]()
84+
}
85+
return mapset.NewSet[string](strings.Fields(finalizers)...)
86+
}

internal/resource/resource_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package resource_test
5+
6+
import (
7+
"testing"
8+
9+
mapset "github.com/deckarep/golang-set/v2"
10+
"github.com/stretchr/testify/require"
11+
12+
"github.com/hashicorp/consul/internal/resource"
13+
rtest "github.com/hashicorp/consul/internal/resource/resourcetest"
14+
pbtenancy "github.com/hashicorp/consul/proto-public/pbtenancy/v2beta1"
15+
)
16+
17+
func TestFinalizer(t *testing.T) {
18+
t.Run("no finalizers", func(t *testing.T) {
19+
res := rtest.Resource(pbtenancy.NamespaceType, "ns1").Build()
20+
require.False(t, resource.HasFinalizers(res))
21+
require.False(t, resource.HasFinalizer(res, "finalizer1"))
22+
require.Equal(t, mapset.NewSet[string](), resource.GetFinalizers(res))
23+
resource.RemoveFinalizer(res, "finalizer")
24+
})
25+
26+
t.Run("add finalizer", func(t *testing.T) {
27+
res := rtest.Resource(pbtenancy.NamespaceType, "ns1").Build()
28+
resource.AddFinalizer(res, "finalizer1")
29+
require.True(t, resource.HasFinalizers(res))
30+
require.True(t, resource.HasFinalizer(res, "finalizer1"))
31+
require.False(t, resource.HasFinalizer(res, "finalizer2"))
32+
require.Equal(t, mapset.NewSet[string]("finalizer1"), resource.GetFinalizers(res))
33+
34+
// add duplicate -> noop
35+
resource.AddFinalizer(res, "finalizer1")
36+
require.Equal(t, mapset.NewSet[string]("finalizer1"), resource.GetFinalizers(res))
37+
})
38+
39+
t.Run("remove finalizer", func(t *testing.T) {
40+
res := rtest.Resource(pbtenancy.NamespaceType, "ns1").Build()
41+
resource.AddFinalizer(res, "finalizer1")
42+
resource.AddFinalizer(res, "finalizer2")
43+
resource.RemoveFinalizer(res, "finalizer1")
44+
require.False(t, resource.HasFinalizer(res, "finalizer1"))
45+
require.True(t, resource.HasFinalizer(res, "finalizer2"))
46+
require.Equal(t, mapset.NewSet[string]("finalizer2"), resource.GetFinalizers(res))
47+
48+
// remove non-existent -> noop
49+
resource.RemoveFinalizer(res, "finalizer3")
50+
require.Equal(t, mapset.NewSet[string]("finalizer2"), resource.GetFinalizers(res))
51+
})
52+
53+
}

test-integ/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ require (
5353
github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf // indirect
5454
github.com/cpuguy83/dockercfg v0.3.1 // indirect
5555
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
56+
github.com/deckarep/golang-set/v2 v2.3.1 // indirect
5657
github.com/docker/distribution v2.8.2+incompatible // indirect
5758
github.com/docker/docker v24.0.5+incompatible // indirect
5859
github.com/docker/go-connections v0.4.0 // indirect

test-integ/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
163163
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
164164
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
165165
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
166+
github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A=
167+
github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
166168
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
167169
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
168170
github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=

test/integration/consul-container/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ require (
6868
github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf // indirect
6969
github.com/cpuguy83/dockercfg v0.3.1 // indirect
7070
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
71+
github.com/deckarep/golang-set/v2 v2.3.1 // indirect
7172
github.com/docker/distribution v2.8.2+incompatible // indirect
7273
github.com/docker/go-units v0.5.0 // indirect
7374
github.com/emicklei/go-restful/v3 v3.10.1 // indirect

test/integration/consul-container/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
159159
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
160160
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
161161
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
162+
github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A=
163+
github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
162164
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
163165
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
164166
github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=

0 commit comments

Comments
 (0)