Skip to content

Commit d350ed8

Browse files
committed
Backport bugfix: update ring with new ip address when instance is lost, rejoins, but heartbeat is disabled
Signed-off-by: Charlie Le <[email protected]>
1 parent 3f03510 commit d350ed8

File tree

4 files changed

+42
-8
lines changed

4 files changed

+42
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## master / unreleased
44

5+
## 1.18.2 2025-07-09
6+
7+
* [BUGFIX] Backporting Ring: update ring with new ip address when instance is lost, rejoins, but heartbeat is disabled #6271
8+
59
## 1.18.1 2024-10-14
610

711
* [BUGFIX] Backporting upgrade to go 1.22.7 to patch CVE-2024-34155, CVE-2024-34156, CVE-2024-34158 #6217 #6264

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.18.1
1+
1.18.2

pkg/ring/lifecycler.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,9 @@ func (i *Lifecycler) initRing(ctx context.Context) error {
684684

685685
level.Info(i.logger).Log("msg", "existing entry found in ring", "state", i.GetState(), "tokens", len(tokens), "ring", i.RingName)
686686

687+
// Update the address if it has changed
688+
instanceDesc.Addr = i.Addr
689+
687690
// Update the ring if the instance has been changed and the heartbeat is disabled.
688691
// We dont need to update KV here when heartbeat is enabled as this info will eventually be update on KV
689692
// on the next heartbeat

pkg/ring/lifecycler_test.go

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ func testLifecyclerConfig(ringConfig Config, id string) LifecyclerConfig {
4040
return lifecyclerConfig
4141
}
4242

43+
// testLifecyclerConfigWithAddr creates a LifecyclerConfig with the given address.
44+
// This is useful for testing when we want to set the address to a specific value.
45+
func testLifecyclerConfigWithAddr(ringConfig Config, id string, addr string) LifecyclerConfig {
46+
l := testLifecyclerConfig(ringConfig, id)
47+
l.Addr = addr
48+
return l
49+
}
50+
4351
func checkNormalised(d interface{}, id string) bool {
4452
desc, ok := d.(*Desc)
4553
return ok &&
@@ -644,8 +652,8 @@ func TestRestartIngester_DisabledHeartbeat_unregister_on_shutdown_false(t *testi
644652
}
645653

646654
// Starts Ingester and wait it to became active
647-
startIngesterAndWaitActive := func(ingId string) *Lifecycler {
648-
lifecyclerConfig := testLifecyclerConfig(ringConfig, ingId)
655+
startIngesterAndWaitActive := func(ingId string, addr string) *Lifecycler {
656+
lifecyclerConfig := testLifecyclerConfigWithAddr(ringConfig, ingId, addr)
649657
// Disabling heartBeat and unregister_on_shutdown
650658
lifecyclerConfig.UnregisterOnShutdown = false
651659
lifecyclerConfig.HeartbeatPeriod = 0
@@ -662,10 +670,10 @@ func TestRestartIngester_DisabledHeartbeat_unregister_on_shutdown_false(t *testi
662670
// test if the ingester 2 became active after:
663671
// * Clean Shutdown (LEAVING after shutdown)
664672
// * Crashes while in the PENDING or JOINING state
665-
l1 := startIngesterAndWaitActive("ing1")
673+
l1 := startIngesterAndWaitActive("ing1", "0.0.0.0")
666674
defer services.StopAndAwaitTerminated(context.Background(), l1) //nolint:errcheck
667675

668-
l2 := startIngesterAndWaitActive("ing2")
676+
l2 := startIngesterAndWaitActive("ing2", "0.0.0.0")
669677

670678
ingesters := poll(func(desc *Desc) bool {
671679
return len(desc.Ingesters) == 2 && desc.Ingesters["ing1"].State == ACTIVE && desc.Ingesters["ing2"].State == ACTIVE
@@ -684,7 +692,7 @@ func TestRestartIngester_DisabledHeartbeat_unregister_on_shutdown_false(t *testi
684692
assert.Equal(t, LEAVING, ingesters["ing2"].State)
685693

686694
// Start Ingester2 again - Should flip back to ACTIVE in the ring
687-
l2 = startIngesterAndWaitActive("ing2")
695+
l2 = startIngesterAndWaitActive("ing2", "0.0.0.0")
688696
require.NoError(t, services.StopAndAwaitTerminated(context.Background(), l2))
689697

690698
// Simulate ingester2 crash on startup and left the ring with JOINING state
@@ -698,7 +706,7 @@ func TestRestartIngester_DisabledHeartbeat_unregister_on_shutdown_false(t *testi
698706
})
699707
require.NoError(t, err)
700708

701-
l2 = startIngesterAndWaitActive("ing2")
709+
l2 = startIngesterAndWaitActive("ing2", "0.0.0.0")
702710
require.NoError(t, services.StopAndAwaitTerminated(context.Background(), l2))
703711

704712
// Simulate ingester2 crash on startup and left the ring with PENDING state
@@ -712,7 +720,26 @@ func TestRestartIngester_DisabledHeartbeat_unregister_on_shutdown_false(t *testi
712720
})
713721
require.NoError(t, err)
714722

715-
l2 = startIngesterAndWaitActive("ing2")
723+
l2 = startIngesterAndWaitActive("ing2", "0.0.0.0")
724+
require.NoError(t, services.StopAndAwaitTerminated(context.Background(), l2))
725+
726+
// Simulate ingester2 crashing and left the ring with ACTIVE state, but when it comes up
727+
// it has a different ip address
728+
startIngesterAndWaitActive("ing2", "0.0.0.0")
729+
ingesters = poll(func(desc *Desc) bool {
730+
return desc.Ingesters["ing2"].State == ACTIVE && desc.Ingesters["ing2"].Addr == "0.0.0.0:1"
731+
})
732+
assert.Equal(t, ACTIVE, ingesters["ing2"].State)
733+
assert.Equal(t, "0.0.0.0:1", ingesters["ing2"].Addr)
734+
735+
l2 = startIngesterAndWaitActive("ing2", "1.1.1.1")
736+
737+
// The ring should have the new ip address
738+
ingesters = poll(func(desc *Desc) bool {
739+
return desc.Ingesters["ing2"].State == ACTIVE && desc.Ingesters["ing2"].Addr == "1.1.1.1:1"
740+
})
741+
assert.Equal(t, ACTIVE, ingesters["ing2"].State)
742+
assert.Equal(t, "1.1.1.1:1", ingesters["ing2"].Addr)
716743
require.NoError(t, services.StopAndAwaitTerminated(context.Background(), l2))
717744
}
718745

0 commit comments

Comments
 (0)