diff --git a/ipam/allocator.go b/ipam/allocator.go index e3765aca..f57f9132 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -126,11 +126,13 @@ func (alloc *Allocator) cancelOps(ops *[]operation) { // if we found any. func (alloc *Allocator) cancelOpsFor(ops *[]operation, ident string) bool { var found bool - for i, op := range *ops { - if op.ForContainer(ident) { + for i := 0; i < len(*ops); { + if op := (*ops)[i]; op.ForContainer(ident) { found = true op.Cancel() *ops = append((*ops)[:i], (*ops)[i+1:]...) + } else { + i++ } } return found diff --git a/ipam/allocator_test.go b/ipam/allocator_test.go index fd444190..220ee176 100644 --- a/ipam/allocator_test.go +++ b/ipam/allocator_test.go @@ -229,7 +229,6 @@ func TestCancel(t *testing.T) { doneChan <- ok == nil }() - AssertNothingSent(t, doneChan) time.Sleep(100 * time.Millisecond) AssertNothingSent(t, doneChan) @@ -240,6 +239,39 @@ func TestCancel(t *testing.T) { } } +func TestCancelOnDied(t *testing.T) { + const ( + CIDR = "10.0.1.7/26" + container1 = "abcdef" + ) + + router := gossip.NewTestRouter(0.0) + alloc1, subnet := makeAllocator("01:00:00:02:00:00", CIDR, 2) + alloc1.SetInterfaces(router.Connect(alloc1.ourName, alloc1)) + alloc1.Start() + + doneChan := make(chan bool) + f := func() { + _, ok := alloc1.Allocate(container1, subnet, nil) + doneChan <- ok == nil + } + + // Attempt two allocations in parallel, to check that this is handled correctly + go f() + go f() + + // Nothing should happen, because we declared the quorum as 2 + time.Sleep(100 * time.Millisecond) + AssertNothingSent(t, doneChan) + + alloc1.ContainerDied(container1) + + // Check that the two allocations both exit with an error + if <-doneChan || <-doneChan { + require.FailNow(t, "Error: got result from Allocate") + } +} + func TestGossipShutdown(t *testing.T) { const ( container1 = "abcdef"