diff --git a/libnetwork/ipam/allocator_test.go b/libnetwork/ipam/allocator_test.go index b1fc6b69eb..de97461992 100644 --- a/libnetwork/ipam/allocator_test.go +++ b/libnetwork/ipam/allocator_test.go @@ -20,6 +20,7 @@ import ( "github.com/docker/libnetwork/ipamutils" _ "github.com/docker/libnetwork/testutils" "github.com/docker/libnetwork/types" + "github.com/stretchr/testify/assert" ) const ( @@ -170,662 +171,669 @@ func TestPoolDataMarshal(t *testing.T) { } func TestSubnetsMarshal(t *testing.T) { - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - pid0, _, _, err := a.RequestPool(localAddressSpace, "192.168.0.0/16", "", nil, false) - if err != nil { - t.Fatal(err) - } - pid1, _, _, err := a.RequestPool(localAddressSpace, "192.169.0.0/16", "", nil, false) - if err != nil { - t.Fatal(err) - } - _, _, err = a.RequestAddress(pid0, nil, nil) - if err != nil { - t.Fatal(err) - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + if err != nil { + t.Fatal(err) + } + pid0, _, _, err := a.RequestPool(localAddressSpace, "192.168.0.0/16", "", nil, false) + if err != nil { + t.Fatal(err) + } + pid1, _, _, err := a.RequestPool(localAddressSpace, "192.169.0.0/16", "", nil, false) + if err != nil { + t.Fatal(err) + } + _, _, err = a.RequestAddress(pid0, nil, nil) + if err != nil { + t.Fatal(err) + } - cfg, err := a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + cfg, err := a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - ba := cfg.Value() - if err := cfg.SetValue(ba); err != nil { - t.Fatal(err) - } + ba := cfg.Value() + if err := cfg.SetValue(ba); err != nil { + t.Fatal(err) + } - expIP := &net.IPNet{IP: net.IP{192, 168, 0, 2}, Mask: net.IPMask{255, 255, 0, 0}} - ip, _, err := a.RequestAddress(pid0, nil, nil) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(expIP, ip) { - t.Fatalf("Got unexpected ip after pool config restore: %s", ip) - } + expIP := &net.IPNet{IP: net.IP{192, 168, 0, 2}, Mask: net.IPMask{255, 255, 0, 0}} + ip, _, err := a.RequestAddress(pid0, nil, nil) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(expIP, ip) { + t.Fatalf("Got unexpected ip after pool config restore: %s", ip) + } - expIP = &net.IPNet{IP: net.IP{192, 169, 0, 1}, Mask: net.IPMask{255, 255, 0, 0}} - ip, _, err = a.RequestAddress(pid1, nil, nil) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(expIP, ip) { - t.Fatalf("Got unexpected ip after pool config restore: %s", ip) + expIP = &net.IPNet{IP: net.IP{192, 169, 0, 1}, Mask: net.IPMask{255, 255, 0, 0}} + ip, _, err = a.RequestAddress(pid1, nil, nil) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(expIP, ip) { + t.Fatalf("Got unexpected ip after pool config restore: %s", ip) + } } } func TestAddSubnets(t *testing.T) { - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - a.addrSpaces["abc"] = a.addrSpaces[localAddressSpace] + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + if err != nil { + t.Fatal(err) + } + a.addrSpaces["abc"] = a.addrSpaces[localAddressSpace] - pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) - if err != nil { - t.Fatal("Unexpected failure in adding subnet") - } + pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) + if err != nil { + t.Fatal("Unexpected failure in adding subnet") + } - pid1, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false) - if err != nil { - t.Fatalf("Unexpected failure in adding overlapping subnets to different address spaces: %v", err) - } + pid1, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false) + if err != nil { + t.Fatalf("Unexpected failure in adding overlapping subnets to different address spaces: %v", err) + } - if pid0 == pid1 { - t.Fatal("returned same pool id for same subnets in different namespaces") - } + if pid0 == pid1 { + t.Fatal("returned same pool id for same subnets in different namespaces") + } - pid, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false) - if err != nil { - t.Fatalf("Unexpected failure requesting existing subnet: %v", err) - } - if pid != pid1 { - t.Fatal("returned different pool id for same subnet requests") - } + pid, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false) + if err != nil { + t.Fatalf("Unexpected failure requesting existing subnet: %v", err) + } + if pid != pid1 { + t.Fatal("returned different pool id for same subnet requests") + } - _, _, _, err = a.RequestPool("abc", "10.128.0.0/9", "", nil, false) - if err == nil { - t.Fatal("Expected failure on adding overlapping base subnet") - } + _, _, _, err = a.RequestPool("abc", "10.128.0.0/9", "", nil, false) + if err == nil { + t.Fatal("Expected failure on adding overlapping base subnet") + } - pid2, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false) - if err != nil { - t.Fatalf("Unexpected failure on adding sub pool: %v", err) - } - pid3, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false) - if err != nil { - t.Fatalf("Unexpected failure on adding overlapping sub pool: %v", err) - } - if pid2 != pid3 { - t.Fatal("returned different pool id for same sub pool requests") - } + pid2, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false) + if err != nil { + t.Fatalf("Unexpected failure on adding sub pool: %v", err) + } + pid3, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false) + if err != nil { + t.Fatalf("Unexpected failure on adding overlapping sub pool: %v", err) + } + if pid2 != pid3 { + t.Fatal("returned different pool id for same sub pool requests") + } - _, _, _, err = a.RequestPool(localAddressSpace, "10.20.2.0/24", "", nil, false) - if err == nil { - t.Fatal("Failed to detect overlapping subnets") - } + _, _, _, err = a.RequestPool(localAddressSpace, "10.20.2.0/24", "", nil, false) + if err == nil { + t.Fatal("Failed to detect overlapping subnets") + } - _, _, _, err = a.RequestPool(localAddressSpace, "10.128.0.0/9", "", nil, false) - if err == nil { - t.Fatal("Failed to detect overlapping subnets") - } + _, _, _, err = a.RequestPool(localAddressSpace, "10.128.0.0/9", "", nil, false) + if err == nil { + t.Fatal("Failed to detect overlapping subnets") + } - _, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3:4:5:6::/112", "", nil, false) - if err != nil { - t.Fatalf("Failed to add v6 subnet: %s", err.Error()) - } + _, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3:4:5:6::/112", "", nil, false) + if err != nil { + t.Fatalf("Failed to add v6 subnet: %s", err.Error()) + } - _, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3::/64", "", nil, false) - if err == nil { - t.Fatal("Failed to detect overlapping v6 subnet") + _, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3::/64", "", nil, false) + if err == nil { + t.Fatal("Failed to detect overlapping v6 subnet") + } } } func TestAddReleasePoolID(t *testing.T) { - var k0, k1, k2 SubnetKey + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } + var k0, k1, k2 SubnetKey + aSpace, err := a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err := a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) + if err != nil { + t.Fatal("Unexpected failure in adding pool") + } + if err := k0.FromString(pid0); err != nil { + t.Fatal(err) + } - pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) - if err != nil { - t.Fatal("Unexpected failure in adding pool") - } - if err := k0.FromString(pid0); err != nil { - t.Fatal(err) - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + subnets := aSpace.subnets - subnets := aSpace.subnets + if subnets[k0].RefCount != 1 { + t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) + } - if subnets[k0].RefCount != 1 { - t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) - } + pid1, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false) + if err != nil { + t.Fatal("Unexpected failure in adding sub pool") + } + if err := k1.FromString(pid1); err != nil { + t.Fatal(err) + } - pid1, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false) - if err != nil { - t.Fatal("Unexpected failure in adding sub pool") - } - if err := k1.FromString(pid1); err != nil { - t.Fatal(err) - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + subnets = aSpace.subnets + if subnets[k1].RefCount != 1 { + t.Fatalf("Unexpected ref count for %s: %d", k1, subnets[k1].RefCount) + } - subnets = aSpace.subnets - if subnets[k1].RefCount != 1 { - t.Fatalf("Unexpected ref count for %s: %d", k1, subnets[k1].RefCount) - } + pid2, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false) + if err != nil { + t.Fatal("Unexpected failure in adding sub pool") + } + if pid0 == pid1 || pid0 == pid2 || pid1 != pid2 { + t.Fatalf("Incorrect poolIDs returned %s, %s, %s", pid0, pid1, pid2) + } + if err := k2.FromString(pid2); err != nil { + t.Fatal(err) + } - pid2, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false) - if err != nil { - t.Fatal("Unexpected failure in adding sub pool") - } - if pid0 == pid1 || pid0 == pid2 || pid1 != pid2 { - t.Fatalf("Incorrect poolIDs returned %s, %s, %s", pid0, pid1, pid2) - } - if err := k2.FromString(pid2); err != nil { - t.Fatal(err) - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + subnets = aSpace.subnets + if subnets[k2].RefCount != 2 { + t.Fatalf("Unexpected ref count for %s: %d", k2, subnets[k2].RefCount) + } - subnets = aSpace.subnets - if subnets[k2].RefCount != 2 { - t.Fatalf("Unexpected ref count for %s: %d", k2, subnets[k2].RefCount) - } + if subnets[k0].RefCount != 3 { + t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) + } - if subnets[k0].RefCount != 3 { - t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) - } + if err := a.ReleasePool(pid1); err != nil { + t.Fatal(err) + } - if err := a.ReleasePool(pid1); err != nil { - t.Fatal(err) - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + subnets = aSpace.subnets + if subnets[k0].RefCount != 2 { + t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) + } + if err := a.ReleasePool(pid0); err != nil { + t.Fatal(err) + } - subnets = aSpace.subnets - if subnets[k0].RefCount != 2 { - t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) - } - if err := a.ReleasePool(pid0); err != nil { - t.Fatal(err) - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + subnets = aSpace.subnets + if subnets[k0].RefCount != 1 { + t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) + } - subnets = aSpace.subnets - if subnets[k0].RefCount != 1 { - t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) - } + pid00, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) + if err != nil { + t.Fatal("Unexpected failure in adding pool") + } + if pid00 != pid0 { + t.Fatal("main pool should still exist") + } - pid00, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) - if err != nil { - t.Fatal("Unexpected failure in adding pool") - } - if pid00 != pid0 { - t.Fatal("main pool should still exist") - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + subnets = aSpace.subnets + if subnets[k0].RefCount != 2 { + t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) + } - subnets = aSpace.subnets - if subnets[k0].RefCount != 2 { - t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) - } + if err := a.ReleasePool(pid2); err != nil { + t.Fatal(err) + } - if err := a.ReleasePool(pid2); err != nil { - t.Fatal(err) - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + subnets = aSpace.subnets + if subnets[k0].RefCount != 1 { + t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) + } - subnets = aSpace.subnets - if subnets[k0].RefCount != 1 { - t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) - } + if err := a.ReleasePool(pid00); err != nil { + t.Fatal(err) + } - if err := a.ReleasePool(pid00); err != nil { - t.Fatal(err) - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } + subnets = aSpace.subnets + if bp, ok := subnets[k0]; ok { + t.Fatalf("Base pool %s is still present: %v", k0, bp) + } - subnets = aSpace.subnets - if bp, ok := subnets[k0]; ok { - t.Fatalf("Base pool %s is still present: %v", k0, bp) - } + _, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) + if err != nil { + t.Fatal("Unexpected failure in adding pool") + } - _, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) - if err != nil { - t.Fatal("Unexpected failure in adding pool") - } + aSpace, err = a.getAddrSpace(localAddressSpace) + if err != nil { + t.Fatal(err) + } - aSpace, err = a.getAddrSpace(localAddressSpace) - if err != nil { - t.Fatal(err) - } - - subnets = aSpace.subnets - if subnets[k0].RefCount != 1 { - t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) + subnets = aSpace.subnets + if subnets[k0].RefCount != 1 { + t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) + } } } func TestPredefinedPool(t *testing.T) { - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - if _, err := a.getPredefinedPool("blue", false); err == nil { - t.Fatal("Expected failure for non default addr space") - } + if _, err := a.getPredefinedPool("blue", false); err == nil { + t.Fatal("Expected failure for non default addr space") + } - pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false) - if err != nil { - t.Fatal(err) - } + pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false) + if err != nil { + t.Fatal(err) + } - nw2, err := a.getPredefinedPool(localAddressSpace, false) - if err != nil { - t.Fatal(err) - } - if types.CompareIPNet(nw, nw2) { - t.Fatalf("Unexpected default network returned: %s = %s", nw2, nw) - } + nw2, err := a.getPredefinedPool(localAddressSpace, false) + if err != nil { + t.Fatal(err) + } + if types.CompareIPNet(nw, nw2) { + t.Fatalf("Unexpected default network returned: %s = %s", nw2, nw) + } - if err := a.ReleasePool(pid); err != nil { - t.Fatal(err) + if err := a.ReleasePool(pid); err != nil { + t.Fatal(err) + } } } func TestRemoveSubnet(t *testing.T) { - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - a.addrSpaces["splane"] = &addrSpace{ - id: dsConfigKey + "/" + "splane", - ds: a.addrSpaces[localAddressSpace].ds, - alloc: a.addrSpaces[localAddressSpace].alloc, - scope: a.addrSpaces[localAddressSpace].scope, - subnets: map[SubnetKey]*PoolData{}, - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - input := []struct { - addrSpace string - subnet string - v6 bool - }{ - {localAddressSpace, "192.168.0.0/16", false}, - {localAddressSpace, "172.17.0.0/16", false}, - {localAddressSpace, "10.0.0.0/8", false}, - {localAddressSpace, "2001:db8:1:2:3:4:ffff::/112", false}, - {"splane", "172.17.0.0/16", false}, - {"splane", "10.0.0.0/8", false}, - {"splane", "2001:db8:1:2:3:4:5::/112", true}, - {"splane", "2001:db8:1:2:3:4:ffff::/112", true}, - } - - poolIDs := make([]string, len(input)) - - for ind, i := range input { - if poolIDs[ind], _, _, err = a.RequestPool(i.addrSpace, i.subnet, "", nil, i.v6); err != nil { - t.Fatalf("Failed to apply input. Can't proceed: %s", err.Error()) + a.addrSpaces["splane"] = &addrSpace{ + id: dsConfigKey + "/" + "splane", + ds: a.addrSpaces[localAddressSpace].ds, + alloc: a.addrSpaces[localAddressSpace].alloc, + scope: a.addrSpaces[localAddressSpace].scope, + subnets: map[SubnetKey]*PoolData{}, } - } - for ind, id := range poolIDs { - if err := a.ReleasePool(id); err != nil { - t.Fatalf("Failed to release poolID %s (%d)", id, ind) + input := []struct { + addrSpace string + subnet string + v6 bool + }{ + {localAddressSpace, "192.168.0.0/16", false}, + {localAddressSpace, "172.17.0.0/16", false}, + {localAddressSpace, "10.0.0.0/8", false}, + {localAddressSpace, "2001:db8:1:2:3:4:ffff::/112", false}, + {"splane", "172.17.0.0/16", false}, + {"splane", "10.0.0.0/8", false}, + {"splane", "2001:db8:1:2:3:4:5::/112", true}, + {"splane", "2001:db8:1:2:3:4:ffff::/112", true}, + } + + poolIDs := make([]string, len(input)) + + for ind, i := range input { + if poolIDs[ind], _, _, err = a.RequestPool(i.addrSpace, i.subnet, "", nil, i.v6); err != nil { + t.Fatalf("Failed to apply input. Can't proceed: %s", err.Error()) + } + } + + for ind, id := range poolIDs { + if err := a.ReleasePool(id); err != nil { + t.Fatalf("Failed to release poolID %s (%d)", id, ind) + } } } } func TestGetSameAddress(t *testing.T) { - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - a.addrSpaces["giallo"] = &addrSpace{ - id: dsConfigKey + "/" + "giallo", - ds: a.addrSpaces[localAddressSpace].ds, - alloc: a.addrSpaces[localAddressSpace].alloc, - scope: a.addrSpaces[localAddressSpace].scope, - subnets: map[SubnetKey]*PoolData{}, - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - pid, _, _, err := a.RequestPool("giallo", "192.168.100.0/24", "", nil, false) - if err != nil { - t.Fatal(err) - } + a.addrSpaces["giallo"] = &addrSpace{ + id: dsConfigKey + "/" + "giallo", + ds: a.addrSpaces[localAddressSpace].ds, + alloc: a.addrSpaces[localAddressSpace].alloc, + scope: a.addrSpaces[localAddressSpace].scope, + subnets: map[SubnetKey]*PoolData{}, + } - ip := net.ParseIP("192.168.100.250") - _, _, err = a.RequestAddress(pid, ip, nil) - if err != nil { - t.Fatal(err) - } + pid, _, _, err := a.RequestPool("giallo", "192.168.100.0/24", "", nil, false) + if err != nil { + t.Fatal(err) + } - _, _, err = a.RequestAddress(pid, ip, nil) - if err == nil { - t.Fatal(err) + ip := net.ParseIP("192.168.100.250") + _, _, err = a.RequestAddress(pid, ip, nil) + if err != nil { + t.Fatal(err) + } + + _, _, err = a.RequestAddress(pid, ip, nil) + if err == nil { + t.Fatal(err) + } } } func TestGetAddressSubPoolEqualPool(t *testing.T) { - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - // Requesting a subpool of same size of the master pool should not cause any problem on ip allocation - pid, _, _, err := a.RequestPool(localAddressSpace, "172.18.0.0/16", "172.18.0.0/16", nil, false) - if err != nil { - t.Fatal(err) - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - _, _, err = a.RequestAddress(pid, nil, nil) - if err != nil { - t.Fatal(err) + // Requesting a subpool of same size of the master pool should not cause any problem on ip allocation + pid, _, _, err := a.RequestPool(localAddressSpace, "172.18.0.0/16", "172.18.0.0/16", nil, false) + if err != nil { + t.Fatal(err) + } + + _, _, err = a.RequestAddress(pid, nil, nil) + if err != nil { + t.Fatal(err) + } } } func TestRequestReleaseAddressFromSubPool(t *testing.T) { - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - a.addrSpaces["rosso"] = &addrSpace{ - id: dsConfigKey + "/" + "rosso", - ds: a.addrSpaces[localAddressSpace].ds, - alloc: a.addrSpaces[localAddressSpace].alloc, - scope: a.addrSpaces[localAddressSpace].scope, - subnets: map[SubnetKey]*PoolData{}, - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false) - if err != nil { - t.Fatal(err) - } - - var ip *net.IPNet - expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}} - for err == nil { - var c *net.IPNet - if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil { - ip = c + a.addrSpaces["rosso"] = &addrSpace{ + id: dsConfigKey + "/" + "rosso", + ds: a.addrSpaces[localAddressSpace].ds, + alloc: a.addrSpaces[localAddressSpace].alloc, + scope: a.addrSpaces[localAddressSpace].scope, + subnets: map[SubnetKey]*PoolData{}, } - } - if err != ipamapi.ErrNoAvailableIPs { - t.Fatal(err) - } - if !types.CompareIPNet(expected, ip) { - t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) - } - rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}} - if err = a.ReleaseAddress(poolID, rp.IP); err != nil { - t.Fatal(err) - } - if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(rp, ip) { - t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) - } - _, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false) - if err != nil { - t.Fatal(err) - } - poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false) - if err != nil { - t.Fatal(err) - } - expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}} - for err == nil { - var c *net.IPNet - if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil { - ip = c + poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false) + if err != nil { + t.Fatal(err) } - } - if err != ipamapi.ErrNoAvailableIPs { - t.Fatal(err) - } - if !types.CompareIPNet(expected, ip) { - t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) - } - rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}} - if err = a.ReleaseAddress(poolID, rp.IP); err != nil { - t.Fatal(err) - } - if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(rp, ip) { - t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) - } - // Request any addresses from subpool after explicit address request - unoExp, _ := types.ParseCIDR("10.2.2.0/16") - dueExp, _ := types.ParseCIDR("10.2.2.2/16") - treExp, _ := types.ParseCIDR("10.2.2.1/16") + var ip *net.IPNet + expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}} + for err == nil { + var c *net.IPNet + if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil { + ip = c + } + } + if err != ipamapi.ErrNoAvailableIPs { + t.Fatal(err) + } + if !types.CompareIPNet(expected, ip) { + t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) + } + rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}} + if err = a.ReleaseAddress(poolID, rp.IP); err != nil { + t.Fatal(err) + } + if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(rp, ip) { + t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) + } - if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil { - t.Fatal(err) - } - tre, _, err := a.RequestAddress(poolID, treExp.IP, nil) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(tre, treExp) { - t.Fatalf("Unexpected address: %v", tre) - } + _, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false) + if err != nil { + t.Fatal(err) + } + poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false) + if err != nil { + t.Fatal(err) + } + expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}} + for err == nil { + var c *net.IPNet + if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil { + ip = c + } + } + if err != ipamapi.ErrNoAvailableIPs { + t.Fatal(err) + } + if !types.CompareIPNet(expected, ip) { + t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) + } + rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}} + if err = a.ReleaseAddress(poolID, rp.IP); err != nil { + t.Fatal(err) + } + if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(rp, ip) { + t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) + } - uno, _, err := a.RequestAddress(poolID, nil, nil) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(uno, unoExp) { - t.Fatalf("Unexpected address: %v", uno) - } + // Request any addresses from subpool after explicit address request + unoExp, _ := types.ParseCIDR("10.2.2.0/16") + dueExp, _ := types.ParseCIDR("10.2.2.2/16") + treExp, _ := types.ParseCIDR("10.2.2.1/16") - due, _, err := a.RequestAddress(poolID, nil, nil) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(due, dueExp) { - t.Fatalf("Unexpected address: %v", due) - } + if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil { + t.Fatal(err) + } + tre, _, err := a.RequestAddress(poolID, treExp.IP, nil) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(tre, treExp) { + t.Fatalf("Unexpected address: %v", tre) + } - if err = a.ReleaseAddress(poolID, uno.IP); err != nil { - t.Fatal(err) - } - uno, _, err = a.RequestAddress(poolID, nil, nil) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(uno, unoExp) { - t.Fatalf("Unexpected address: %v", uno) - } + uno, _, err := a.RequestAddress(poolID, nil, nil) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(uno, unoExp) { + t.Fatalf("Unexpected address: %v", uno) + } - if err = a.ReleaseAddress(poolID, tre.IP); err != nil { - t.Fatal(err) - } - tre, _, err = a.RequestAddress(poolID, nil, nil) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(tre, treExp) { - t.Fatalf("Unexpected address: %v", tre) + due, _, err := a.RequestAddress(poolID, nil, nil) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(due, dueExp) { + t.Fatalf("Unexpected address: %v", due) + } + + if err = a.ReleaseAddress(poolID, uno.IP); err != nil { + t.Fatal(err) + } + uno, _, err = a.RequestAddress(poolID, nil, nil) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(uno, unoExp) { + t.Fatalf("Unexpected address: %v", uno) + } + + if err = a.ReleaseAddress(poolID, tre.IP); err != nil { + t.Fatal(err) + } + tre, _, err = a.RequestAddress(poolID, nil, nil) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(tre, treExp) { + t.Fatalf("Unexpected address: %v", tre) + } } } func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) { opts := map[string]string{ - ipamapi.AllocSerialPrefix: "true", - } - a, err := getAllocator(false) - if err != nil { - t.Fatal(err) - } - a.addrSpaces["rosso"] = &addrSpace{ - id: dsConfigKey + "/" + "rosso", - ds: a.addrSpaces[localAddressSpace].ds, - alloc: a.addrSpaces[localAddressSpace].alloc, - scope: a.addrSpaces[localAddressSpace].scope, - subnets: map[SubnetKey]*PoolData{}, - } + ipamapi.AllocSerialPrefix: "true"} + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false) - if err != nil { - t.Fatal(err) - } - - var ip *net.IPNet - expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}} - for err == nil { - var c *net.IPNet - if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil { - ip = c + a.addrSpaces["rosso"] = &addrSpace{ + id: dsConfigKey + "/" + "rosso", + ds: a.addrSpaces[localAddressSpace].ds, + alloc: a.addrSpaces[localAddressSpace].alloc, + scope: a.addrSpaces[localAddressSpace].scope, + subnets: map[SubnetKey]*PoolData{}, } - } - if err != ipamapi.ErrNoAvailableIPs { - t.Fatal(err) - } - if !types.CompareIPNet(expected, ip) { - t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) - } - rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}} - if err = a.ReleaseAddress(poolID, rp.IP); err != nil { - t.Fatal(err) - } - if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(rp, ip) { - t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) - } - _, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false) - if err != nil { - t.Fatal(err) - } - poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false) - if err != nil { - t.Fatal(err) - } - expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}} - for err == nil { - var c *net.IPNet - if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil { - ip = c + poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false) + if err != nil { + t.Fatal(err) } - } - if err != ipamapi.ErrNoAvailableIPs { - t.Fatal(err) - } - if !types.CompareIPNet(expected, ip) { - t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) - } - rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}} - if err = a.ReleaseAddress(poolID, rp.IP); err != nil { - t.Fatal(err) - } - if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(rp, ip) { - t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) - } - // Request any addresses from subpool after explicit address request - unoExp, _ := types.ParseCIDR("10.2.2.0/16") - dueExp, _ := types.ParseCIDR("10.2.2.2/16") - treExp, _ := types.ParseCIDR("10.2.2.1/16") - quaExp, _ := types.ParseCIDR("10.2.2.3/16") - fivExp, _ := types.ParseCIDR("10.2.2.4/16") - if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil { - t.Fatal(err) - } - tre, _, err := a.RequestAddress(poolID, treExp.IP, opts) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(tre, treExp) { - t.Fatalf("Unexpected address: %v", tre) - } + var ip *net.IPNet + expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}} + for err == nil { + var c *net.IPNet + if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil { + ip = c + } + } + if err != ipamapi.ErrNoAvailableIPs { + t.Fatal(err) + } + if !types.CompareIPNet(expected, ip) { + t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) + } + rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}} + if err = a.ReleaseAddress(poolID, rp.IP); err != nil { + t.Fatal(err) + } + if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(rp, ip) { + t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) + } - uno, _, err := a.RequestAddress(poolID, nil, opts) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(uno, unoExp) { - t.Fatalf("Unexpected address: %v", uno) - } + _, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false) + if err != nil { + t.Fatal(err) + } + poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false) + if err != nil { + t.Fatal(err) + } + expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}} + for err == nil { + var c *net.IPNet + if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil { + ip = c + } + } + if err != ipamapi.ErrNoAvailableIPs { + t.Fatal(err) + } + if !types.CompareIPNet(expected, ip) { + t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) + } + rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}} + if err = a.ReleaseAddress(poolID, rp.IP); err != nil { + t.Fatal(err) + } + if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(rp, ip) { + t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) + } - due, _, err := a.RequestAddress(poolID, nil, opts) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(due, dueExp) { - t.Fatalf("Unexpected address: %v", due) - } + // Request any addresses from subpool after explicit address request + unoExp, _ := types.ParseCIDR("10.2.2.0/16") + dueExp, _ := types.ParseCIDR("10.2.2.2/16") + treExp, _ := types.ParseCIDR("10.2.2.1/16") + quaExp, _ := types.ParseCIDR("10.2.2.3/16") + fivExp, _ := types.ParseCIDR("10.2.2.4/16") + if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil { + t.Fatal(err) + } + tre, _, err := a.RequestAddress(poolID, treExp.IP, opts) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(tre, treExp) { + t.Fatalf("Unexpected address: %v", tre) + } - if err = a.ReleaseAddress(poolID, uno.IP); err != nil { - t.Fatal(err) - } - uno, _, err = a.RequestAddress(poolID, nil, opts) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(uno, quaExp) { - t.Fatalf("Unexpected address: %v", uno) - } + uno, _, err := a.RequestAddress(poolID, nil, opts) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(uno, unoExp) { + t.Fatalf("Unexpected address: %v", uno) + } - if err = a.ReleaseAddress(poolID, tre.IP); err != nil { - t.Fatal(err) - } - tre, _, err = a.RequestAddress(poolID, nil, opts) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(tre, fivExp) { - t.Fatalf("Unexpected address: %v", tre) + due, _, err := a.RequestAddress(poolID, nil, opts) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(due, dueExp) { + t.Fatalf("Unexpected address: %v", due) + } + + if err = a.ReleaseAddress(poolID, uno.IP); err != nil { + t.Fatal(err) + } + uno, _, err = a.RequestAddress(poolID, nil, opts) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(uno, quaExp) { + t.Fatalf("Unexpected address: %v", uno) + } + + if err = a.ReleaseAddress(poolID, tre.IP); err != nil { + t.Fatal(err) + } + tre, _, err = a.RequestAddress(poolID, nil, opts) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(tre, fivExp) { + t.Fatalf("Unexpected address: %v", tre) + } } } @@ -846,71 +854,71 @@ func TestRequestSyntaxCheck(t *testing.T) { pool = "192.168.0.0/16" subPool = "192.168.0.0/24" as = "green" - err error ) - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - a.addrSpaces[as] = &addrSpace{ - id: dsConfigKey + "/" + as, - ds: a.addrSpaces[localAddressSpace].ds, - alloc: a.addrSpaces[localAddressSpace].alloc, - scope: a.addrSpaces[localAddressSpace].scope, - subnets: map[SubnetKey]*PoolData{}, - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - _, _, _, err = a.RequestPool("", pool, "", nil, false) - if err == nil { - t.Fatal("Failed to detect wrong request: empty address space") - } + a.addrSpaces[as] = &addrSpace{ + id: dsConfigKey + "/" + as, + ds: a.addrSpaces[localAddressSpace].ds, + alloc: a.addrSpaces[localAddressSpace].alloc, + scope: a.addrSpaces[localAddressSpace].scope, + subnets: map[SubnetKey]*PoolData{}, + } - _, _, _, err = a.RequestPool("", pool, subPool, nil, false) - if err == nil { - t.Fatal("Failed to detect wrong request: empty address space") - } + _, _, _, err = a.RequestPool("", pool, "", nil, false) + if err == nil { + t.Fatal("Failed to detect wrong request: empty address space") + } - _, _, _, err = a.RequestPool(as, "", subPool, nil, false) - if err == nil { - t.Fatal("Failed to detect wrong request: subPool specified and no pool") - } + _, _, _, err = a.RequestPool("", pool, subPool, nil, false) + if err == nil { + t.Fatal("Failed to detect wrong request: empty address space") + } - pid, _, _, err := a.RequestPool(as, pool, subPool, nil, false) - if err != nil { - t.Fatalf("Unexpected failure: %v", err) - } + _, _, _, err = a.RequestPool(as, "", subPool, nil, false) + if err == nil { + t.Fatal("Failed to detect wrong request: subPool specified and no pool") + } - _, _, err = a.RequestAddress("", nil, nil) - if err == nil { - t.Fatal("Failed to detect wrong request: no pool id specified") - } + pid, _, _, err := a.RequestPool(as, pool, subPool, nil, false) + if err != nil { + t.Fatalf("Unexpected failure: %v", err) + } - ip := net.ParseIP("172.17.0.23") - _, _, err = a.RequestAddress(pid, ip, nil) - if err == nil { - t.Fatal("Failed to detect wrong request: requested IP from different subnet") - } + _, _, err = a.RequestAddress("", nil, nil) + if err == nil { + t.Fatal("Failed to detect wrong request: no pool id specified") + } - ip = net.ParseIP("192.168.0.50") - _, _, err = a.RequestAddress(pid, ip, nil) - if err != nil { - t.Fatalf("Unexpected failure: %v", err) - } + ip := net.ParseIP("172.17.0.23") + _, _, err = a.RequestAddress(pid, ip, nil) + if err == nil { + t.Fatal("Failed to detect wrong request: requested IP from different subnet") + } - err = a.ReleaseAddress("", ip) - if err == nil { - t.Fatal("Failed to detect wrong request: no pool id specified") - } + ip = net.ParseIP("192.168.0.50") + _, _, err = a.RequestAddress(pid, ip, nil) + if err != nil { + t.Fatalf("Unexpected failure: %v", err) + } - err = a.ReleaseAddress(pid, nil) - if err == nil { - t.Fatal("Failed to detect wrong request: no pool id specified") - } + err = a.ReleaseAddress("", ip) + if err == nil { + t.Fatal("Failed to detect wrong request: no pool id specified") + } - err = a.ReleaseAddress(pid, ip) - if err != nil { - t.Fatalf("Unexpected failure: %v: %s, %s", err, pid, ip) + err = a.ReleaseAddress(pid, nil) + if err == nil { + t.Fatal("Failed to detect wrong request: no pool id specified") + } + + err = a.ReleaseAddress(pid, ip) + if err != nil { + t.Fatalf("Unexpected failure: %v: %s, %s", err, pid, ip) + } } } @@ -951,65 +959,66 @@ func TestRelease(t *testing.T) { subnet = "192.168.0.0/23" ) - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) - if err != nil { - t.Fatal(err) - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - bm := a.addresses[SubnetKey{localAddressSpace, subnet, ""}] - - // Allocate all addresses - for err != ipamapi.ErrNoAvailableIPs { - _, _, err = a.RequestAddress(pid, nil, nil) - } - - toRelease := []struct { - address string - }{ - {"192.168.0.1"}, - {"192.168.0.2"}, - {"192.168.0.3"}, - {"192.168.0.4"}, - {"192.168.0.5"}, - {"192.168.0.6"}, - {"192.168.0.7"}, - {"192.168.0.8"}, - {"192.168.0.9"}, - {"192.168.0.10"}, - {"192.168.0.30"}, - {"192.168.0.31"}, - {"192.168.1.32"}, - - {"192.168.0.254"}, - {"192.168.1.1"}, - {"192.168.1.2"}, - - {"192.168.1.3"}, - - {"192.168.1.253"}, - {"192.168.1.254"}, - } - - // One by one, relase the address and request again. We should get the same IP - for i, inp := range toRelease { - ip0 := net.ParseIP(inp.address) - a.ReleaseAddress(pid, ip0) - bm = a.addresses[SubnetKey{localAddressSpace, subnet, ""}] - if bm.Unselected() != 1 { - t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected()) - } - - nw, _, err := a.RequestAddress(pid, nil, nil) + pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) if err != nil { - t.Fatalf("Failed to obtain the address: %s", err.Error()) + t.Fatal(err) } - ip := nw.IP - if !ip0.Equal(ip) { - t.Fatalf("Failed to obtain the same address. Expected: %s, Got: %s", ip0, ip) + + bm := a.addresses[SubnetKey{localAddressSpace, subnet, ""}] + + // Allocate all addresses + for err != ipamapi.ErrNoAvailableIPs { + _, _, err = a.RequestAddress(pid, nil, nil) + } + + toRelease := []struct { + address string + }{ + {"192.168.0.1"}, + {"192.168.0.2"}, + {"192.168.0.3"}, + {"192.168.0.4"}, + {"192.168.0.5"}, + {"192.168.0.6"}, + {"192.168.0.7"}, + {"192.168.0.8"}, + {"192.168.0.9"}, + {"192.168.0.10"}, + {"192.168.0.30"}, + {"192.168.0.31"}, + {"192.168.1.32"}, + + {"192.168.0.254"}, + {"192.168.1.1"}, + {"192.168.1.2"}, + + {"192.168.1.3"}, + + {"192.168.1.253"}, + {"192.168.1.254"}, + } + + // One by one, relase the address and request again. We should get the same IP + for i, inp := range toRelease { + ip0 := net.ParseIP(inp.address) + a.ReleaseAddress(pid, ip0) + bm = a.addresses[SubnetKey{localAddressSpace, subnet, ""}] + if bm.Unselected() != 1 { + t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected()) + } + + nw, _, err := a.RequestAddress(pid, nil, nil) + if err != nil { + t.Fatalf("Failed to obtain the address: %s", err.Error()) + } + ip := nw.IP + if !ip0.Equal(ip) { + t.Fatalf("Failed to obtain the same address. Expected: %s, Got: %s", ip0, ip) + } } } } @@ -1058,26 +1067,27 @@ func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP str ) lastIP := net.ParseIP(lastExpectedIP) - a, err := getAllocator(true) - if err != nil { - t.Fatal(err) - } - pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) - if err != nil { - t.Fatal(err) - } + for _, store := range []bool{false, true} { + a, err := getAllocator(store) + assert.NoError(t, err) - i := 0 - start := time.Now() - for ; i < numReq; i++ { - nw, _, err = a.RequestAddress(pid, nil, nil) - } - if printTime { - fmt.Printf("\nTaken %v, to allocate %d addresses on %s\n", time.Since(start), numReq, subnet) - } + pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) + if err != nil { + t.Fatal(err) + } - if !lastIP.Equal(nw.IP) { - t.Fatalf("Wrong last IP. Expected %s. Got: %s (err: %v, ind: %d)", lastExpectedIP, nw.IP.String(), err, i) + i := 0 + start := time.Now() + for ; i < numReq; i++ { + nw, _, err = a.RequestAddress(pid, nil, nil) + } + if printTime { + fmt.Printf("\nTaken %v, to allocate %d addresses on %s\n", time.Since(start), numReq, subnet) + } + + if !lastIP.Equal(nw.IP) { + t.Fatalf("Wrong last IP. Expected %s. Got: %s (err: %v, ind: %d)", lastExpectedIP, nw.IP.String(), err, i) + } } } @@ -1111,15 +1121,15 @@ func BenchmarkRequest_8(b *testing.B) { } func TestAllocateRandomDeallocate(t *testing.T) { - testAllocateRandomDeallocate(t, "172.25.0.0/16", "", 384) - testAllocateRandomDeallocate(t, "172.25.0.0/16", "172.25.252.0/22", 384) + for _, store := range []bool{false, true} { + testAllocateRandomDeallocate(t, "172.25.0.0/16", "", 384, store) + testAllocateRandomDeallocate(t, "172.25.0.0/16", "172.25.252.0/22", 384, store) + } } -func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int) { - ds, err := randomLocalStore(true) - if err != nil { - t.Fatal(err) - } +func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, store bool) { + ds, err := randomLocalStore(store) + assert.NoError(t, err) a, err := NewAllocator(ds, nil) if err != nil { diff --git a/libnetwork/ipam/parallel_test.go b/libnetwork/ipam/parallel_test.go new file mode 100644 index 0000000000..7f9bc94661 --- /dev/null +++ b/libnetwork/ipam/parallel_test.go @@ -0,0 +1,239 @@ +package ipam + +import ( + "context" + "fmt" + "net" + "sync" + "testing" + + "github.com/golang/sync/semaphore" + + "github.com/docker/libnetwork/ipamapi" + "github.com/stretchr/testify/assert" +) + +const ( + all = iota + even + odd +) + +type releaseMode uint + +type testContext struct { + a *Allocator + opts map[string]string + ipList []*net.IPNet + ipMap map[string]bool + pid string + maxIP int +} + +func newTestContext(t *testing.T, mask int, options map[string]string) *testContext { + a, err := getAllocator(true) + if err != nil { + t.Fatal(err) + } + a.addrSpaces["giallo"] = &addrSpace{ + id: dsConfigKey + "/" + "giallo", + ds: a.addrSpaces[localAddressSpace].ds, + alloc: a.addrSpaces[localAddressSpace].alloc, + scope: a.addrSpaces[localAddressSpace].scope, + subnets: map[SubnetKey]*PoolData{}, + } + + network := fmt.Sprintf("192.168.100.0/%d", mask) + // total ips 2^(32-mask) - 2 (network and broadcast) + totalIps := 1< 0 { + length++ + } + default: + t.Fatal("unsupported mode yet") + } + + ipIndex := make([]int, 0, length) + // calculate the index to release from the ipList + for i := startIndex; ; i += increment { + ipIndex = append(ipIndex, i) + if i+increment > stopIndex { + break + } + } + + var id int + parallelExec := semaphore.NewWeighted(parallel) + ch := make(chan *net.IPNet, len(ipIndex)) + wg := sync.WaitGroup{} + for index := range ipIndex { + wg.Add(1) + go func(id, index int) { + parallelExec.Acquire(context.Background(), 1) + // logrus.Errorf("index %v", index) + // logrus.Errorf("list %v", tctx.ipList) + err := tctx.a.ReleaseAddress(tctx.pid, tctx.ipList[index].IP) + if err != nil { + t.Fatalf("routine %d got %v", id, err) + } + ch <- tctx.ipList[index] + parallelExec.Release(1) + wg.Done() + }(id, index) + id++ + } + wg.Wait() + + for i := 0; i < len(ipIndex); i++ { + ip := <-ch + + // check if it is really free + _, _, err := tctx.a.RequestAddress(tctx.pid, ip.IP, nil) + assert.NoError(t, err, "ip %v not properly released", ip) + if err != nil { + t.Fatalf("ip %v not properly released, error:%v", ip, err) + } + err = tctx.a.ReleaseAddress(tctx.pid, ip.IP) + assert.NoError(t, err) + + if there, ok := tctx.ipMap[ip.String()]; !ok || !there { + t.Fatalf("ip %v got double deallocated", ip) + } + tctx.ipMap[ip.String()] = false + for j, v := range tctx.ipList { + if v == ip { + tctx.ipList = append(tctx.ipList[:j], tctx.ipList[j+1:]...) + break + } + } + } + + assert.Len(t, tctx.ipList, tctx.maxIP-length) +}