diff --git a/ipam/allocator.go b/ipam/allocator.go
index 83172c97..655ec07b 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.CIDR, hasBeenCancelled func() bool) (address.Address, error) {
@@ -343,6 +354,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 00000000..a4e36c15
--- /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 47a5b566..1128f653 100644
--- a/ipam/http.go
+++ b/ipam/http.go
@@ -82,6 +82,10 @@ func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CID
}
})
+ 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"], true); ok {
diff --git a/site/ipam/overview-init-ipam.md b/site/ipam/overview-init-ipam.md
index f85eb49c..9c687604 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)
@@ -111,6 +112,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
diff --git a/weave b/weave
index a05ff71c..1f7259cc 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