mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
IPAM tests
Added tests for swarm mode and also some new parallel tests Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>
This commit is contained in:
parent
b8c14de74a
commit
4c8d751400
2 changed files with 932 additions and 683 deletions
|
@ -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,7 +171,8 @@ func TestPoolDataMarshal(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSubnetsMarshal(t *testing.T) {
|
||||
a, err := getAllocator(true)
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -214,10 +216,12 @@ func TestSubnetsMarshal(t *testing.T) {
|
|||
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)
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -281,16 +285,15 @@ func TestAddSubnets(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatal("Failed to detect overlapping v6 subnet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddReleasePoolID(t *testing.T) {
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var k0, k1, k2 SubnetKey
|
||||
|
||||
a, err := getAllocator(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
aSpace, err := a.getAddrSpace(localAddressSpace)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -445,13 +448,13 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
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")
|
||||
|
@ -473,13 +476,14 @@ func TestPredefinedPool(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
assert.NoError(t, err)
|
||||
|
||||
a.addrSpaces["splane"] = &addrSpace{
|
||||
id: dsConfigKey + "/" + "splane",
|
||||
ds: a.addrSpaces[localAddressSpace].ds,
|
||||
|
@ -516,13 +520,14 @@ func TestRemoveSubnet(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
assert.NoError(t, err)
|
||||
|
||||
a.addrSpaces["giallo"] = &addrSpace{
|
||||
id: dsConfigKey + "/" + "giallo",
|
||||
ds: a.addrSpaces[localAddressSpace].ds,
|
||||
|
@ -546,13 +551,14 @@ func TestGetSameAddress(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAddressSubPoolEqualPool(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)
|
||||
|
||||
// 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 {
|
||||
|
@ -563,13 +569,14 @@ func TestGetAddressSubPoolEqualPool(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestReleaseAddressFromSubPool(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)
|
||||
|
||||
a.addrSpaces["rosso"] = &addrSpace{
|
||||
id: dsConfigKey + "/" + "rosso",
|
||||
ds: a.addrSpaces[localAddressSpace].ds,
|
||||
|
@ -693,16 +700,16 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
ipamapi.AllocSerialPrefix: "true"}
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
assert.NoError(t, err)
|
||||
|
||||
a.addrSpaces["rosso"] = &addrSpace{
|
||||
id: dsConfigKey + "/" + "rosso",
|
||||
ds: a.addrSpaces[localAddressSpace].ds,
|
||||
|
@ -827,6 +834,7 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
if !types.CompareIPNet(tre, fivExp) {
|
||||
t.Fatalf("Unexpected address: %v", tre)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAddress(t *testing.T) {
|
||||
|
@ -846,13 +854,12 @@ 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)
|
||||
}
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
assert.NoError(t, err)
|
||||
|
||||
a.addrSpaces[as] = &addrSpace{
|
||||
id: dsConfigKey + "/" + as,
|
||||
ds: a.addrSpaces[localAddressSpace].ds,
|
||||
|
@ -912,6 +919,7 @@ func TestRequestSyntaxCheck(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Unexpected failure: %v: %s, %s", err, pid, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequest(t *testing.T) {
|
||||
|
@ -951,10 +959,10 @@ func TestRelease(t *testing.T) {
|
|||
subnet = "192.168.0.0/23"
|
||||
)
|
||||
|
||||
a, err := getAllocator(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1012,6 +1020,7 @@ func TestRelease(t *testing.T) {
|
|||
t.Fatalf("Failed to obtain the same address. Expected: %s, Got: %s", ip0, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertGetAddress(t *testing.T, subnet string) {
|
||||
|
@ -1058,10 +1067,10 @@ 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)
|
||||
}
|
||||
for _, store := range []bool{false, true} {
|
||||
a, err := getAllocator(store)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1079,6 +1088,7 @@ func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP str
|
|||
if !lastIP.Equal(nw.IP) {
|
||||
t.Fatalf("Wrong last IP. Expected %s. Got: %s (err: %v, ind: %d)", lastExpectedIP, nw.IP.String(), err, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkRequest(b *testing.B, a *Allocator, subnet string) {
|
||||
|
@ -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 {
|
||||
|
|
239
libnetwork/ipam/parallel_test.go
Normal file
239
libnetwork/ipam/parallel_test.go
Normal file
|
@ -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<<uint(32-mask) - 2
|
||||
|
||||
pid, _, _, err := a.RequestPool("giallo", network, "", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return &testContext{
|
||||
a: a,
|
||||
opts: options,
|
||||
ipList: make([]*net.IPNet, 0, totalIps),
|
||||
ipMap: make(map[string]bool),
|
||||
pid: pid,
|
||||
maxIP: totalIps,
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebug(t *testing.T) {
|
||||
tctx := newTestContext(t, 23, map[string]string{ipamapi.AllocSerialPrefix: "true"})
|
||||
tctx.a.RequestAddress(tctx.pid, nil, map[string]string{ipamapi.AllocSerialPrefix: "true"})
|
||||
tctx.a.RequestAddress(tctx.pid, nil, map[string]string{ipamapi.AllocSerialPrefix: "true"})
|
||||
}
|
||||
|
||||
func TestFullAllocateRelease(t *testing.T) {
|
||||
for _, parallelism := range []int64{2, 4, 8} {
|
||||
for _, mask := range []int{29, 25, 24, 21} {
|
||||
tctx := newTestContext(t, mask, map[string]string{ipamapi.AllocSerialPrefix: "true"})
|
||||
allocate(t, tctx, parallelism)
|
||||
release(t, tctx, all, parallelism)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOddAllocateRelease(t *testing.T) {
|
||||
for _, parallelism := range []int64{2, 4, 8} {
|
||||
for _, mask := range []int{29, 25, 24, 21} {
|
||||
tctx := newTestContext(t, mask, map[string]string{ipamapi.AllocSerialPrefix: "true"})
|
||||
allocate(t, tctx, parallelism)
|
||||
release(t, tctx, odd, parallelism)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFullAllocateSerialReleaseParallel(t *testing.T) {
|
||||
for _, parallelism := range []int64{1, 4, 8} {
|
||||
tctx := newTestContext(t, 23, map[string]string{ipamapi.AllocSerialPrefix: "true"})
|
||||
allocate(t, tctx, 1)
|
||||
release(t, tctx, all, parallelism)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOddAllocateSerialReleaseParallel(t *testing.T) {
|
||||
for _, parallelism := range []int64{1, 4, 8} {
|
||||
tctx := newTestContext(t, 23, map[string]string{ipamapi.AllocSerialPrefix: "true"})
|
||||
allocate(t, tctx, 1)
|
||||
release(t, tctx, odd, parallelism)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvenAllocateSerialReleaseParallel(t *testing.T) {
|
||||
for _, parallelism := range []int64{1, 4, 8} {
|
||||
tctx := newTestContext(t, 23, map[string]string{ipamapi.AllocSerialPrefix: "true"})
|
||||
allocate(t, tctx, 1)
|
||||
release(t, tctx, even, parallelism)
|
||||
}
|
||||
}
|
||||
|
||||
func allocate(t *testing.T, tctx *testContext, parallel int64) {
|
||||
// Allocate the whole space
|
||||
parallelExec := semaphore.NewWeighted(parallel)
|
||||
routineNum := tctx.maxIP + 10
|
||||
ch := make(chan *net.IPNet, routineNum)
|
||||
var id int
|
||||
var wg sync.WaitGroup
|
||||
// routine loop
|
||||
for {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
parallelExec.Acquire(context.Background(), 1)
|
||||
ip, _, _ := tctx.a.RequestAddress(tctx.pid, nil, tctx.opts)
|
||||
ch <- ip
|
||||
parallelExec.Release(1)
|
||||
wg.Done()
|
||||
}(id)
|
||||
id++
|
||||
if id == routineNum {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// give time to all the go routines to finish
|
||||
wg.Wait()
|
||||
|
||||
// process results
|
||||
for i := 0; i < routineNum; i++ {
|
||||
ip := <-ch
|
||||
if ip == nil {
|
||||
continue
|
||||
}
|
||||
if there, ok := tctx.ipMap[ip.String()]; ok && there {
|
||||
t.Fatalf("Got duplicate IP %s", ip.String())
|
||||
break
|
||||
}
|
||||
tctx.ipList = append(tctx.ipList, ip)
|
||||
tctx.ipMap[ip.String()] = true
|
||||
}
|
||||
|
||||
assert.Len(t, tctx.ipList, tctx.maxIP)
|
||||
if len(tctx.ipList) != tctx.maxIP {
|
||||
t.Fatal("missmatch number allocation")
|
||||
}
|
||||
}
|
||||
|
||||
func release(t *testing.T, tctx *testContext, mode releaseMode, parallel int64) {
|
||||
var startIndex, increment, stopIndex, length int
|
||||
switch mode {
|
||||
case all:
|
||||
startIndex = 0
|
||||
increment = 1
|
||||
stopIndex = tctx.maxIP - 1
|
||||
length = tctx.maxIP
|
||||
case odd, even:
|
||||
if mode == odd {
|
||||
startIndex = 1
|
||||
}
|
||||
increment = 2
|
||||
stopIndex = tctx.maxIP - 1
|
||||
length = tctx.maxIP / 2
|
||||
if tctx.maxIP%2 > 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)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue