Skip to content

Commit ec2103a

Browse files
authored
fix(load-balancer): apply the service UID label to existing Load Balancers (#1325)
Set the service UID after copying the existing labels so it replaces a stale value. Unrelated labels on the Load Balancer are still preserved. This is reachable whenever a Load Balancer is adopted with a stale UID label: recreating a Service under the same name gives it a new UID, and `EnsureLoadBalancer` finds the existing Load Balancer through its name fallback, which also covers importing Load Balancers created by other means.
1 parent dbe5e21 commit ec2103a

2 files changed

Lines changed: 47 additions & 2 deletions

File tree

internal/hcops/load_balancer.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,10 +345,11 @@ func (l *LoadBalancerOps) changeHCLBInfo(ctx context.Context, lb *hcloud.LoadBal
345345

346346
if lb.Labels[LabelServiceUID] != string(svc.ObjectMeta.UID) {
347347
// Make a defensive copy of labels. This way we do not modify lb unless
348-
// updating is really successful.
348+
// updating is really successful. The service UID is set after copying,
349+
// so that it replaces a stale value instead of being overwritten by it.
349350
labels := make(map[string]string, len(lb.Labels)+1)
350-
labels[LabelServiceUID] = string(svc.ObjectMeta.UID)
351351
maps.Copy(labels, lb.Labels)
352+
labels[LabelServiceUID] = string(svc.ObjectMeta.UID)
352353
opts.Labels = labels
353354
update = true
354355
}

internal/hcops/load_balancer_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,50 @@ func TestLoadBalancerOps_ReconcileHCLB(t *testing.T) {
12471247
assert.Equal(t, "some-value", tt.initialLB.Labels["some-label"])
12481248
},
12491249
},
1250+
{
1251+
name: "replace stale service UID label",
1252+
serviceUID: "12",
1253+
initialLB: &hcloud.LoadBalancer{
1254+
ID: 12,
1255+
Labels: map[string]string{
1256+
hcops.LabelServiceUID: "stale-uid",
1257+
"some-label": "some-value",
1258+
},
1259+
PublicNet: hcloud.LoadBalancerPublicNet{
1260+
Enabled: true,
1261+
},
1262+
},
1263+
mock: func(_ *testing.T, tt *LBReconcilementTestCase) {
1264+
updated := *tt.initialLB
1265+
updated.Labels = map[string]string{
1266+
hcops.LabelServiceUID: tt.serviceUID,
1267+
"some-label": "some-value",
1268+
}
1269+
opts := hcloud.LoadBalancerUpdateOpts{
1270+
Labels: map[string]string{
1271+
hcops.LabelServiceUID: tt.serviceUID,
1272+
"some-label": "some-value",
1273+
},
1274+
}
1275+
tt.fx.LBClient.
1276+
On("Update", tt.fx.Ctx, tt.initialLB, opts).
1277+
Return(&updated, nil, nil)
1278+
},
1279+
perform: func(t *testing.T, tt *LBReconcilementTestCase) {
1280+
changed, err := tt.fx.LBOps.ReconcileHCLB(tt.fx.Ctx, tt.initialLB, tt.service)
1281+
assert.NoError(t, err)
1282+
assert.True(t, changed)
1283+
assert.Equal(t, tt.serviceUID, tt.initialLB.Labels[hcops.LabelServiceUID])
1284+
assert.Equal(t, "some-value", tt.initialLB.Labels["some-label"])
1285+
1286+
// The stale label must actually be replaced, otherwise every
1287+
// reconcile issues the same update again.
1288+
changed, err = tt.fx.LBOps.ReconcileHCLB(tt.fx.Ctx, tt.initialLB, tt.service)
1289+
assert.NoError(t, err)
1290+
assert.False(t, changed)
1291+
tt.fx.LBClient.AssertNumberOfCalls(t, "Update", 1)
1292+
},
1293+
},
12501294
{
12511295
name: "rename load balancer",
12521296
serviceUID: "11",

0 commit comments

Comments
 (0)