From bc70e73f9c4910ddbe80161a1aa181dc92d456a1 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 24 Feb 2016 14:43:06 +0000 Subject: [PATCH] Implement `weave consense` --- ipam/allocator.go | 12 ++++++++++++ ipam/consense.go | 24 ++++++++++++++++++++++++ ipam/http.go | 4 ++++ site/ipam/overview-init-ipam.md | 16 ++++++++++++++-- weave | 5 +++++ 5 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 ipam/consense.go diff --git a/ipam/allocator.go b/ipam/allocator.go index 4ea0eb8167..256822c2a0 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -54,6 +54,7 @@ type Allocator struct { nicknames map[mesh.PeerName]string // so we can map nicknames for rmpeer pendingAllocates []operation // held until we get some free space pendingClaims []operation // held until we know who owns the space + pendingConsenses []operation // held until consensus achieved dead map[string]time.Time // containers we heard were dead, and when db db.DB // persistence gossip mesh.Gossip // our link to the outside world for sending messages @@ -165,6 +166,8 @@ func (alloc *Allocator) tryOps(ops *[]operation) { // Try all pending operations func (alloc *Allocator) tryPendingOps() { + // Unblock pending consenses first + alloc.tryOps(&alloc.pendingConsenses) // Process existing claims before servicing new allocations alloc.tryOps(&alloc.pendingClaims) alloc.tryOps(&alloc.pendingAllocates) @@ -193,6 +196,14 @@ func (e *errorCancelled) Error() string { // Actor client API +// Consense (Sync) - wait for consensus +func (alloc *Allocator) Consense() { + resultChan := make(chan struct{}) + op := &consense{resultChan: resultChan} + alloc.doOperation(op, &alloc.pendingConsenses) + <-resultChan +} + // Allocate (Sync) - get new IP address for container with given name in range // if there isn't any space in that range we block indefinitely func (alloc *Allocator) Allocate(ident string, r address.Range, hasBeenCancelled func() bool) (address.Address, error) { @@ -348,6 +359,7 @@ func (alloc *Allocator) Shutdown() { alloc.shuttingDown = true alloc.cancelOps(&alloc.pendingClaims) alloc.cancelOps(&alloc.pendingAllocates) + alloc.cancelOps(&alloc.pendingConsenses) if heir := alloc.pickPeerForTransfer(); heir != mesh.UnknownPeerName { alloc.ring.Transfer(alloc.ourName, heir) alloc.space.Clear() diff --git a/ipam/consense.go b/ipam/consense.go new file mode 100644 index 0000000000..a4e36c15a6 --- /dev/null +++ b/ipam/consense.go @@ -0,0 +1,24 @@ +package ipam + +type consense struct { + resultChan chan<- struct{} +} + +func (c *consense) Try(alloc *Allocator) bool { + if !alloc.ring.Empty() { + close(c.resultChan) + return true + } + + alloc.establishRing() + + return false +} + +func (c *consense) Cancel() { + close(c.resultChan) +} + +func (c *consense) ForContainer(ident string) bool { + return false +} diff --git a/ipam/http.go b/ipam/http.go index eb51b87a10..7ca1312e1d 100644 --- a/ipam/http.go +++ b/ipam/http.go @@ -77,6 +77,10 @@ func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CID w.WriteHeader(204) }) + router.Methods("GET").Path("/consensus").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + alloc.Consense() + }) + router.Methods("GET").Path("/ip/{id}/{ip}/{prefixlen}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) if subnet, ok := parseCIDR(w, vars["ip"]+"/"+vars["prefixlen"]); ok { diff --git a/site/ipam/overview-init-ipam.md b/site/ipam/overview-init-ipam.md index 727216c9e8..afd651a52e 100644 --- a/site/ipam/overview-init-ipam.md +++ b/site/ipam/overview-init-ipam.md @@ -15,6 +15,7 @@ The following automatic IP address managment topics are discussed: * [Initializing Peers on a Weave Network](#initialization) * [`--init-peer-count` and How Quorum is Achieved](#quorum) + * [Forcing Consensus](#forcing-consensus) * [Choosing an Allocation Range](#range) @@ -100,6 +101,19 @@ is safe with respect to Weave's startup quorum: ...host1 is rebooted... host1$ weave launch $HOST2 $HOST3 +### Forcing Consensus + +Under certain circumstances (for example when adding new nodes to an +existing cluster) it is desirable to ensure that a node has +successfully joined and received a copy of the IPAM data structure +shared amongst the peers. An administrative command is provided for +this purpose: + + host1$ weave consense + +This operation will block until the node on which it is run has joined +successfully. + ### Choosing an Allocation Range By default, Weave allocates IP addresses in the 10.32.0.0/12 @@ -126,5 +140,3 @@ to the rest of the network without any conflicts arising. * [Automatic Allocation Across Multiple Subnets](/site/ipam/allocation-multi-ipam.md) * [Plugin Command-line Arguments](/site/plugin/plug-in-command-line.md) - - \ No newline at end of file diff --git a/weave b/weave index 6364bcfd3a..69bc9e07a9 100755 --- a/weave +++ b/weave @@ -51,6 +51,8 @@ weave launch [--rewrite-inspect] launch-plugin [--no-multicast-route] +weave consense + weave env [--restore] config dns-args @@ -2186,6 +2188,9 @@ EOF echo "The 'stop-dns command has been removed; DNS is stopped as part of 'stop' and 'stop-router'." >&2 exit 0 ;; + consense) + call_weave GET /consensus + ;; *) echo "Unknown weave command '$COMMAND'" >&2 usage