libnet/ipamapi: add in/out structs for RequestPool
The `RequestPool` method has many args and named returns. This makes the code hard to follow at times. This commit adds one struct, `PoolRequest`, to replace these args, and one struct, `AllocatedPool`, to replace these named returns. Both structs' fields are properly documented to better define their semantics, and their relationship with address allocation. Signed-off-by: Albin Kerouanton <albinker@gmail.com>
This commit is contained in:
parent
c945239e73
commit
9c4c3d7443
13 changed files with 363 additions and 336 deletions
|
@ -884,13 +884,18 @@ func (na *cnmNetworkAllocator) allocatePools(n *api.Network) (map[string]string,
|
|||
}
|
||||
|
||||
for i, ic := range ipamConfigs {
|
||||
poolID, poolIP, meta, err := ipam.RequestPool(asName, ic.Subnet, ic.Range, dOptions, false)
|
||||
alloc, err := ipam.RequestPool(ipamapi.PoolRequest{
|
||||
AddressSpace: asName,
|
||||
Pool: ic.Subnet,
|
||||
SubPool: ic.Range,
|
||||
Options: dOptions,
|
||||
})
|
||||
if err != nil {
|
||||
// Rollback by releasing all the resources allocated so far.
|
||||
releasePools(ipam, ipamConfigs[:i], pools)
|
||||
return nil, err
|
||||
}
|
||||
pools[poolIP.String()] = poolID
|
||||
pools[alloc.Pool.String()] = alloc.PoolID
|
||||
|
||||
// The IPAM contract allows the IPAM driver to autonomously
|
||||
// provide a network gateway in response to the pool request.
|
||||
|
@ -902,7 +907,7 @@ func (na *cnmNetworkAllocator) allocatePools(n *api.Network) (map[string]string,
|
|||
gwIP *net.IPNet
|
||||
ip net.IP
|
||||
)
|
||||
if gws, ok := meta[netlabel.Gateway]; ok {
|
||||
if gws, ok := alloc.Meta[netlabel.Gateway]; ok {
|
||||
if ip, gwIP, err = net.ParseCIDR(gws); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse gateway address (%v) returned by ipam driver: %v", gws, err)
|
||||
}
|
||||
|
@ -917,7 +922,7 @@ func (na *cnmNetworkAllocator) allocatePools(n *api.Network) (map[string]string,
|
|||
defer delete(dOptions, ipamapi.RequestAddressType)
|
||||
|
||||
if ic.Gateway != "" || gwIP == nil {
|
||||
gwIP, _, err = ipam.RequestAddress(poolID, net.ParseIP(ic.Gateway), dOptions)
|
||||
gwIP, _, err = ipam.RequestAddress(alloc.PoolID, net.ParseIP(ic.Gateway), dOptions)
|
||||
if err != nil {
|
||||
// Rollback by releasing all the resources allocated so far.
|
||||
releasePools(ipam, ipamConfigs[:i], pools)
|
||||
|
@ -926,7 +931,7 @@ func (na *cnmNetworkAllocator) allocatePools(n *api.Network) (map[string]string,
|
|||
}
|
||||
|
||||
if ic.Subnet == "" {
|
||||
ic.Subnet = poolIP.String()
|
||||
ic.Subnet = alloc.Pool.String()
|
||||
}
|
||||
|
||||
if ic.Gateway == "" {
|
||||
|
|
|
@ -3,9 +3,10 @@ package cnmallocator
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/libnetwork/types"
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
"github.com/moby/swarmkit/v2/api"
|
||||
"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
|
||||
"gotest.tools/v3/assert"
|
||||
|
@ -728,11 +729,14 @@ func (a *mockIpam) GetDefaultAddressSpaces() (string, string, error) {
|
|||
return "defaultAS", "defaultAS", nil
|
||||
}
|
||||
|
||||
func (a *mockIpam) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
|
||||
a.actualIpamOptions = options
|
||||
func (a *mockIpam) RequestPool(req ipamapi.PoolRequest) (ipamapi.AllocatedPool, error) {
|
||||
a.actualIpamOptions = req.Options
|
||||
|
||||
poolCidr, _ := types.ParseCIDR(pool)
|
||||
return fmt.Sprintf("%s/%s", "defaultAS", pool), poolCidr, nil, nil
|
||||
poolCidr := netip.MustParsePrefix(req.Pool)
|
||||
return ipamapi.AllocatedPool{
|
||||
PoolID: fmt.Sprintf("defaultAS/%s", req.Pool),
|
||||
Pool: poolCidr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *mockIpam) ReleasePool(poolID string) error {
|
||||
|
|
|
@ -91,41 +91,35 @@ func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
|
|||
// If requestedPool is the empty string then the default predefined pool for addressSpace will be used, otherwise pool must be a valid IP address and length in CIDR notation.
|
||||
// If requestedSubPool is not empty, it must be a valid IP address and length in CIDR notation which is a sub-range of requestedPool.
|
||||
// requestedSubPool must be empty if requestedPool is empty.
|
||||
func (a *Allocator) RequestPool(addressSpace, requestedPool, requestedSubPool string, _ map[string]string, v6 bool) (poolID string, pool *net.IPNet, meta map[string]string, err error) {
|
||||
log.G(context.TODO()).Debugf("RequestPool(%s, %s, %s, _, %t)", addressSpace, requestedPool, requestedSubPool, v6)
|
||||
func (a *Allocator) RequestPool(req ipamapi.PoolRequest) (ipamapi.AllocatedPool, error) {
|
||||
log.G(context.TODO()).Debugf("RequestPool: %+v", req)
|
||||
|
||||
parseErr := func(err error) error {
|
||||
return types.InternalErrorf("failed to parse pool request for address space %q pool %q subpool %q: %v", addressSpace, requestedPool, requestedSubPool, err)
|
||||
if req.AddressSpace == "" {
|
||||
return ipamapi.AllocatedPool{}, types.InternalErrorf("invalid pool request: empty address space")
|
||||
}
|
||||
|
||||
if addressSpace == "" {
|
||||
return "", nil, nil, parseErr(ipamapi.ErrInvalidAddressSpace)
|
||||
}
|
||||
aSpace, err := a.getAddrSpace(addressSpace, v6)
|
||||
aSpace, err := a.getAddrSpace(req.AddressSpace, req.V6)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
return ipamapi.AllocatedPool{}, types.InternalErrorf("invalid pool request: invalid address space")
|
||||
}
|
||||
if requestedPool == "" && requestedSubPool != "" {
|
||||
return "", nil, nil, parseErr(ipamapi.ErrInvalidSubPool)
|
||||
if req.Pool == "" && req.SubPool != "" {
|
||||
return ipamapi.AllocatedPool{}, types.InternalErrorf("invalid pool request: %v", ipamapi.ErrInvalidSubPool)
|
||||
}
|
||||
|
||||
k := PoolID{AddressSpace: addressSpace}
|
||||
if requestedPool == "" {
|
||||
k.Subnet, err = aSpace.allocatePredefinedPool(v6)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
k := PoolID{AddressSpace: req.AddressSpace}
|
||||
if req.Pool == "" {
|
||||
if k.Subnet, err = aSpace.allocatePredefinedPool(req.V6); err != nil {
|
||||
return ipamapi.AllocatedPool{}, err
|
||||
}
|
||||
return k.String(), netiputil.ToIPNet(k.Subnet), nil, nil
|
||||
return ipamapi.AllocatedPool{PoolID: k.String(), Pool: k.Subnet}, nil
|
||||
}
|
||||
|
||||
if k.Subnet, err = netip.ParsePrefix(requestedPool); err != nil {
|
||||
return "", nil, nil, parseErr(ipamapi.ErrInvalidPool)
|
||||
if k.Subnet, err = netip.ParsePrefix(req.Pool); err != nil {
|
||||
return ipamapi.AllocatedPool{}, types.InternalErrorf("invalid pool request: %v", err)
|
||||
}
|
||||
|
||||
if requestedSubPool != "" {
|
||||
k.ChildSubnet, err = netip.ParsePrefix(requestedSubPool)
|
||||
if err != nil {
|
||||
return "", nil, nil, parseErr(ipamapi.ErrInvalidSubPool)
|
||||
if req.SubPool != "" {
|
||||
if k.ChildSubnet, err = netip.ParsePrefix(req.SubPool); err != nil {
|
||||
return ipamapi.AllocatedPool{}, types.InternalErrorf("invalid pool request: %v", ipamapi.ErrInvalidSubPool)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,10 +134,10 @@ func (a *Allocator) RequestPool(addressSpace, requestedPool, requestedSubPool st
|
|||
|
||||
err = aSpace.allocateSubnet(k.Subnet, k.ChildSubnet)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
return ipamapi.AllocatedPool{}, types.ForbiddenErrorf("invalid pool request: %v", err)
|
||||
}
|
||||
|
||||
return k.String(), netiputil.ToIPNet(k.Subnet), nil, nil
|
||||
return ipamapi.AllocatedPool{PoolID: k.String(), Pool: k.Subnet}, nil
|
||||
}
|
||||
|
||||
// ReleasePool releases the address pool identified by the passed id
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/libnetwork/bitmap"
|
||||
"github.com/docker/docker/libnetwork/internal/netiputil"
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/docker/libnetwork/ipamutils"
|
||||
"github.com/docker/docker/libnetwork/types"
|
||||
|
@ -58,55 +59,55 @@ func TestAddSubnets(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
|
||||
alloc1, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8"})
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected failure in adding subnet")
|
||||
}
|
||||
|
||||
pid1, _, _, err := a.RequestPool(globalAddressSpace, "10.0.0.0/8", "", nil, false)
|
||||
alloc2, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: globalAddressSpace, Pool: "10.0.0.0/8"})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure in adding overlapping subnets to different address spaces: %v", err)
|
||||
}
|
||||
|
||||
if pid0 == pid1 {
|
||||
if alloc1.PoolID == alloc2.PoolID {
|
||||
t.Fatal("returned same pool id for same subnets in different namespaces")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(globalAddressSpace, "10.0.0.0/8", "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: globalAddressSpace, Pool: "10.0.0.0/8"})
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure requesting existing subnet")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(globalAddressSpace, "10.128.0.0/9", "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: globalAddressSpace, Pool: "10.128.0.0/9"})
|
||||
if err == nil {
|
||||
t.Fatal("Expected failure on adding overlapping base subnet")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(globalAddressSpace, "10.0.0.0/8", "10.128.0.0/9", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: globalAddressSpace, Pool: "10.0.0.0/8", SubPool: "10.128.0.0/9"})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure on adding sub pool: %v", err)
|
||||
}
|
||||
_, _, _, err = a.RequestPool(globalAddressSpace, "10.0.0.0/8", "10.128.0.0/9", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: globalAddressSpace, Pool: "10.0.0.0/8", SubPool: "10.128.0.0/9"})
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure on adding overlapping sub pool")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, "10.20.2.0/24", "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.20.2.0/24"})
|
||||
if err == nil {
|
||||
t.Fatal("Failed to detect overlapping subnets")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, "10.128.0.0/9", "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.128.0.0/9"})
|
||||
if err == nil {
|
||||
t.Fatal("Failed to detect overlapping subnets")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3:4:5:6::/112", "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "1003:1:2:3:4:5:6::/112"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add v6 subnet: %s", err.Error())
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3::/64", "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "1003:1:2:3::/64"})
|
||||
if err == nil {
|
||||
t.Fatal("Failed to detect overlapping v6 subnet")
|
||||
}
|
||||
|
@ -118,13 +119,13 @@ func TestDoublePoolRelease(t *testing.T) {
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(t, err)
|
||||
|
||||
pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
|
||||
alloc1, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8"})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = a.ReleasePool(pid0)
|
||||
err = a.ReleasePool(alloc1.PoolID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = a.ReleasePool(pid0)
|
||||
err = a.ReleasePool(alloc1.PoolID)
|
||||
assert.Check(t, is.ErrorContains(err, ""))
|
||||
}
|
||||
|
||||
|
@ -137,11 +138,11 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
|
||||
alloc1, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8"})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure in adding pool: %v", err)
|
||||
}
|
||||
k0, err := PoolIDFromString(pid0)
|
||||
k0, err := PoolIDFromString(alloc1.PoolID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -155,17 +156,17 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
|
||||
}
|
||||
|
||||
pid1, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
|
||||
alloc2, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8", SubPool: "10.0.0.0/16"})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure in adding sub pool: %v", err)
|
||||
}
|
||||
k1, err := PoolIDFromString(pid1)
|
||||
k1, err := PoolIDFromString(alloc2.PoolID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if pid0 == pid1 {
|
||||
t.Fatalf("Incorrect poolIDs returned %s, %s", pid0, pid1)
|
||||
if alloc1.PoolID == alloc2.PoolID {
|
||||
t.Fatalf("Incorrect poolIDs returned %s, %s", alloc1.PoolID, alloc2.PoolID)
|
||||
}
|
||||
|
||||
aSpace, err = a.getAddrSpace(localAddressSpace, false)
|
||||
|
@ -177,7 +178,7 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
t.Errorf("Unexpected autoRelease value for %s: %v", k1, got)
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8", SubPool: "10.0.0.0/16"})
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure in adding sub pool: %v", err)
|
||||
}
|
||||
|
@ -191,7 +192,7 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
|
||||
}
|
||||
|
||||
if err := a.ReleasePool(pid1); err != nil {
|
||||
if err := a.ReleasePool(alloc2.PoolID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -203,7 +204,7 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
if got := aSpace.subnets[k0.Subnet].autoRelease; got != false {
|
||||
t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
|
||||
}
|
||||
if err := a.ReleasePool(pid0); err != nil {
|
||||
if err := a.ReleasePool(alloc1.PoolID); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
|
@ -211,12 +212,12 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
t.Error("Pool should have been deleted when released")
|
||||
}
|
||||
|
||||
pid00, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
|
||||
alloc10, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8"})
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected failure in adding pool: %v", err)
|
||||
}
|
||||
if pid00 != pid0 {
|
||||
t.Errorf("main pool should still exist. Got poolID %q, want %q", pid00, pid0)
|
||||
if alloc10.PoolID != alloc1.PoolID {
|
||||
t.Errorf("main pool should still exist. Got poolID %q, want %q", alloc10.PoolID, alloc1.PoolID)
|
||||
}
|
||||
|
||||
aSpace, err = a.getAddrSpace(localAddressSpace, false)
|
||||
|
@ -228,7 +229,7 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
|
||||
}
|
||||
|
||||
if err := a.ReleasePool(pid00); err != nil {
|
||||
if err := a.ReleasePool(alloc10.PoolID); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
|
@ -241,7 +242,7 @@ func TestAddReleasePoolID(t *testing.T) {
|
|||
t.Errorf("Base pool %s is still present: %v", k0, bp)
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8"})
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected failure in adding pool: %v", err)
|
||||
}
|
||||
|
@ -260,25 +261,25 @@ func TestPredefinedPool(t *testing.T) {
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(t, err)
|
||||
|
||||
pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
|
||||
alloc1, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pid2, nw2, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
|
||||
alloc2, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if types.CompareIPNet(nw, nw2) {
|
||||
t.Fatalf("Unexpected default network returned: %s = %s", nw2, nw)
|
||||
if alloc1.Pool == alloc2.Pool {
|
||||
t.Fatalf("Unexpected default network returned: %s = %s", alloc2.Pool, alloc1.Pool)
|
||||
}
|
||||
|
||||
if err := a.ReleasePool(pid); err != nil {
|
||||
if err := a.ReleasePool(alloc1.PoolID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := a.ReleasePool(pid2); err != nil {
|
||||
if err := a.ReleasePool(alloc2.PoolID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -287,32 +288,29 @@ func TestRemoveSubnet(t *testing.T) {
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(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", true},
|
||||
{globalAddressSpace, "172.17.0.0/16", false},
|
||||
{globalAddressSpace, "10.0.0.0/8", false},
|
||||
{globalAddressSpace, "2001:db8:1:2:3:4:5::/112", true},
|
||||
{globalAddressSpace, "2001:db8:1:2:3:4:ffff::/112", true},
|
||||
reqs := []ipamapi.PoolRequest{
|
||||
{AddressSpace: localAddressSpace, Pool: "192.168.0.0/16"},
|
||||
{AddressSpace: localAddressSpace, Pool: "172.17.0.0/16"},
|
||||
{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8"},
|
||||
{AddressSpace: localAddressSpace, Pool: "2001:db8:1:2:3:4:ffff::/112", V6: true},
|
||||
{AddressSpace: globalAddressSpace, Pool: "172.17.0.0/16"},
|
||||
{AddressSpace: globalAddressSpace, Pool: "10.0.0.0/8"},
|
||||
{AddressSpace: globalAddressSpace, Pool: "2001:db8:1:2:3:4:5::/112", V6: true},
|
||||
{AddressSpace: globalAddressSpace, Pool: "2001:db8:1:2:3:4:ffff::/112", V6: true},
|
||||
}
|
||||
allocs := make([]ipamapi.AllocatedPool, 0, len(reqs))
|
||||
|
||||
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 {
|
||||
for _, req := range reqs {
|
||||
alloc, err := a.RequestPool(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to apply input. Can't proceed: %s", err.Error())
|
||||
}
|
||||
allocs = append(allocs, alloc)
|
||||
}
|
||||
|
||||
for ind, id := range poolIDs {
|
||||
if err := a.ReleasePool(id); err != nil {
|
||||
t.Fatalf("Failed to release poolID %s (%d)", id, ind)
|
||||
for idx, alloc := range allocs {
|
||||
if err := a.ReleasePool(alloc.PoolID); err != nil {
|
||||
t.Fatalf("Failed to release poolID %s (%d)", alloc.PoolID, idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -321,18 +319,18 @@ func TestGetSameAddress(t *testing.T) {
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(t, err)
|
||||
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, "192.168.100.0/24", "", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "192.168.100.0/24"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ip := net.ParseIP("192.168.100.250")
|
||||
_, _, err = a.RequestAddress(pid, ip, nil)
|
||||
_, _, err = a.RequestAddress(alloc.PoolID, ip, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, _, err = a.RequestAddress(pid, ip, nil)
|
||||
_, _, err = a.RequestAddress(alloc.PoolID, ip, nil)
|
||||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -343,15 +341,14 @@ func TestPoolAllocationReuse(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
|
||||
// First get all pools until they are exhausted to
|
||||
pList := []string{}
|
||||
pool, _, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
|
||||
allocs := []ipamapi.AllocatedPool{}
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace})
|
||||
for err == nil {
|
||||
pList = append(pList, pool)
|
||||
pool, _, _, err = a.RequestPool(localAddressSpace, "", "", nil, false)
|
||||
allocs = append(allocs, alloc)
|
||||
alloc, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace})
|
||||
}
|
||||
nPools := len(pList)
|
||||
for _, pool := range pList {
|
||||
if err := a.ReleasePool(pool); err != nil {
|
||||
for _, alloc := range allocs {
|
||||
if err := a.ReleasePool(alloc.PoolID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -360,16 +357,16 @@ func TestPoolAllocationReuse(t *testing.T) {
|
|||
// Verify that we don't see any repeat networks even though
|
||||
// we have freed them.
|
||||
seen := map[string]bool{}
|
||||
for i := 0; i < nPools; i++ {
|
||||
pool, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
|
||||
for i := 0; i < len(allocs); i++ {
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := seen[nw.String()]; ok {
|
||||
t.Fatalf("Network %s was reused before exhausing the pool list", nw.String())
|
||||
if _, ok := seen[alloc.Pool.String()]; ok {
|
||||
t.Fatalf("Network %s was reused before exhausing the pool list", alloc.Pool.String())
|
||||
}
|
||||
seen[nw.String()] = true
|
||||
if err := a.ReleasePool(pool); err != nil {
|
||||
seen[alloc.Pool.String()] = true
|
||||
if err := a.ReleasePool(alloc.PoolID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -380,12 +377,12 @@ func TestGetAddressSubPoolEqualPool(t *testing.T) {
|
|||
assert.NilError(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)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "172.18.0.0/16", SubPool: "172.18.0.0/16"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, _, err = a.RequestAddress(pid, nil, nil)
|
||||
_, _, err = a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -395,7 +392,7 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(t, err)
|
||||
|
||||
poolID, _, _, err := a.RequestPool(localAddressSpace, "172.28.0.0/16", "172.28.30.0/24", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "172.28.0.0/16", SubPool: "172.28.30.0/24"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -404,7 +401,7 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
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 {
|
||||
if c, _, err = a.RequestAddress(alloc.PoolID, nil, nil); err == nil {
|
||||
ip = c
|
||||
}
|
||||
}
|
||||
|
@ -415,28 +412,28 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
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 {
|
||||
if err = a.ReleaseAddress(alloc.PoolID, rp.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil {
|
||||
if ip, _, err = a.RequestAddress(alloc.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(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8", SubPool: "10.0.0.0/16"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
poolID, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/16", "10.0.0.0/24", nil, false)
|
||||
alloc, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/16", SubPool: "10.0.0.0/24"})
|
||||
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 {
|
||||
if c, _, err = a.RequestAddress(alloc.PoolID, nil, nil); err == nil {
|
||||
ip = c
|
||||
}
|
||||
}
|
||||
|
@ -447,10 +444,10 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
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 {
|
||||
if err = a.ReleaseAddress(alloc.PoolID, rp.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil {
|
||||
if ip, _, err = a.RequestAddress(alloc.PoolID, nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(rp, ip) {
|
||||
|
@ -462,10 +459,10 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
dueExp, _ := types.ParseCIDR("10.2.2.2/16")
|
||||
treExp, _ := types.ParseCIDR("10.2.2.1/16")
|
||||
|
||||
if poolID, _, _, err = a.RequestPool(localAddressSpace, "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
|
||||
if alloc, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.2.0.0/16", SubPool: "10.2.2.0/24"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tre, _, err := a.RequestAddress(poolID, treExp.IP, nil)
|
||||
tre, _, err := a.RequestAddress(alloc.PoolID, treExp.IP, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -473,7 +470,7 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
t.Fatalf("Unexpected address: want %v, got %v", treExp, tre)
|
||||
}
|
||||
|
||||
uno, _, err := a.RequestAddress(poolID, nil, nil)
|
||||
uno, _, err := a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -481,7 +478,7 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
t.Fatalf("Unexpected address: %v", uno)
|
||||
}
|
||||
|
||||
due, _, err := a.RequestAddress(poolID, nil, nil)
|
||||
due, _, err := a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -489,10 +486,10 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
t.Fatalf("Unexpected address: %v", due)
|
||||
}
|
||||
|
||||
if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
|
||||
if err = a.ReleaseAddress(alloc.PoolID, uno.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
uno, _, err = a.RequestAddress(poolID, nil, nil)
|
||||
uno, _, err = a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -500,10 +497,10 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
t.Fatalf("Unexpected address: %v", uno)
|
||||
}
|
||||
|
||||
if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
|
||||
if err = a.ReleaseAddress(alloc.PoolID, tre.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tre, _, err = a.RequestAddress(poolID, nil, nil)
|
||||
tre, _, err = a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -519,7 +516,7 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(t, err)
|
||||
|
||||
poolID, _, _, err := a.RequestPool(localAddressSpace, "172.28.0.0/16", "172.28.30.0/24", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "172.28.0.0/16", SubPool: "172.28.30.0/24"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -528,7 +525,7 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
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 {
|
||||
if c, _, err = a.RequestAddress(alloc.PoolID, nil, opts); err == nil {
|
||||
ip = c
|
||||
}
|
||||
}
|
||||
|
@ -539,28 +536,28 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
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 {
|
||||
if err = a.ReleaseAddress(alloc.PoolID, rp.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
|
||||
if ip, _, err = a.RequestAddress(alloc.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(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/8", SubPool: "10.0.0.0/16"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
poolID, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/16", "10.0.0.0/24", nil, false)
|
||||
alloc, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.0.0.0/16", SubPool: "10.0.0.0/24"})
|
||||
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 {
|
||||
if c, _, err = a.RequestAddress(alloc.PoolID, nil, opts); err == nil {
|
||||
ip = c
|
||||
}
|
||||
}
|
||||
|
@ -571,10 +568,10 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
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 {
|
||||
if err = a.ReleaseAddress(alloc.PoolID, rp.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
|
||||
if ip, _, err = a.RequestAddress(alloc.PoolID, nil, opts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(rp, ip) {
|
||||
|
@ -587,10 +584,10 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
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(localAddressSpace, "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
|
||||
if alloc, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "10.2.0.0/16", SubPool: "10.2.2.0/24"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tre, _, err := a.RequestAddress(poolID, treExp.IP, opts)
|
||||
tre, _, err := a.RequestAddress(alloc.PoolID, treExp.IP, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -598,7 +595,7 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
t.Fatalf("Unexpected address: want %v, got %v", treExp, tre)
|
||||
}
|
||||
|
||||
uno, _, err := a.RequestAddress(poolID, nil, opts)
|
||||
uno, _, err := a.RequestAddress(alloc.PoolID, nil, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -606,7 +603,7 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
t.Fatalf("Unexpected address: %v", uno)
|
||||
}
|
||||
|
||||
due, _, err := a.RequestAddress(poolID, nil, opts)
|
||||
due, _, err := a.RequestAddress(alloc.PoolID, nil, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -614,10 +611,10 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
t.Fatalf("Unexpected address: %v", due)
|
||||
}
|
||||
|
||||
if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
|
||||
if err = a.ReleaseAddress(alloc.PoolID, uno.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
uno, _, err = a.RequestAddress(poolID, nil, opts)
|
||||
uno, _, err = a.RequestAddress(alloc.PoolID, nil, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -625,10 +622,10 @@ func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
t.Fatalf("Unexpected address: %v", uno)
|
||||
}
|
||||
|
||||
if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
|
||||
if err = a.ReleaseAddress(alloc.PoolID, tre.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tre, _, err = a.RequestAddress(poolID, nil, opts)
|
||||
tre, _, err = a.RequestAddress(alloc.PoolID, nil, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -659,22 +656,22 @@ func TestRequestSyntaxCheck(t *testing.T) {
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, _, _, err = a.RequestPool("", pool, "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{Pool: pool})
|
||||
if err == nil {
|
||||
t.Fatal("Failed to detect wrong request: empty address space")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool("", pool, subPool, nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{Pool: pool, SubPool: subPool})
|
||||
if err == nil {
|
||||
t.Fatal("Failed to detect wrong request: empty address space")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, "", subPool, nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, SubPool: subPool})
|
||||
if err == nil {
|
||||
t.Fatal("Failed to detect wrong request: subPool specified and no pool")
|
||||
}
|
||||
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, pool, subPool, nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: pool, SubPool: subPool})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure: %v", err)
|
||||
}
|
||||
|
@ -685,13 +682,13 @@ func TestRequestSyntaxCheck(t *testing.T) {
|
|||
}
|
||||
|
||||
ip := net.ParseIP("172.17.0.23")
|
||||
_, _, err = a.RequestAddress(pid, ip, nil)
|
||||
_, _, err = a.RequestAddress(alloc.PoolID, ip, nil)
|
||||
if err == nil {
|
||||
t.Fatal("Failed to detect wrong request: requested IP from different subnet")
|
||||
}
|
||||
|
||||
ip = net.ParseIP("192.168.0.50")
|
||||
_, _, err = a.RequestAddress(pid, ip, nil)
|
||||
_, _, err = a.RequestAddress(alloc.PoolID, ip, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure: %v", err)
|
||||
}
|
||||
|
@ -701,14 +698,14 @@ func TestRequestSyntaxCheck(t *testing.T) {
|
|||
t.Fatal("Failed to detect wrong request: no pool id specified")
|
||||
}
|
||||
|
||||
err = a.ReleaseAddress(pid, nil)
|
||||
err = a.ReleaseAddress(alloc.PoolID, nil)
|
||||
if err == nil {
|
||||
t.Fatal("Failed to detect wrong request: no pool id specified")
|
||||
}
|
||||
|
||||
err = a.ReleaseAddress(pid, ip)
|
||||
err = a.ReleaseAddress(alloc.PoolID, ip)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure: %v: %s, %s", err, pid, ip)
|
||||
t.Fatalf("Unexpected failure: %v: %s, %s", err, alloc.PoolID, ip)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -807,12 +804,12 @@ func TestOverlappingRequests(t *testing.T) {
|
|||
|
||||
// Set up some existing allocations. This should always succeed.
|
||||
for _, env := range tc.environment {
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, env, "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: env})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
// Make the test allocation.
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, tc.subnet, "", nil, false)
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: tc.subnet})
|
||||
if tc.ok {
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
|
@ -848,7 +845,7 @@ func TestUnusualSubnets(t *testing.T) {
|
|||
// IPv4 /31 blocks. See RFC 3021.
|
||||
//
|
||||
|
||||
pool, _, _, err := allocator.RequestPool(localAddressSpace, subnet, "", nil, false)
|
||||
alloc, err := allocator.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: subnet})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -856,7 +853,7 @@ func TestUnusualSubnets(t *testing.T) {
|
|||
// Outside-the-range
|
||||
|
||||
for _, outside := range outsideTheRangeAddresses {
|
||||
_, _, errx := allocator.RequestAddress(pool, net.ParseIP(outside.address), nil)
|
||||
_, _, errx := allocator.RequestAddress(alloc.PoolID, net.ParseIP(outside.address), nil)
|
||||
if errx != ipamapi.ErrIPOutOfRange {
|
||||
t.Fatalf("Address %s failed to throw expected error: %s", outside.address, errx.Error())
|
||||
}
|
||||
|
@ -865,7 +862,7 @@ func TestUnusualSubnets(t *testing.T) {
|
|||
// Should get just these two IPs followed by exhaustion on the next request
|
||||
|
||||
for _, expected := range expectedAddresses {
|
||||
got, _, errx := allocator.RequestAddress(pool, nil, nil)
|
||||
got, _, errx := allocator.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if errx != nil {
|
||||
t.Fatalf("Failed to obtain the address: %s", errx.Error())
|
||||
}
|
||||
|
@ -876,7 +873,7 @@ func TestUnusualSubnets(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
_, _, err = allocator.RequestAddress(pool, nil, nil)
|
||||
_, _, err = allocator.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != ipamapi.ErrNoAvailableIPs {
|
||||
t.Fatal("Did not get expected error when pool is exhausted.")
|
||||
}
|
||||
|
@ -888,14 +885,14 @@ func TestRelease(t *testing.T) {
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(t, err)
|
||||
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: subnet})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Allocate all addresses
|
||||
for err != ipamapi.ErrNoAvailableIPs {
|
||||
_, _, err = a.RequestAddress(pid, nil, nil)
|
||||
_, _, err = a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
}
|
||||
|
||||
toRelease := []struct {
|
||||
|
@ -928,13 +925,13 @@ func TestRelease(t *testing.T) {
|
|||
// One by one, release 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)
|
||||
a.ReleaseAddress(alloc.PoolID, ip0)
|
||||
bm := a.local4.subnets[netip.MustParsePrefix(subnet)].addrs
|
||||
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)
|
||||
nw, _, err := a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to obtain the address: %s", err.Error())
|
||||
}
|
||||
|
@ -988,7 +985,7 @@ func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP str
|
|||
a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
|
||||
assert.NilError(t, err)
|
||||
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: subnet})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -996,7 +993,7 @@ func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP str
|
|||
i := 0
|
||||
start := time.Now()
|
||||
for ; i < numReq; i++ {
|
||||
nw, _, err = a.RequestAddress(pid, nil, nil)
|
||||
nw, _, err = a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1011,9 +1008,9 @@ func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP str
|
|||
}
|
||||
|
||||
func benchmarkRequest(b *testing.B, a *Allocator, subnet string) {
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: subnet})
|
||||
for err != ipamapi.ErrNoAvailableIPs {
|
||||
_, _, err = a.RequestAddress(pid, nil, nil)
|
||||
_, _, err = a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1046,7 +1043,7 @@ func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, s
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, pool, subPool, nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: pool, SubPool: subPool})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1055,7 +1052,7 @@ func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, s
|
|||
indices := make(map[int]*net.IPNet, num)
|
||||
allocated := make(map[string]bool, num)
|
||||
for i := 0; i < num; i++ {
|
||||
ip, _, err := a.RequestAddress(pid, nil, nil)
|
||||
ip, _, err := a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1078,7 +1075,7 @@ func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, s
|
|||
for i := 0; i < num/2; i++ {
|
||||
idx := pattern[i]
|
||||
ip := indices[idx]
|
||||
err := a.ReleaseAddress(pid, ip.IP)
|
||||
err := a.ReleaseAddress(alloc.PoolID, ip.IP)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure on deallocation of %s: %v.\nSeed: %d.", ip, err, seed)
|
||||
}
|
||||
|
@ -1088,7 +1085,7 @@ func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, s
|
|||
|
||||
// Request a quarter of addresses
|
||||
for i := 0; i < num/2; i++ {
|
||||
ip, _, err := a.RequestAddress(pid, nil, nil)
|
||||
ip, _, err := a.RequestAddress(alloc.PoolID, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1148,7 +1145,8 @@ func runParallelTests(t *testing.T, instance int) {
|
|||
defer done.Done()
|
||||
}
|
||||
|
||||
_, pools[instance], _, err = allocator.RequestPool(localAddressSpace, "", "", nil, false)
|
||||
alloc, err := allocator.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace})
|
||||
pools[instance] = netiputil.ToIPNet(alloc.Pool)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1183,7 +1181,7 @@ func TestRequestReleaseAddressDuplicate(t *testing.T) {
|
|||
}
|
||||
var l sync.Mutex
|
||||
|
||||
poolID, _, _, err := a.RequestPool(localAddressSpace, "198.168.0.0/23", "", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: "198.168.0.0/23"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1203,7 +1201,7 @@ outer:
|
|||
break outer
|
||||
default:
|
||||
}
|
||||
if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
|
||||
if c, _, err = a.RequestAddress(alloc.PoolID, nil, opts); err == nil {
|
||||
break
|
||||
}
|
||||
// No addresses available. Spin until one is.
|
||||
|
@ -1236,7 +1234,7 @@ outer:
|
|||
l.Lock()
|
||||
ips = append(ips, IP{ip, -1})
|
||||
l.Unlock()
|
||||
return a.ReleaseAddress(poolID, ip.IP)
|
||||
return a.ReleaseAddress(alloc.PoolID, ip.IP)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func newTestContext(t *testing.T, mask int, options map[string]string) *testCont
|
|||
// total ips 2^(32-mask) - 2 (network and broadcast)
|
||||
totalIps := 1<<uint(32-mask) - 2
|
||||
|
||||
pid, _, _, err := a.RequestPool(localAddressSpace, network, "", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace, Pool: network})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func newTestContext(t *testing.T, mask int, options map[string]string) *testCont
|
|||
opts: options,
|
||||
ipList: make([]*net.IPNet, 0, totalIps),
|
||||
ipMap: make(map[string]bool),
|
||||
pid: pid,
|
||||
pid: alloc.PoolID,
|
||||
maxIP: totalIps,
|
||||
}
|
||||
}
|
||||
|
@ -93,21 +93,21 @@ func TestRequestPoolParallel(t *testing.T) {
|
|||
|
||||
for i := 0; i < 120; i++ {
|
||||
group.Go(func() error {
|
||||
name, _, _, err := a.RequestPool("GlobalDefault", "", "", nil, false)
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: "GlobalDefault"})
|
||||
if err != nil {
|
||||
t.Log(err) // log so we can see the error in real time rather than at the end when we actually call "Wait".
|
||||
return fmt.Errorf("request error %v", err)
|
||||
}
|
||||
idx := atomic.AddInt32(&operationIndex, 1)
|
||||
ch <- &op{idx, true, name}
|
||||
ch <- &op{idx, true, alloc.PoolID}
|
||||
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
||||
idx = atomic.AddInt32(&operationIndex, 1)
|
||||
err = a.ReleasePool(name)
|
||||
err = a.ReleasePool(alloc.PoolID)
|
||||
if err != nil {
|
||||
t.Log(err) // log so we can see the error in real time rather than at the end when we actually call "Wait".
|
||||
return fmt.Errorf("release error %v", err)
|
||||
}
|
||||
ch <- &op{idx, false, name}
|
||||
ch <- &op{idx, false, alloc.PoolID}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package ipamapi
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/docker/docker/libnetwork/types"
|
||||
)
|
||||
|
@ -45,13 +46,9 @@ var (
|
|||
type Ipam interface {
|
||||
// GetDefaultAddressSpaces returns the default local and global address spaces for this ipam
|
||||
GetDefaultAddressSpaces() (string, string, error)
|
||||
// RequestPool returns an address pool along with its unique id. Address space is a mandatory field
|
||||
// which denotes a set of non-overlapping pools. requestedPool describes the pool of addresses in CIDR notation.
|
||||
// requestedSubPool indicates a smaller range of addresses from the pool, for now it is specified in CIDR notation.
|
||||
// Both requestedPool and requestedSubPool are non-mandatory fields. When they are not specified, Ipam driver may choose to
|
||||
// return a self chosen pool for this request. In such case the v6 flag needs to be set appropriately so
|
||||
// that the driver would return the expected ip version pool.
|
||||
RequestPool(addressSpace, requestedPool, requestedSubPool string, options map[string]string, v6 bool) (poolID string, pool *net.IPNet, meta map[string]string, err error)
|
||||
// RequestPool allocate an address pool either statically or dynamically
|
||||
// based on req.
|
||||
RequestPool(req PoolRequest) (AllocatedPool, error)
|
||||
// ReleasePool releases the address pool identified by the passed id
|
||||
ReleasePool(poolID string) error
|
||||
// RequestAddress request an address from the specified pool ID. Input options or required IP can be passed.
|
||||
|
@ -63,6 +60,41 @@ type Ipam interface {
|
|||
IsBuiltIn() bool
|
||||
}
|
||||
|
||||
type PoolRequest struct {
|
||||
// AddressSpace is a mandatory field which denotes which block of pools
|
||||
// should be used to make the allocation. This value is opaque, and only
|
||||
// the IPAM driver can interpret it. Each driver might support a different
|
||||
// set of AddressSpace.
|
||||
AddressSpace string
|
||||
// Pool is a prefix in CIDR notation. It's non-mandatory. When specified
|
||||
// the Pool will be statically allocated. The Pool is used for dynamic
|
||||
// address allocation -- except when SubPool is specified.
|
||||
Pool string
|
||||
// SubPool is a subnet from Pool, in CIDR notation too. It's non-mandatory.
|
||||
// When specified, it represents the subnet where addresses will be
|
||||
// dynamically allocated. It can't be specified if Pool isn't specified.
|
||||
SubPool string
|
||||
// Options is a map of opaque k/v passed to the driver. It's non-mandatory.
|
||||
// Drivers are free to ignore it.
|
||||
Options map[string]string
|
||||
// V6 indicates which address family should be used to dynamically allocate
|
||||
// a prefix (ie. when Pool isn't specified).
|
||||
V6 bool
|
||||
}
|
||||
|
||||
type AllocatedPool struct {
|
||||
// PoolID represents the ID of the allocated pool. Its value is opaque and
|
||||
// shouldn't be interpreted by anything but the IPAM driver that generated
|
||||
// it.
|
||||
PoolID string
|
||||
// Pool is the allocated prefix.
|
||||
Pool netip.Prefix
|
||||
// Meta represents a list of extra IP addresses automatically reserved
|
||||
// during the pool allocation. These are generally keyed by well-known
|
||||
// strings defined in the netlabel package.
|
||||
Meta map[string]string
|
||||
}
|
||||
|
||||
// Capability represents the requirements and capabilities of the IPAM driver
|
||||
type Capability struct {
|
||||
// Whether on address request, libnetwork must
|
||||
|
|
|
@ -4,6 +4,7 @@ package null
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/docker/libnetwork/types"
|
||||
|
@ -15,7 +16,7 @@ const (
|
|||
defaultPoolID = defaultAddressSpace + "/" + defaultPoolCIDR
|
||||
)
|
||||
|
||||
var defaultPool, _ = types.ParseCIDR(defaultPoolCIDR)
|
||||
var defaultPool = netip.MustParsePrefix(defaultPoolCIDR)
|
||||
|
||||
type allocator struct{}
|
||||
|
||||
|
@ -23,20 +24,23 @@ func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
|
|||
return defaultAddressSpace, defaultAddressSpace, nil
|
||||
}
|
||||
|
||||
func (a *allocator) RequestPool(addressSpace, requestedPool, requestedSubPool string, _ map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
|
||||
if addressSpace != defaultAddressSpace {
|
||||
return "", nil, nil, types.InvalidParameterErrorf("unknown address space: %s", addressSpace)
|
||||
func (a *allocator) RequestPool(req ipamapi.PoolRequest) (ipamapi.AllocatedPool, error) {
|
||||
if req.AddressSpace != defaultAddressSpace {
|
||||
return ipamapi.AllocatedPool{}, types.InvalidParameterErrorf("unknown address space: %s", req.AddressSpace)
|
||||
}
|
||||
if requestedPool != "" {
|
||||
return "", nil, nil, types.InvalidParameterErrorf("null ipam driver does not handle specific address pool requests")
|
||||
if req.Pool != "" {
|
||||
return ipamapi.AllocatedPool{}, types.InvalidParameterErrorf("null ipam driver does not handle specific address pool requests")
|
||||
}
|
||||
if requestedSubPool != "" {
|
||||
return "", nil, nil, types.InvalidParameterErrorf("null ipam driver does not handle specific address subpool requests")
|
||||
if req.SubPool != "" {
|
||||
return ipamapi.AllocatedPool{}, types.InvalidParameterErrorf("null ipam driver does not handle specific address subpool requests")
|
||||
}
|
||||
if v6 {
|
||||
return "", nil, nil, types.InvalidParameterErrorf("null ipam driver does not handle IPv6 address pool requests")
|
||||
if req.V6 {
|
||||
return ipamapi.AllocatedPool{}, types.InvalidParameterErrorf("null ipam driver does not handle IPv6 address pool requests")
|
||||
}
|
||||
return defaultPoolID, defaultPool, nil, nil
|
||||
return ipamapi.AllocatedPool{
|
||||
PoolID: defaultPoolID,
|
||||
Pool: defaultPool,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *allocator) ReleasePool(poolID string) error {
|
||||
|
|
|
@ -3,42 +3,30 @@ package null
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/libnetwork/types"
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestPoolRequest(t *testing.T) {
|
||||
a := allocator{}
|
||||
|
||||
pid, pool, _, err := a.RequestPool(defaultAddressSpace, "", "", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(defaultPool, pool) {
|
||||
t.Fatalf("Unexpected pool returned. Expected %v. Got: %v", defaultPool, pool)
|
||||
}
|
||||
if pid != defaultPoolID {
|
||||
t.Fatalf("Unexpected pool id returned. Expected: %s. Got: %s", defaultPoolID, pid)
|
||||
}
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: defaultAddressSpace})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(alloc.PoolID, defaultPoolID))
|
||||
assert.Check(t, is.Equal(alloc.Pool, defaultPool))
|
||||
|
||||
_, _, _, err = a.RequestPool("default", "", "", nil, false)
|
||||
if err == nil {
|
||||
t.Fatal("Unexpected success")
|
||||
}
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: "default"})
|
||||
assert.ErrorContains(t, err, "unknown address space: default")
|
||||
|
||||
_, _, _, err = a.RequestPool(defaultAddressSpace, "192.168.0.0/16", "", nil, false)
|
||||
if err == nil {
|
||||
t.Fatal("Unexpected success")
|
||||
}
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: defaultAddressSpace, Pool: "192.168.0.0/16"})
|
||||
assert.ErrorContains(t, err, "null ipam driver does not handle specific address pool requests")
|
||||
|
||||
_, _, _, err = a.RequestPool(defaultAddressSpace, "", "192.168.0.0/24", nil, false)
|
||||
if err == nil {
|
||||
t.Fatal("Unexpected success")
|
||||
}
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: defaultAddressSpace, SubPool: "192.168.0.0/24"})
|
||||
assert.ErrorContains(t, err, "null ipam driver does not handle specific address subpool requests")
|
||||
|
||||
_, _, _, err = a.RequestPool(defaultAddressSpace, "", "", nil, true)
|
||||
if err == nil {
|
||||
t.Fatal("Unexpected success")
|
||||
}
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{AddressSpace: defaultAddressSpace, V6: true})
|
||||
assert.ErrorContains(t, err, "null ipam driver does not handle IPv6 address pool requests")
|
||||
}
|
||||
|
||||
func TestOtherRequests(t *testing.T) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
|
@ -116,14 +117,25 @@ func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
|
|||
}
|
||||
|
||||
// RequestPool requests an address pool in the specified address space
|
||||
func (a *allocator) RequestPool(addressSpace, requestedPool, requestedSubPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
|
||||
req := &api.RequestPoolRequest{AddressSpace: addressSpace, Pool: requestedPool, SubPool: requestedSubPool, Options: options, V6: v6}
|
||||
res := &api.RequestPoolResponse{}
|
||||
if err := a.call("RequestPool", req, res); err != nil {
|
||||
return "", nil, nil, err
|
||||
func (a *allocator) RequestPool(req ipamapi.PoolRequest) (ipamapi.AllocatedPool, error) {
|
||||
remoteReq := &api.RequestPoolRequest{
|
||||
AddressSpace: req.AddressSpace,
|
||||
Pool: req.Pool,
|
||||
SubPool: req.SubPool,
|
||||
Options: req.Options,
|
||||
V6: req.V6,
|
||||
}
|
||||
retPool, err := types.ParseCIDR(res.Pool)
|
||||
return res.PoolID, retPool, res.Data, err
|
||||
res := &api.RequestPoolResponse{}
|
||||
if err := a.call("RequestPool", remoteReq, res); err != nil {
|
||||
return ipamapi.AllocatedPool{}, err
|
||||
}
|
||||
|
||||
retPool, err := netip.ParsePrefix(res.Pool)
|
||||
return ipamapi.AllocatedPool{
|
||||
PoolID: res.PoolID,
|
||||
Pool: retPool,
|
||||
Meta: res.Data,
|
||||
}, err
|
||||
}
|
||||
|
||||
// ReleasePool removes an address pool from the specified address space
|
||||
|
|
|
@ -14,6 +14,8 @@ import (
|
|||
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func decodeToMap(r *http.Request) (res map[string]interface{}, err error) {
|
||||
|
@ -248,72 +250,51 @@ func TestRemoteDriver(t *testing.T) {
|
|||
d := newAllocator(plugin, client)
|
||||
|
||||
l, g, err := d.(*allocator).GetDefaultAddressSpaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if l != "white" || g != "blue" {
|
||||
t.Fatalf("Unexpected default local/global address spaces: %s, %s", l, g)
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(l, "white"))
|
||||
assert.Check(t, is.Equal(g, "blue"))
|
||||
|
||||
// Request any pool
|
||||
poolID, pool, _, err := d.RequestPool("white", "", "", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if poolID != "white/172.18.0.0/16" {
|
||||
t.Fatalf("Unexpected pool id: %s", poolID)
|
||||
}
|
||||
if pool == nil || pool.String() != "172.18.0.0/16" {
|
||||
t.Fatalf("Unexpected pool: %s", pool)
|
||||
}
|
||||
alloc, err := d.RequestPool(ipamapi.PoolRequest{
|
||||
AddressSpace: "white",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(alloc.PoolID, "white/172.18.0.0/16"))
|
||||
assert.Check(t, is.Equal(alloc.Pool.String(), "172.18.0.0/16"))
|
||||
|
||||
// Request specific pool
|
||||
poolID2, pool2, ops, err := d.RequestPool("white", "172.20.0.0/16", "", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if poolID2 != "white/172.20.0.0/16" {
|
||||
t.Fatalf("Unexpected pool id: %s", poolID2)
|
||||
}
|
||||
if pool2 == nil || pool2.String() != "172.20.0.0/16" {
|
||||
t.Fatalf("Unexpected pool: %s", pool2)
|
||||
}
|
||||
if dns, ok := ops["DNS"]; !ok || dns != "8.8.8.8" {
|
||||
t.Fatal("Missing options")
|
||||
}
|
||||
alloc, err = d.RequestPool(ipamapi.PoolRequest{
|
||||
AddressSpace: "white",
|
||||
Pool: "172.20.0.0/16",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(alloc.PoolID, "white/172.20.0.0/16"))
|
||||
assert.Check(t, is.Equal(alloc.Pool.String(), "172.20.0.0/16"))
|
||||
assert.Check(t, is.Equal(alloc.Meta["DNS"], "8.8.8.8"))
|
||||
|
||||
// Request specific pool and subpool
|
||||
poolID3, pool3, _, err := d.RequestPool("white", "172.20.0.0/16", "172.20.3.0/24" /*nil*/, map[string]string{"culo": "yes"}, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if poolID3 != "white/172.20.0.0/16/172.20.3.0/24" {
|
||||
t.Fatalf("Unexpected pool id: %s", poolID3)
|
||||
}
|
||||
if pool3 == nil || pool3.String() != "172.20.0.0/16" {
|
||||
t.Fatalf("Unexpected pool: %s", pool3)
|
||||
}
|
||||
alloc, err = d.RequestPool(ipamapi.PoolRequest{
|
||||
AddressSpace: "white",
|
||||
Pool: "172.20.0.0/16",
|
||||
SubPool: "172.20.3.0/24",
|
||||
Options: map[string]string{"culo": "yes"},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(alloc.PoolID, "white/172.20.0.0/16/172.20.3.0/24"))
|
||||
assert.Check(t, is.Equal(alloc.Pool.String(), "172.20.0.0/16"))
|
||||
|
||||
// Request any address
|
||||
addr, _, err := d.RequestAddress(poolID2, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if addr == nil || addr.String() != "172.20.0.34/16" {
|
||||
t.Fatalf("Unexpected address: %s", addr)
|
||||
}
|
||||
addr, _, err := d.RequestAddress("white/172.20.0.0/16", nil, nil)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(addr.String(), "172.20.0.34/16"))
|
||||
|
||||
// Request specific address
|
||||
addr2, _, err := d.RequestAddress(poolID2, net.ParseIP("172.20.1.45"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if addr2 == nil || addr2.String() != "172.20.1.45/16" {
|
||||
t.Fatalf("Unexpected address: %s", addr2)
|
||||
}
|
||||
addr2, _, err := d.RequestAddress("white/172.20.0.0/16", net.ParseIP("172.20.1.45"), nil)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(addr2.String(), "172.20.1.45/16"))
|
||||
|
||||
// Release address
|
||||
err = d.ReleaseAddress(poolID, net.ParseIP("172.18.1.45"))
|
||||
err = d.ReleaseAddress("white/172.20.0.0/16", net.ParseIP("172.18.1.45"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@ package windowsipam
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
|
@ -17,7 +19,7 @@ const (
|
|||
// DefaultIPAM defines the default ipam-driver for local-scoped windows networks
|
||||
const DefaultIPAM = "windows"
|
||||
|
||||
var defaultPool, _ = types.ParseCIDR("0.0.0.0/0")
|
||||
var defaultPool = netip.MustParsePrefix("0.0.0.0/0")
|
||||
|
||||
type allocator struct{}
|
||||
|
||||
|
@ -32,25 +34,24 @@ func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
|
|||
|
||||
// RequestPool returns an address pool along with its unique id. This is a null ipam driver. It allocates the
|
||||
// subnet user asked and does not validate anything. Doesn't support subpool allocation
|
||||
func (a *allocator) RequestPool(addressSpace, requestedPool, requestedSubPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
|
||||
log.G(context.TODO()).Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, requestedPool, requestedSubPool, options, v6)
|
||||
if requestedSubPool != "" || v6 {
|
||||
return "", nil, nil, types.InternalErrorf("This request is not supported by null ipam driver")
|
||||
func (a *allocator) RequestPool(req ipamapi.PoolRequest) (ipamapi.AllocatedPool, error) {
|
||||
log.G(context.TODO()).Debugf("RequestPool: %+v", req)
|
||||
if req.SubPool != "" || req.V6 {
|
||||
return ipamapi.AllocatedPool{}, types.InternalErrorf("this request is not supported by the 'windows' ipam driver")
|
||||
}
|
||||
|
||||
var ipNet *net.IPNet
|
||||
var err error
|
||||
|
||||
if requestedPool != "" {
|
||||
_, ipNet, err = net.ParseCIDR(requestedPool)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
pool := defaultPool
|
||||
if req.Pool != "" {
|
||||
var err error
|
||||
if pool, err = netip.ParsePrefix(req.Pool); err != nil {
|
||||
return ipamapi.AllocatedPool{}, fmt.Errorf("invalid IPAM request: %w", err)
|
||||
}
|
||||
} else {
|
||||
ipNet = defaultPool
|
||||
}
|
||||
|
||||
return ipNet.String(), ipNet, nil, nil
|
||||
return ipamapi.AllocatedPool{
|
||||
PoolID: pool.String(),
|
||||
Pool: pool,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ReleasePool releases the address pool - always succeeds
|
||||
|
|
|
@ -7,41 +7,42 @@ import (
|
|||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/docker/libnetwork/netlabel"
|
||||
"github.com/docker/docker/libnetwork/types"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestWindowsIPAM(t *testing.T) {
|
||||
a := &allocator{}
|
||||
|
||||
alloc, err := a.RequestPool(ipamapi.PoolRequest{AddressSpace: localAddressSpace})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(alloc.PoolID, defaultPool.String()))
|
||||
assert.Check(t, is.Equal(alloc.Pool, defaultPool))
|
||||
|
||||
alloc, err = a.RequestPool(ipamapi.PoolRequest{
|
||||
AddressSpace: localAddressSpace,
|
||||
Pool: "192.168.0.0/16",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(alloc.PoolID, "192.168.0.0/16"))
|
||||
assert.Check(t, is.Equal(alloc.Pool.String(), "192.168.0.0/16"))
|
||||
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{
|
||||
AddressSpace: localAddressSpace,
|
||||
Pool: "192.168.0.0/16",
|
||||
SubPool: "192.168.0.0/16",
|
||||
})
|
||||
assert.ErrorContains(t, err, "this request is not supported by the 'windows' ipam driver")
|
||||
|
||||
_, err = a.RequestPool(ipamapi.PoolRequest{
|
||||
AddressSpace: localAddressSpace,
|
||||
V6: true,
|
||||
})
|
||||
assert.ErrorContains(t, err, "this request is not supported by the 'windows' ipam driver")
|
||||
|
||||
requestPool, _ := types.ParseCIDR("192.168.0.0/16")
|
||||
requestAddress := net.ParseIP("192.168.1.1")
|
||||
|
||||
pid, pool, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(defaultPool, pool) ||
|
||||
pid != pool.String() {
|
||||
t.Fatalf("Unexpected data returned. Expected %v : %s. Got: %v : %s", defaultPool, pid, pool, pool.String())
|
||||
}
|
||||
|
||||
pid, pool, _, err = a.RequestPool(localAddressSpace, requestPool.String(), "", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(requestPool, pool) ||
|
||||
pid != requestPool.String() {
|
||||
t.Fatalf("Unexpected data returned. Expected %v : %s. Got: %v : %s", requestPool, requestPool.String(), pool, pool.String())
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, requestPool.String(), requestPool.String(), nil, false)
|
||||
if err == nil {
|
||||
t.Fatal("Unexpected success for subpool request")
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool(localAddressSpace, requestPool.String(), "", nil, true)
|
||||
if err == nil {
|
||||
t.Fatal("Unexpected success for v6 request")
|
||||
}
|
||||
|
||||
err = a.ReleasePool(requestPool.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/docker/docker/libnetwork/datastore"
|
||||
"github.com/docker/docker/libnetwork/driverapi"
|
||||
"github.com/docker/docker/libnetwork/etchosts"
|
||||
"github.com/docker/docker/libnetwork/internal/netiputil"
|
||||
"github.com/docker/docker/libnetwork/internal/setmatrix"
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/docker/libnetwork/netlabel"
|
||||
|
@ -1508,7 +1509,7 @@ func (n *Network) ipamAllocate() error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, requestedPool, requestedSubPool string, options map[string]string, v6 bool) (poolID string, pool *net.IPNet, meta map[string]string, err error) {
|
||||
func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, requestedPool, requestedSubPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
|
||||
var tmpPoolLeases []string
|
||||
defer func() {
|
||||
// Prevent repeated lock/unlock in the loop.
|
||||
|
@ -1516,13 +1517,19 @@ func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, requestedPo
|
|||
// Release all pools we held on to.
|
||||
for _, pID := range tmpPoolLeases {
|
||||
if err := ipam.ReleasePool(pID); err != nil {
|
||||
log.G(context.TODO()).Warnf("Failed to release overlapping pool %s while returning from pool request helper for network %s", pool, nwName)
|
||||
log.G(context.TODO()).Warnf("Failed to release overlapping pool while returning from pool request helper for network %s", nwName)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
poolID, pool, meta, err = ipam.RequestPool(addressSpace, requestedPool, requestedSubPool, options, v6)
|
||||
alloc, err := ipam.RequestPool(ipamapi.PoolRequest{
|
||||
AddressSpace: addressSpace,
|
||||
Pool: requestedPool,
|
||||
SubPool: requestedSubPool,
|
||||
Options: options,
|
||||
V6: v6,
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
@ -1544,13 +1551,13 @@ func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, requestedPo
|
|||
// instead would likely have avoided that as well, so we can only guess.
|
||||
//
|
||||
// [1]: https://github.com/moby/libnetwork/commit/5ca79d6b87873264516323a7b76f0af7d0298492#diff-bdcd879439d041827d334846f9aba01de6e3683ed8fdd01e63917dae6df23846
|
||||
if requestedPool != "" || n.Scope() == scope.Global || pool.String() == "0.0.0.0/0" {
|
||||
return poolID, pool, meta, nil
|
||||
if requestedPool != "" || n.Scope() == scope.Global || alloc.Pool.String() == "0.0.0.0/0" {
|
||||
return alloc.PoolID, netiputil.ToIPNet(alloc.Pool), alloc.Meta, nil
|
||||
}
|
||||
|
||||
// Check for overlap and if none found, we have found the right pool.
|
||||
if _, err := netutils.FindAvailableNetwork([]*net.IPNet{pool}); err == nil {
|
||||
return poolID, pool, meta, nil
|
||||
if _, err := netutils.FindAvailableNetwork([]*net.IPNet{netiputil.ToIPNet(alloc.Pool)}); err == nil {
|
||||
return alloc.PoolID, netiputil.ToIPNet(alloc.Pool), alloc.Meta, nil
|
||||
}
|
||||
|
||||
// Pool obtained in this iteration is overlapping. Hold onto the pool
|
||||
|
@ -1558,7 +1565,7 @@ func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, requestedPo
|
|||
// the same pool over again. But make sure we still do a deferred release
|
||||
// when we have either obtained a non-overlapping pool or ran out of
|
||||
// pre-defined pools.
|
||||
tmpPoolLeases = append(tmpPoolLeases, poolID)
|
||||
tmpPoolLeases = append(tmpPoolLeases, alloc.PoolID)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue