diff --git a/ipam/allocator.go b/ipam/allocator.go index 57c01d87..7d4d4096 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -83,6 +83,7 @@ func NewAllocator(ourName mesh.PeerName, ourUID mesh.PeerUID, ourNickname string // Start runs the allocator goroutine func (alloc *Allocator) Start() { + alloc.loadPersistedRing() actionChan := make(chan func(), mesh.ChannelSize) alloc.actionChan = actionChan alloc.ticker = time.NewTicker(tickInterval) @@ -583,6 +584,7 @@ func (alloc *Allocator) ringUpdated() { alloc.paxos = nil } + alloc.persistRing() alloc.space.UpdateRanges(alloc.ring.OwnedRanges()) alloc.tryPendingOps() } @@ -730,6 +732,7 @@ func (alloc *Allocator) donateSpace(r address.Range, to mesh.PeerName) { } alloc.debugln("Giving range", chunk, "to", to) alloc.ring.GrantRangeToHost(chunk.Start, chunk.End, to) + alloc.persistRing() } func (alloc *Allocator) assertInvariants() { @@ -762,6 +765,26 @@ func (alloc *Allocator) reportFreeSpace() { alloc.ring.ReportFree(freespace) } +// Persisting the Ring +const ( + ringIdent = "ring" +) + +func (alloc *Allocator) persistRing() { + if err := alloc.db.Save(ringIdent, alloc.ring); err != nil { + common.Log.Errorf("Error persisting ring data: %s", err) + } +} + +func (alloc *Allocator) loadPersistedRing() { + if err := alloc.db.Load(ringIdent, &alloc.ring); err != nil { + common.Log.Errorf("Error loading persisted ring data: %s", err) + } + if alloc.ring != nil { + alloc.space.UpdateRanges(alloc.ring.OwnedRanges()) + } +} + // Owned addresses func (alloc *Allocator) allOwned(ident string) []address.Address { diff --git a/test/162_persist_ipam_2_test.sh b/test/162_persist_ipam_2_test.sh new file mode 100755 index 00000000..e5efac96 --- /dev/null +++ b/test/162_persist_ipam_2_test.sh @@ -0,0 +1,43 @@ +#! /bin/bash + +. ./config.sh + +start_suite "Checking persistence of IPAM" + +launch_router_with_db() { + host=$1 + shift + WEAVE_DOCKER_ARGS="-v /tmp:/db" weave_on $host launch-router --db-prefix=/db/test162- "$@" +} + +# Remove any persisted data from previous runs +run_on $HOST1 "sudo rm -f /tmp/test162-*" +run_on $HOST2 "sudo rm -f /tmp/test162-*" + +launch_router_with_db $HOST1 +launch_router_with_db $HOST2 $HOST1 + +start_container $HOST1 --name=c1 +C1=$(container_ip $HOST1 c1) +start_container $HOST2 --name=c2 +assert_raises "exec_on $HOST2 c2 $PING $C1" + +stop_router_on $HOST1 +stop_router_on $HOST2 + +# Start just HOST2; if nothing persisted it would form its own ring +launch_router_with_db $HOST2 +start_container $HOST2 --name=c3 +C3=$(container_ip $HOST2 c3) +assert_raises "[ $C3 != $C1 ]" + +stop_router_on $HOST2 + +# Now start HOST1 with HOST2 down and see if it hangs when we launch a container +launch_router_with_db $HOST1 $HOST2 +start_container $HOST1 --name=c4 +C4=$(container_ip $HOST1 c4) +assert_raises "[ $C4 != $C1 ]" +assert_raises "[ $C4 != $C3 ]" + +end_suite