diff --git a/ipam/allocate.go b/ipam/allocate.go index c11f75ed..72e3af69 100644 --- a/ipam/allocate.go +++ b/ipam/allocate.go @@ -25,15 +25,15 @@ func (g *allocate) Try(alloc *Allocator) bool { return true } - if addr, found := alloc.ownedInRange(g.ident, g.r); found { + if addrs := alloc.ownedInRange(g.ident, g.r); len(addrs) > 0 { // If we had heard that this container died, resurrect it delete(alloc.dead, g.ident) // delete is no-op if key not in map - g.resultChan <- allocateResult{addr, nil} + g.resultChan <- allocateResult{addrs[0], nil} return true } if !alloc.universe.Overlaps(g.r) { - g.resultChan <- allocateResult{0, fmt.Errorf("range %s out of bounds: %s", g.r, alloc.universe)} + g.resultChan <- allocateResult{err: fmt.Errorf("range %s out of bounds: %s", g.r, alloc.universe)} return true } @@ -66,7 +66,7 @@ func (g *allocate) Try(alloc *Allocator) bool { } func (g *allocate) Cancel() { - g.resultChan <- allocateResult{0, &errorCancelled{"Allocate", g.ident}} + g.resultChan <- allocateResult{err: &errorCancelled{"Allocate", g.ident}} } func (g *allocate) ForContainer(ident string) bool { diff --git a/ipam/allocator.go b/ipam/allocator.go index 4ea0eb81..235ab65d 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -203,18 +203,13 @@ func (alloc *Allocator) Allocate(ident string, r address.Range, hasBeenCancelled return result.addr, result.err } -// Lookup (Sync) - get existing IP address for container with given name in range -func (alloc *Allocator) Lookup(ident string, r address.Range) (address.Address, error) { - resultChan := make(chan allocateResult) +// Lookup (Sync) - get existing IP addresses for container with given name in range +func (alloc *Allocator) Lookup(ident string, r address.Range) ([]address.Address, error) { + resultChan := make(chan []address.Address) alloc.actionChan <- func() { - if addr, found := alloc.ownedInRange(ident, r); found { - resultChan <- allocateResult{addr: addr} - return - } - resultChan <- allocateResult{err: fmt.Errorf("lookup: no address found for %s in range %s", ident, r)} + resultChan <- alloc.ownedInRange(ident, r) } - result := <-resultChan - return result.addr, result.err + return <-resultChan, nil } // Claim an address that we think we should own (Sync) @@ -861,13 +856,14 @@ func (alloc *Allocator) removeOwned(ident string, addrToFree address.Address) bo return false } -func (alloc *Allocator) ownedInRange(ident string, r address.Range) (address.Address, bool) { +func (alloc *Allocator) ownedInRange(ident string, r address.Range) []address.Address { + var a []address.Address for _, addr := range alloc.owned[ident] { if r.Contains(addr) { - return addr, true + a = append(a, addr) } } - return 0, false + return a } func (alloc *Allocator) findOwner(addr address.Address) string { diff --git a/ipam/allocator_test.go b/ipam/allocator_test.go index c9eef59c..55a631e7 100644 --- a/ipam/allocator_test.go +++ b/ipam/allocator_test.go @@ -49,6 +49,10 @@ func TestAllocFree(t *testing.T) { require.NoError(t, err) require.Equal(t, testAddr2, addr2.String(), "address") + addrs, err := alloc.Lookup(container1, subnet) + require.NoError(t, err) + require.Equal(t, []address.Address{addr1, addr2}, addrs) + // Ask for another address for a different container and check it's different addr1b, _ := alloc.Allocate(container2, cidr1.HostRange(), returnFalse) if addr1b.String() == testAddr1 { diff --git a/ipam/http.go b/ipam/http.go index eb51b87a..2cfc26fa 100644 --- a/ipam/http.go +++ b/ipam/http.go @@ -29,6 +29,15 @@ func parseCIDR(w http.ResponseWriter, cidrStr string) (address.CIDR, bool) { return cidr, true } +func writeAddresses(w http.ResponseWriter, addrs []address.Address, subnet address.CIDR) { + for i, addr := range addrs { + fmt.Fprintf(w, "%s/%d", addr, subnet.PrefixLen) + if i < len(addrs)-1 { + w.Write([]byte{' '}) + } + } +} + func (alloc *Allocator) handleHTTPAllocate(dockerCli *docker.Client, w http.ResponseWriter, ident string, checkAlive bool, subnet address.CIDR) { closedChan := w.(http.CloseNotifier).CloseNotify() addr, err := alloc.Allocate(ident, subnet.HostRange(), @@ -80,22 +89,22 @@ func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CID 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 { - addr, err := alloc.Lookup(vars["id"], subnet.HostRange()) + addrs, err := alloc.Lookup(vars["id"], subnet.HostRange()) if err != nil { http.NotFound(w, r) return } - fmt.Fprintf(w, "%s/%d", addr, subnet.PrefixLen) + writeAddresses(w, addrs, subnet) } }) router.Methods("GET").Path("/ip/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - addr, err := alloc.Lookup(mux.Vars(r)["id"], defaultSubnet.HostRange()) + addrs, err := alloc.Lookup(mux.Vars(r)["id"], defaultSubnet.HostRange()) if err != nil { http.NotFound(w, r) return } - fmt.Fprintf(w, "%s/%d", addr, defaultSubnet.PrefixLen) + writeAddresses(w, addrs, defaultSubnet) }) router.Methods("POST").Path("/ip/{id}/{ip}/{prefixlen}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/weave b/weave index 6364bcfd..2d6d4135 100755 --- a/weave +++ b/weave @@ -1343,7 +1343,7 @@ ipam_cidrs() { echo "IP address allocation must be enabled to use 'net:'" >&2 return 1 fi - elif ! is_cidr "$CIDR" ; then + elif [ -n "$CIDR" ] && ! is_cidr "$CIDR" ; then echo "$CIDR" >&2 return 1 else