Skip to content

Commit ef2fa92

Browse files
authored
Eliminate sharding.Ring interface (#450)
1 parent 450e5be commit ef2fa92

File tree

7 files changed

+36
-86
lines changed

7 files changed

+36
-86
lines changed

pkg/controller/controllerring/reconciler.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,7 @@ func (r *Reconciler) reconcileWebhooks(ctx context.Context, controllerRing *shar
186186
}
187187

188188
// add ring-specific path to webhook client config
189-
webhookPath, err := sharder.WebhookPathFor(controllerRing)
190-
if err != nil {
191-
return err
192-
}
189+
webhookPath := sharder.WebhookPathForControllerRing(controllerRing)
193190

194191
if service := webhook.ClientConfig.Service; service != nil {
195192
service.Path = ptr.To(path.Join(ptr.Deref(service.Path, ""), webhookPath))

pkg/controller/sharder/reconciler.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func (r *Reconciler) resyncResource(
146146
ctx context.Context,
147147
log logr.Logger,
148148
gr metav1.GroupResource,
149-
ring sharding.Ring,
149+
ring *shardingv1alpha1.ControllerRing,
150150
namespaces sets.Set[string],
151151
hashRing *consistenthash.Ring,
152152
shards leases.Shards,
@@ -194,7 +194,7 @@ func (r *Reconciler) resyncObject(
194194
log logr.Logger,
195195
gr metav1.GroupResource,
196196
obj *metav1.PartialObjectMetadata,
197-
ring sharding.Ring,
197+
ring *shardingv1alpha1.ControllerRing,
198198
hashRing *consistenthash.Ring,
199199
shards leases.Shards,
200200
controlled bool,
@@ -243,7 +243,7 @@ func (r *Reconciler) resyncObject(
243243
}
244244

245245
shardingmetrics.DrainsTotal.WithLabelValues(
246-
ring.GetName(), gr.Group, gr.Resource,
246+
ring.Name, gr.Group, gr.Resource,
247247
).Inc()
248248

249249
// object will go through the sharder webhook when shard removes the drain label, which will perform the assignment
@@ -264,7 +264,7 @@ func (r *Reconciler) resyncObject(
264264
}
265265

266266
shardingmetrics.MovementsTotal.WithLabelValues(
267-
ring.GetName(), gr.Group, gr.Resource,
267+
ring.Name, gr.Group, gr.Resource,
268268
).Inc()
269269

270270
return nil

pkg/sharding/key.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ import (
2222
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2323
"k8s.io/apimachinery/pkg/util/sets"
2424
"sigs.k8s.io/controller-runtime/pkg/client"
25+
26+
shardingv1alpha1 "github.com/timebertt/kubernetes-controller-sharding/pkg/apis/sharding/v1alpha1"
2527
)
2628

2729
// KeyFuncForResource returns the key function that maps the given resource or its controller dependening on whether
2830
// the resource is listed as a resource or controlled resource in the given ring.
29-
func KeyFuncForResource(gr metav1.GroupResource, ring Ring) (KeyFunc, error) {
31+
func KeyFuncForResource(gr metav1.GroupResource, ring *shardingv1alpha1.ControllerRing) (KeyFunc, error) {
3032
ringResources := sets.New[metav1.GroupResource]()
3133
controlledResources := sets.New[metav1.GroupResource]()
3234

pkg/sharding/ring.go

Lines changed: 0 additions & 33 deletions
This file was deleted.

pkg/sharding/ring/ring.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121

2222
coordinationv1 "k8s.io/api/coordination/v1"
2323

24-
"github.com/timebertt/kubernetes-controller-sharding/pkg/sharding"
24+
shardingv1alpha1 "github.com/timebertt/kubernetes-controller-sharding/pkg/apis/sharding/v1alpha1"
2525
"github.com/timebertt/kubernetes-controller-sharding/pkg/sharding/consistenthash"
2626
"github.com/timebertt/kubernetes-controller-sharding/pkg/sharding/leases"
2727
shardingmetrics "github.com/timebertt/kubernetes-controller-sharding/pkg/sharding/metrics"
@@ -32,13 +32,13 @@ import (
3232
// This is a central function in the sharding implementation bringing together the leases package with the
3333
// consistenthash package.
3434
// In short, it determines the subset of available shards and constructs a new consistenthash.Ring with it.
35-
func FromLeases(ringObj sharding.Ring, leaseList *coordinationv1.LeaseList, now time.Time) (*consistenthash.Ring, leases.Shards) {
35+
func FromLeases(controllerRing *shardingv1alpha1.ControllerRing, leaseList *coordinationv1.LeaseList, now time.Time) (*consistenthash.Ring, leases.Shards) {
3636
// determine ready shards and calculate hash ring
3737
shards := leases.ToShards(leaseList.Items, now)
3838
availableShards := shards.AvailableShards().IDs()
3939
ring := consistenthash.New(nil, 0, availableShards...)
4040

41-
shardingmetrics.RingCalculationsTotal.WithLabelValues(ringObj.GetName()).Inc()
41+
shardingmetrics.RingCalculationsTotal.WithLabelValues(controllerRing.Name).Inc()
4242

4343
return ring, shards
4444
}

pkg/webhook/sharder/add.go

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,13 @@ import (
2525

2626
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2727
"k8s.io/utils/clock"
28-
"sigs.k8s.io/controller-runtime/pkg/client"
2928
"sigs.k8s.io/controller-runtime/pkg/manager"
3029
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
3130

3231
shardingv1alpha1 "github.com/timebertt/kubernetes-controller-sharding/pkg/apis/sharding/v1alpha1"
33-
"github.com/timebertt/kubernetes-controller-sharding/pkg/sharding"
3432
)
3533

3634
const (
37-
// HandlerName is the name of the webhook handler.
38-
HandlerName = "sharder"
3935
// WebhookPathPrefix is the path prefix at which the handler should be registered.
4036
WebhookPathPrefix = "/webhooks/sharder/"
4137
)
@@ -58,41 +54,28 @@ func (h *Handler) AddToManager(mgr manager.Manager) error {
5854

5955
const pathControllerRing = "controllerring"
6056

61-
// WebhookPathFor returns the webhook handler path that should be used for implementing the given ring object.
62-
// It is the reverse of RingForWebhookPath.
63-
func WebhookPathFor(obj client.Object) (string, error) {
64-
switch obj.(type) {
65-
case *shardingv1alpha1.ControllerRing:
66-
return path.Join(WebhookPathPrefix, pathControllerRing, obj.GetName()), nil
67-
default:
68-
return "", fmt.Errorf("unexpected kind %T", obj)
69-
}
57+
// WebhookPathForControllerRing returns the webhook handler path that should be used for implementing the given
58+
// ControllerRing. It is the reverse of ControllerRingForWebhookPath.
59+
func WebhookPathForControllerRing(ring *shardingv1alpha1.ControllerRing) string {
60+
return path.Join(WebhookPathPrefix, pathControllerRing, ring.Name)
7061
}
7162

72-
// RingForWebhookPath returns the ring object that is associated with the given webhook handler path.
73-
// It is the reverse of WebhookPathFor.
74-
func RingForWebhookPath(requestPath string) (sharding.Ring, error) {
63+
// ControllerRingForWebhookPath returns the ControllerRing that is associated with the given webhook handler path.
64+
// It is the reverse of WebhookPathForControllerRing.
65+
func ControllerRingForWebhookPath(requestPath string) (*shardingv1alpha1.ControllerRing, error) {
7566
if !strings.HasPrefix(requestPath, WebhookPathPrefix) {
7667
return nil, fmt.Errorf("unexpected request path: %s", requestPath)
7768
}
7869

7970
parts := strings.SplitN(strings.TrimPrefix(requestPath, WebhookPathPrefix), "/", 3)
80-
if len(parts) < 2 {
71+
if len(parts) != 2 {
8172
return nil, fmt.Errorf("unexpected request path: %s", requestPath)
8273
}
83-
84-
var ring sharding.Ring
85-
switch parts[0] {
86-
case pathControllerRing:
87-
if len(parts) != 2 {
88-
return nil, fmt.Errorf("unexpected request path: %s", requestPath)
89-
}
90-
ring = &shardingv1alpha1.ControllerRing{ObjectMeta: metav1.ObjectMeta{Name: parts[1]}}
91-
default:
74+
if parts[0] != pathControllerRing {
9275
return nil, fmt.Errorf("unexpected request path: %s", requestPath)
9376
}
9477

95-
return ring, nil
78+
return &shardingv1alpha1.ControllerRing{ObjectMeta: metav1.ObjectMeta{Name: parts[1]}}, nil
9679
}
9780

9881
type ctxKey int

pkg/webhook/sharder/handler.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
logf "sigs.k8s.io/controller-runtime/pkg/log"
3333
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
3434

35+
shardingv1alpha1 "github.com/timebertt/kubernetes-controller-sharding/pkg/apis/sharding/v1alpha1"
3536
"github.com/timebertt/kubernetes-controller-sharding/pkg/sharding"
3637
shardingmetrics "github.com/timebertt/kubernetes-controller-sharding/pkg/sharding/metrics"
3738
"github.com/timebertt/kubernetes-controller-sharding/pkg/sharding/ring"
@@ -46,9 +47,9 @@ type Handler struct {
4647
func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.Response {
4748
log := logf.FromContext(ctx)
4849

49-
ringObj, err := RingForRequest(ctx, h.Reader)
50+
controllerRing, err := ControllerRingForRequest(ctx, h.Reader)
5051
if err != nil {
51-
return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error determining ring for request: %w", err))
52+
return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error determining ControllerRing for request: %w", err))
5253
}
5354

5455
// Unfortunately, admission.Decoder / runtime.Decoder can't handle decoding into PartialObjectMetadata.
@@ -58,7 +59,7 @@ func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.R
5859
return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error decoding object: %w", err))
5960
}
6061

61-
labelShard := ringObj.LabelShard()
62+
labelShard := controllerRing.LabelShard()
6263

6364
// Don't touch labels that the object already has, we can't simply reassign it because the active shard might still
6465
// be working on it.
@@ -69,7 +70,7 @@ func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.R
6970
keyFunc, err := sharding.KeyFuncForResource(metav1.GroupResource{
7071
Group: req.Resource.Group,
7172
Resource: req.Resource.Resource,
72-
}, ringObj)
73+
}, controllerRing)
7374
if err != nil {
7475
return admission.Errored(http.StatusBadRequest, fmt.Errorf("error deteriming hash key func for object: %w", err))
7576
}
@@ -84,15 +85,15 @@ func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.R
8485

8586
// collect list of shards in the ring
8687
leaseList := &coordinationv1.LeaseList{}
87-
if err := h.Reader.List(ctx, leaseList, client.MatchingLabelsSelector{Selector: ringObj.LeaseSelector()}); err != nil {
88+
if err := h.Reader.List(ctx, leaseList, client.MatchingLabelsSelector{Selector: controllerRing.LeaseSelector()}); err != nil {
8889
return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error listing Leases for ControllerRing: %w", err))
8990
}
9091

9192
// get ring from cache and hash the object onto the ring
92-
hashRing, _ := ring.FromLeases(ringObj, leaseList, h.Clock.Now())
93+
hashRing, _ := ring.FromLeases(controllerRing, leaseList, h.Clock.Now())
9394
shard := hashRing.Hash(key)
9495

95-
log.V(1).Info("Assigning object for ring", "ring", client.ObjectKeyFromObject(ringObj), "shard", shard)
96+
log.V(1).Info("Assigning object for ControllerRing", "controllerRing", client.ObjectKeyFromObject(controllerRing), "shard", shard)
9697

9798
patches := make([]jsonpatch.JsonPatchOperation, 0, 2)
9899
if obj.Labels == nil {
@@ -103,30 +104,30 @@ func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.R
103104

104105
if !ptr.Deref(req.DryRun, false) {
105106
shardingmetrics.AssignmentsTotal.WithLabelValues(
106-
ringObj.GetName(), req.Resource.Group, req.Resource.Resource,
107+
controllerRing.Name, req.Resource.Group, req.Resource.Resource,
107108
).Inc()
108109
}
109110

110111
return admission.Patched("assigning object", patches...)
111112
}
112113

113-
// RingForRequest returns the Ring object matching the requests' path.
114-
func RingForRequest(ctx context.Context, c client.Reader) (sharding.Ring, error) {
114+
// ControllerRingForRequest returns the Ring object matching the requests' path.
115+
func ControllerRingForRequest(ctx context.Context, c client.Reader) (*shardingv1alpha1.ControllerRing, error) {
115116
requestPath, err := RequestPathFromContext(ctx)
116117
if err != nil {
117118
return nil, err
118119
}
119120

120-
ring, err := RingForWebhookPath(requestPath)
121+
controllerRing, err := ControllerRingForWebhookPath(requestPath)
121122
if err != nil {
122123
return nil, err
123124
}
124125

125-
if err := c.Get(ctx, client.ObjectKeyFromObject(ring), ring); err != nil {
126-
return nil, fmt.Errorf("error getting ring: %w", err)
126+
if err := c.Get(ctx, client.ObjectKeyFromObject(controllerRing), controllerRing); err != nil {
127+
return nil, fmt.Errorf("error getting ControllerRing: %w", err)
127128
}
128129

129-
return ring, nil
130+
return controllerRing, nil
130131
}
131132

132133
// rfc6901Encoder can escape / characters in label keys for inclusion in JSON patch paths.

0 commit comments

Comments
 (0)