1114 строки
30 KiB
Go
1114 строки
30 KiB
Go
package ipam
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
|
|
"github.com/Azure/azure-container-networking/testutils"
|
|
)
|
|
|
|
func TestPool(t *testing.T) {
|
|
RegisterFailHandler(Fail)
|
|
RunSpecs(t, "Pool Suite")
|
|
}
|
|
|
|
var _ = Describe("Test Pool", func() {
|
|
Describe("Test addressPoolId", func() {
|
|
Context("Creates a new address pool ID object", func() {
|
|
It("Should create a pool ID with given parameters", func() {
|
|
asId := "eth0"
|
|
subnet := "10.0.0.0/16"
|
|
childSubnet := "10.0.1.0/8"
|
|
apId := NewAddressPoolId(asId, subnet, childSubnet)
|
|
Expect(apId.AsId).To(Equal(asId))
|
|
Expect(apId.Subnet).To(Equal(subnet))
|
|
Expect(apId.ChildSubnet).To(Equal(childSubnet))
|
|
})
|
|
})
|
|
|
|
Context("Create a new pool ID when string format is incorrect", func() {
|
|
It("Should raise an error", func() {
|
|
s := "eth0|10.0.0.0/16|10.0.1.0/8|test"
|
|
apId, err := NewAddressPoolIdFromString(s)
|
|
Expect(apId).To(BeNil())
|
|
Expect(err).To(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Context("Create a new pool ID when string only contains addressSpace Id", func() {
|
|
It("Should create a pool ID by parsing the string", func() {
|
|
s := "local"
|
|
apId, err := NewAddressPoolIdFromString(s)
|
|
Expect(apId).NotTo(BeNil())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(apId.AsId).To(Equal(s))
|
|
Expect(apId.Subnet).To(BeEmpty())
|
|
Expect(apId.ChildSubnet).To(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("Create a new pool ID when the string has addrspace and subnet", func() {
|
|
It("Should create a pool ID by parsing the string", func() {
|
|
s := "eth0|10.0.0.0/16"
|
|
apId, err := NewAddressPoolIdFromString(s)
|
|
Expect(apId).NotTo(BeNil())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(apId.AsId).To(Equal("eth0"))
|
|
Expect(apId.Subnet).To(Equal("10.0.0.0/16"))
|
|
Expect(apId.ChildSubnet).To(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("Create a new pool ID when string has addrspace, subnet and child subnet", func() {
|
|
It("Should create a pool ID by parsing the string", func() {
|
|
s := "eth0|10.0.0.0/16|10.0.1.0/8"
|
|
apId, err := NewAddressPoolIdFromString(s)
|
|
Expect(apId).NotTo(BeNil())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(apId.AsId).To(Equal("eth0"))
|
|
Expect(apId.Subnet).To(Equal("10.0.0.0/16"))
|
|
Expect(apId.ChildSubnet).To(Equal("10.0.1.0/8"))
|
|
})
|
|
})
|
|
|
|
Context("Returns the string representation of a pool ID with childSubnet", func() {
|
|
It("Should return string with asID|subnet|childsubnet", func() {
|
|
apId := &addressPoolId{
|
|
AsId: "eth0",
|
|
Subnet: "10.0.0.0/16",
|
|
ChildSubnet: "10.0.1.0/8",
|
|
}
|
|
s := apId.String()
|
|
Expect(s).To(Equal("eth0|10.0.0.0/16|10.0.1.0/8"))
|
|
})
|
|
})
|
|
|
|
Context("Returns the string representation of a pool ID without childSubnet", func() {
|
|
It("Should return a string without childSubnet", func() {
|
|
apId := &addressPoolId{
|
|
AsId: "eth0",
|
|
Subnet: "10.0.0.0/16",
|
|
}
|
|
s := apId.String()
|
|
Expect(s).To(Equal("eth0|10.0.0.0/16"))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test newAddressSpace", func() {
|
|
am := &addressManager{}
|
|
|
|
Context("When scope is LocalScope", func() {
|
|
It("Should create an addressSpace with LocalScope", func() {
|
|
asId := "local"
|
|
scope := LocalScope
|
|
as, err := am.newAddressSpace(asId, scope)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(as.Id).To(Equal(asId))
|
|
Expect(as.Scope).To(Equal(scope))
|
|
})
|
|
})
|
|
|
|
Context("When scope is GlobalScope", func() {
|
|
It("Should create an addressSpace with GlobalScope", func() {
|
|
asId := "local"
|
|
scope := GlobalScope
|
|
as, err := am.newAddressSpace(asId, scope)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(as.Id).To(Equal(asId))
|
|
Expect(as.Scope).To(Equal(scope))
|
|
})
|
|
})
|
|
|
|
Context("When scope is not GlobalScope or LocalScope", func() {
|
|
It("Should raise an error", func() {
|
|
asId := "local"
|
|
scope := 127
|
|
as, err := am.newAddressSpace(asId, scope)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(as).To(BeNil())
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test getAddressSpace and setAddressSpace", func() {
|
|
am := &addressManager{
|
|
AddrSpaces: map[string]*addressSpace{},
|
|
}
|
|
|
|
Context("When addressSpace not exists", func() {
|
|
It("Should raise an error", func() {
|
|
as, err := am.getAddressSpace("lo")
|
|
Expect(err).To(Equal(errInvalidAddressSpace))
|
|
Expect(as).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When addressSpace exists", func() {
|
|
It("Should return the addressSpace", func() {
|
|
asId := "local"
|
|
am.AddrSpaces[asId] = &addressSpace{Id: asId}
|
|
as, err := am.getAddressSpace(asId)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(as.Id).To(Equal(asId))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test setAddressSpace", func() {
|
|
am := &addressManager{
|
|
AddrSpaces: map[string]*addressSpace{},
|
|
}
|
|
am.netApi = &testutils.NetApiMock{}
|
|
asId := "local"
|
|
|
|
Context("When addressSpace not exists", func() {
|
|
It("Should be added to the am", func() {
|
|
err := am.setAddressSpace(&addressSpace{Id: asId})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(am.AddrSpaces[asId].Id).To(Equal(asId))
|
|
})
|
|
})
|
|
|
|
Context("When addressSpace already exists", func() {
|
|
It("Should be merged", func() {
|
|
err := am.setAddressSpace(&addressSpace{Id: asId})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(am.AddrSpaces[asId].Id).To(Equal(asId))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test merge", func() {
|
|
Context("When only new addressSpace contains the pool", func() {
|
|
It("The pool should be merged to the origin addressSpace", func() {
|
|
asId := "local"
|
|
epoch := 3
|
|
poolId := "10.0.0.0/16"
|
|
originAs := &addressSpace{
|
|
Id: asId,
|
|
epoch: epoch,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
newAs := &addressSpace{
|
|
Id: asId,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool := &addressPool{
|
|
Id: poolId,
|
|
as: originAs,
|
|
}
|
|
newAs.Pools[poolId] = pool
|
|
originAs.merge(newAs)
|
|
pool = originAs.Pools[poolId]
|
|
Expect(pool.as.Id).To(Equal(asId))
|
|
Expect(pool.epoch).To(Equal(4))
|
|
Expect(newAs.Pools[poolId]).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When only new addressSpace contains the addressRecord", func() {
|
|
It("The addressRecord should be merged to the origin addressSpace", func() {
|
|
asId := "local"
|
|
epoch := 3
|
|
poolId := "10.0.0.0/16"
|
|
arId := "10.0.0.1/16"
|
|
|
|
originAs := &addressSpace{
|
|
Id: asId,
|
|
epoch: epoch,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool1 := &addressPool{
|
|
Id: poolId,
|
|
as: originAs,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
originAs.Pools[poolId] = pool1
|
|
|
|
newAs := &addressSpace{
|
|
Id: asId,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool2 := &addressPool{
|
|
Id: poolId,
|
|
as: newAs,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
pool2.Addresses[arId] = &addressRecord{InUse: true}
|
|
newAs.Pools[poolId] = pool2
|
|
originAs.merge(newAs)
|
|
pool1 = originAs.Pools[poolId]
|
|
Expect(pool1.as.Id).To(Equal(asId))
|
|
ar := pool1.Addresses[arId]
|
|
Expect(ar.epoch).To(Equal(4))
|
|
Expect(ar.InUse).To(BeTrue())
|
|
Expect(newAs.Pools[poolId]).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When addressRecord is contained in both new addressSpace and origin addressSpace", func() {
|
|
It("The addressRecord of origin addressSpace should be updated", func() {
|
|
asId := "local"
|
|
epoch := 3
|
|
poolId := "10.0.0.0/16"
|
|
arId := "10.0.0.1/16"
|
|
|
|
originAs := &addressSpace{
|
|
Id: asId,
|
|
epoch: epoch,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool1 := &addressPool{
|
|
Id: poolId,
|
|
as: originAs,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
pool1.Addresses[arId] = &addressRecord{InUse: true, unhealthy: true}
|
|
originAs.Pools[poolId] = pool1
|
|
|
|
newAs := &addressSpace{
|
|
Id: asId,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool2 := &addressPool{
|
|
Id: poolId,
|
|
as: newAs,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
pool2.Addresses[arId] = &addressRecord{InUse: true}
|
|
newAs.Pools[poolId] = pool2
|
|
originAs.merge(newAs)
|
|
pool1 = originAs.Pools[poolId]
|
|
Expect(pool1.as.Id).To(Equal(asId))
|
|
ar := pool1.Addresses[arId]
|
|
Expect(ar.epoch).To(Equal(4))
|
|
Expect(ar.InUse).To(BeTrue())
|
|
Expect(ar.unhealthy).To(BeFalse())
|
|
Expect(newAs.Pools[poolId]).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When addressRecord epoch is correct and pool epoch is less", func() {
|
|
It("Should update the pool epoch", func() {
|
|
asId := "local"
|
|
epoch := 3
|
|
poolId := "10.0.0.0/16"
|
|
arId := "10.0.0.1/16"
|
|
|
|
originAs := &addressSpace{
|
|
Id: asId,
|
|
epoch: epoch,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool1 := &addressPool{
|
|
Id: poolId,
|
|
as: originAs,
|
|
epoch: 3,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
pool1.Addresses[arId] = &addressRecord{
|
|
epoch: 4,
|
|
InUse: true,
|
|
}
|
|
originAs.Pools[poolId] = pool1
|
|
newAs := &addressSpace{
|
|
Id: asId,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
originAs.merge(newAs)
|
|
pool1 = originAs.Pools[poolId]
|
|
Expect(pool1.epoch).To(Equal(4))
|
|
ar := pool1.Addresses[arId]
|
|
Expect(ar.epoch).To(Equal(4))
|
|
Expect(ar.InUse).To(BeTrue())
|
|
Expect(ar.unhealthy).To(BeFalse())
|
|
})
|
|
})
|
|
|
|
Context("When addressRecord is in use", func() {
|
|
It("The addressRecord should be set to unhealthy", func() {
|
|
asId := "local"
|
|
epoch := 3
|
|
poolId := "10.0.0.0/16"
|
|
arId := "10.0.0.1/16"
|
|
|
|
originAs := &addressSpace{
|
|
Id: asId,
|
|
epoch: epoch,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool1 := &addressPool{
|
|
Id: poolId,
|
|
as: originAs,
|
|
epoch: 3,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
pool1.Addresses[arId] = &addressRecord{
|
|
epoch: 3,
|
|
InUse: true,
|
|
}
|
|
originAs.Pools[poolId] = pool1
|
|
newAs := &addressSpace{
|
|
Id: asId,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
originAs.merge(newAs)
|
|
pool1 = originAs.Pools[poolId]
|
|
Expect(pool1.epoch).To(Equal(4))
|
|
ar := pool1.Addresses[arId]
|
|
Expect(ar.epoch).To(Equal(3))
|
|
Expect(ar.InUse).To(BeTrue())
|
|
Expect(ar.unhealthy).To(BeTrue())
|
|
})
|
|
})
|
|
|
|
Context("When addressRecord is not in use but pool is in use", func() {
|
|
It("The addressRecord should be deleted", func() {
|
|
asId := "local"
|
|
epoch := 3
|
|
poolId := "10.0.0.0/16"
|
|
arId := "10.0.0.1/16"
|
|
|
|
originAs := &addressSpace{
|
|
Id: asId,
|
|
epoch: epoch,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool := &addressPool{
|
|
Id: poolId,
|
|
as: originAs,
|
|
epoch: 3,
|
|
RefCount: 1,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
pool.Addresses[arId] = &addressRecord{
|
|
epoch: 3,
|
|
InUse: false,
|
|
}
|
|
originAs.Pools[poolId] = pool
|
|
newAs := &addressSpace{
|
|
Id: asId,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
originAs.merge(newAs)
|
|
pool = originAs.Pools[poolId]
|
|
Expect(pool.epoch).To(Equal(3))
|
|
ar := pool.Addresses[arId]
|
|
Expect(ar).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When pool is not in use", func() {
|
|
It("The pool should be deleted", func() {
|
|
asId := "local"
|
|
epoch := 3
|
|
poolId := "10.0.0.0/16"
|
|
|
|
originAs := &addressSpace{
|
|
Id: asId,
|
|
epoch: epoch,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool := &addressPool{
|
|
Id: poolId,
|
|
as: originAs,
|
|
epoch: 3,
|
|
RefCount: 0,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
originAs.Pools[poolId] = pool
|
|
newAs := &addressSpace{
|
|
Id: asId,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
originAs.merge(newAs)
|
|
pool = originAs.Pools[poolId]
|
|
Expect(pool).To(BeNil())
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test newAddressPool", func() {
|
|
Context("When pool already exists", func() {
|
|
It("Should raise an error", func() {
|
|
subnet := &net.IPNet{
|
|
IP: net.IPv4(10, 0, 0, 1),
|
|
Mask: net.IPv4Mask(255, 255, 0, 0),
|
|
}
|
|
poolId := subnet.String()
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
as.Pools[poolId] = &addressPool{Id: poolId}
|
|
pool, err := as.newAddressPool("", 0, subnet)
|
|
Expect(err).To(Equal(errAddressPoolExists))
|
|
Expect(pool.Id).To(Equal(poolId))
|
|
})
|
|
})
|
|
|
|
Context("When pool not exists", func() {
|
|
It("Should create pool successfully", func() {
|
|
subnet := &net.IPNet{
|
|
IP: net.IPv4(10, 0, 0, 1),
|
|
Mask: net.IPv4Mask(255, 255, 0, 0),
|
|
}
|
|
poolId := subnet.String()
|
|
as := &addressSpace{
|
|
Id: "local",
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool, err := as.newAddressPool("local", 1, subnet)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(pool.Id).To(Equal(poolId))
|
|
Expect(pool.as.Id).To(Equal(as.Id))
|
|
Expect(pool.IfName).To(Equal("local"))
|
|
Expect(pool.Subnet.String()).To(Equal(poolId))
|
|
Expect(pool.IsIPv6).To(BeFalse())
|
|
Expect(pool.Priority).To(Equal(1))
|
|
Expect(as.Pools[poolId]).NotTo(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When pool is ipv6", func() {
|
|
It("Should create pool successfully", func() {
|
|
subnet := &net.IPNet{
|
|
IP: net.IPv6zero,
|
|
Mask: net.IPv6zero.DefaultMask(),
|
|
}
|
|
poolId := subnet.String()
|
|
as := &addressSpace{
|
|
Id: "local",
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool, err := as.newAddressPool("local", 1, subnet)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(pool.Id).To(Equal(poolId))
|
|
Expect(pool.as.Id).To(Equal(as.Id))
|
|
Expect(pool.IfName).To(Equal("local"))
|
|
Expect(pool.Subnet.String()).To(Equal(poolId))
|
|
Expect(pool.IsIPv6).To(BeTrue())
|
|
Expect(pool.Priority).To(Equal(1))
|
|
Expect(as.Pools[poolId]).NotTo(BeNil())
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test getAddressPool", func() {
|
|
Context("When pool not find", func() {
|
|
It("Should raise an error", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
pool, _ := as.getAddressPool("10.0.0.0/16")
|
|
Expect(pool).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When pool is found", func() {
|
|
It("Should return the pool", func() {
|
|
poolId := "10.0.0.0/16"
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
as.Pools[poolId] = &addressPool{Id: poolId}
|
|
pool, err := as.getAddressPool(poolId)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(pool.Id).To(Equal(poolId))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test requestPool", func() {
|
|
Context("When poolId is explicitly specified and not found in addressSpace", func() {
|
|
It("Should raise an error", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
ap, err := as.requestPool("10.0.0.0/16", "", nil, false)
|
|
Expect(err).To(Equal(errAddressPoolNotFound))
|
|
Expect(ap).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When poolId is explicitly specified and found in addressSpace", func() {
|
|
It("Should return the pool", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
poolId := "10.0.0.0/16"
|
|
as.Pools[poolId] = &addressPool{
|
|
Id: poolId,
|
|
RefCount: 0,
|
|
}
|
|
ap, err := as.requestPool(poolId, "", nil, false)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap.Id).To(Equal(poolId))
|
|
Expect(ap.RefCount).To(Equal(1))
|
|
})
|
|
})
|
|
|
|
Context("When pool is in use and it has no ips allocated", func() {
|
|
It("Should raise an error", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
poolId := "10.0.0.0/16"
|
|
as.Pools[poolId] = &addressPool{
|
|
Id: poolId,
|
|
RefCount: 1,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.2"] = &addressRecord{
|
|
InUse: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
ap, err := as.requestPool("", "", nil, false)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap.Id).To(Equal(poolId))
|
|
Expect(ap.RefCount).To(Equal(1))
|
|
})
|
|
})
|
|
|
|
Context("When pool is in use and it has ips allocated", func() {
|
|
It("Should raise an error", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
poolId := "10.0.0.0/16"
|
|
as.Pools[poolId] = &addressPool{
|
|
Id: poolId,
|
|
RefCount: 1,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.1"] = &addressRecord{
|
|
InUse: true,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.2"] = &addressRecord{
|
|
InUse: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
ap, err := as.requestPool("", "", nil, false)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(ap).To(BeNil())
|
|
Expect(err).To(Equal(ErrNoAvailableAddressPools))
|
|
})
|
|
})
|
|
|
|
Context("When pool is in use and request same pool explicitly", func() {
|
|
It("Should raise an error", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
poolId := "10.0.0.0/16"
|
|
as.Pools[poolId] = &addressPool{
|
|
Id: poolId,
|
|
RefCount: 1,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.1"] = &addressRecord{
|
|
InUse: true,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.2"] = &addressRecord{
|
|
InUse: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
ap, err := as.requestPool(poolId, "", nil, false)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap).NotTo(BeNil())
|
|
Expect(ap.RefCount).To(Equal(1))
|
|
})
|
|
})
|
|
|
|
Context("When pool is ipv4 and ipv6 is wanted", func() {
|
|
It("Should raise an error", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
poolId := "10.0.0.0/16"
|
|
as.Pools[poolId] = &addressPool{
|
|
Id: poolId,
|
|
IsIPv6: false,
|
|
}
|
|
ap, err := as.requestPool("", "", nil, true)
|
|
Expect(err).To(Equal(ErrNoAvailableAddressPools))
|
|
Expect(ap).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When the requested interface name does not exist", func() {
|
|
It("Should raise an error", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
poolId := "10.0.0.0/16"
|
|
ifName := "local"
|
|
as.Pools[poolId] = &addressPool{
|
|
Id: poolId,
|
|
IfName: ifName,
|
|
}
|
|
options := map[string]string{}
|
|
options[OptInterfaceName] = "en0"
|
|
ap, err := as.requestPool("", "", options, false)
|
|
Expect(err).To(Equal(ErrNoAvailableAddressPools))
|
|
Expect(ap).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When addressSpace has one pool available", func() {
|
|
It("Should return the pool", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
poolId := "10.0.0.0/16"
|
|
as.Pools[poolId] = &addressPool{
|
|
Id: poolId,
|
|
}
|
|
ap, err := as.requestPool("", "", nil, false)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap.Id).To(Equal(poolId))
|
|
Expect(ap.RefCount).To(Equal(1))
|
|
})
|
|
})
|
|
|
|
Context("When addressSpace has pools with different priority", func() {
|
|
It("Should return the pool with the highest priority", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
as.Pools["10.0.0.0/16"] = &addressPool{
|
|
Id: "10.0.0.0/16",
|
|
Priority: 1,
|
|
}
|
|
as.Pools["10.1.0.0/16"] = &addressPool{
|
|
Id: "10.1.0.0/16",
|
|
Priority: 2,
|
|
}
|
|
ap, err := as.requestPool("", "", nil, false)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap.Id).To(Equal("10.1.0.0/16"))
|
|
Expect(ap.RefCount).To(Equal(1))
|
|
})
|
|
})
|
|
|
|
Context("When addressSpace has pools with different addresses", func() {
|
|
It("Should return the pool with the highest number of addresses", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
as.Pools["10.0.0.0/16"] = &addressPool{
|
|
Id: "10.0.0.0/16",
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
as.Pools["10.1.0.0/16"] = &addressPool{
|
|
Id: "10.1.0.0/16",
|
|
Addresses: map[string]*addressRecord{
|
|
"10.1.0.1/16": {},
|
|
},
|
|
}
|
|
ap, err := as.requestPool("", "", nil, false)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap.Id).To(Equal("10.1.0.0/16"))
|
|
Expect(ap.RefCount).To(Equal(1))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test releasePool", func() {
|
|
Context("When pool not found", func() {
|
|
It("Should raise an error", func() {
|
|
as := &addressSpace{
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
err := as.releasePool("10.0.0.0/16")
|
|
Expect(err).To(Equal(errAddressPoolNotFound))
|
|
})
|
|
})
|
|
|
|
Context("When pool's addresses are all not in use", func() {
|
|
It("Should release the pool ", func() {
|
|
poolId := "10.0.0.0/16"
|
|
as := &addressSpace{
|
|
epoch: 2,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
as.Pools[poolId] = &addressPool{
|
|
epoch: 1,
|
|
RefCount: 1,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
|
|
as.Pools[poolId].Addresses["10.0.0.1"] = &addressRecord{
|
|
InUse: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.2"] = &addressRecord{
|
|
InUse: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.3"] = &addressRecord{
|
|
InUse: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
|
|
err := as.releasePool("10.0.0.0/16")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(as.Pools[poolId].isInUse()).To(BeFalse())
|
|
})
|
|
})
|
|
|
|
Context("When the pool has in use addresses", func() {
|
|
It("Should not delete the pool", func() {
|
|
poolId := "10.0.0.0/16"
|
|
as := &addressSpace{
|
|
epoch: 1,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
as.Pools[poolId] = &addressPool{
|
|
epoch: 1,
|
|
RefCount: 1,
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
|
|
as.Pools[poolId].Addresses["10.0.0.1"] = &addressRecord{
|
|
InUse: true,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.2"] = &addressRecord{
|
|
InUse: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
as.Pools[poolId].Addresses["10.0.0.3"] = &addressRecord{
|
|
InUse: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
|
|
err := as.releasePool("10.0.0.0/16")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(as.Pools[poolId]).NotTo(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When pool is still in use", func() {
|
|
It("Should not delete the pool", func() {
|
|
poolId := "10.0.0.0/16"
|
|
as := &addressSpace{
|
|
epoch: 2,
|
|
Pools: map[string]*addressPool{},
|
|
}
|
|
as.Pools[poolId] = &addressPool{
|
|
epoch: 1,
|
|
RefCount: 2,
|
|
}
|
|
err := as.releasePool("10.0.0.0/16")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(as.Pools[poolId]).NotTo(BeNil())
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test getInfo", func() {
|
|
Context("When addressRecord is not in use", func() {
|
|
It("Should add the available", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
ap.Addresses["10.0.0.1/16"] = &addressRecord{InUse: false}
|
|
ap.Addresses["10.0.0.2/16"] = &addressRecord{InUse: true}
|
|
ap.Addresses["10.0.0.3/16"] = &addressRecord{InUse: false}
|
|
apInfo := ap.getInfo()
|
|
Expect(apInfo.Available).To(Equal(2))
|
|
})
|
|
})
|
|
|
|
Context("When addressRecords are unhealthy", func() {
|
|
It("Should append the unhealthyAddrs", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
ap.Addresses["10.0.0.1/16"] = &addressRecord{
|
|
unhealthy: true,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
ap.Addresses["10.0.0.2/16"] = &addressRecord{
|
|
unhealthy: false,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
ap.Addresses["10.0.0.3/16"] = &addressRecord{
|
|
unhealthy: true,
|
|
Addr: net.IPv4zero,
|
|
}
|
|
apInfo := ap.getInfo()
|
|
Expect(len(apInfo.UnhealthyAddrs)).To(Equal(2))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test isInUse", func() {
|
|
Context("When RefCount is set to some value", func() {
|
|
It("Should return true when RefCount > 0", func() {
|
|
ap := &addressPool{RefCount: 0}
|
|
Expect(ap.isInUse()).To(BeFalse())
|
|
ap.RefCount = 1
|
|
Expect(ap.isInUse()).To(BeTrue())
|
|
ap.RefCount = 10000
|
|
Expect(ap.isInUse()).To(BeTrue())
|
|
ap.RefCount = -1
|
|
Expect(ap.isInUse()).To(BeFalse())
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test requestAddress", func() {
|
|
Context("When addressRecord not found", func() {
|
|
It("Should raise errAddressNotFound", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
addr, err := ap.requestAddress("10.0.0.1/16", nil)
|
|
Expect(err).To(Equal(errAddressNotFound))
|
|
Expect(addr).To(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("When addressRecord is in use and id match", func() {
|
|
It("Should return the same addressRecord", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
addrsByID: map[string]*addressRecord{},
|
|
}
|
|
arId := "10.0.0.1/16"
|
|
ap.Addresses[arId] = &addressRecord{
|
|
ID: arId,
|
|
InUse: true,
|
|
}
|
|
options := map[string]string{}
|
|
options[OptAddressID] = arId
|
|
addr, err := ap.requestAddress("10.0.0.1/16", options)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(addr).NotTo(BeEmpty())
|
|
Expect(ap.addrsByID[arId].ID).To(Equal(arId))
|
|
})
|
|
})
|
|
|
|
Context("When id is not found and a address is available", func() {
|
|
It("Should return a new address", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
addrsByID: map[string]*addressRecord{},
|
|
Subnet: subnet1,
|
|
}
|
|
arId := uuid.New().String()
|
|
|
|
ap.Addresses["0"] = &addressRecord{
|
|
ID: "",
|
|
Addr: addr11,
|
|
InUse: false,
|
|
}
|
|
|
|
ap.Addresses["1"] = &addressRecord{
|
|
ID: "",
|
|
Addr: addr12,
|
|
InUse: false,
|
|
}
|
|
|
|
ap.Addresses["3"] = &addressRecord{
|
|
ID: "",
|
|
Addr: addr13,
|
|
InUse: false,
|
|
}
|
|
|
|
options := map[string]string{}
|
|
options[OptAddressID] = arId
|
|
|
|
addr, err := ap.requestAddress("", options)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(addr).NotTo(BeEmpty())
|
|
Expect(ap.addrsByID[arId].ID).To(Equal(arId))
|
|
})
|
|
})
|
|
|
|
Context("When addressRecord is in use and id is empty", func() {
|
|
It("Should raise errAddressInUse", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
ap.Addresses["10.0.0.1/16"] = &addressRecord{InUse: true}
|
|
addr, err := ap.requestAddress("10.0.0.1/16", nil)
|
|
Expect(err).To(Equal(errAddressInUse))
|
|
Expect(addr).To(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("When addressRecord is in use and id is not equal to the addressRecord's id", func() {
|
|
It("Should raise errAddressInUse", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
arId := "10.0.0.1/16"
|
|
ap.Addresses[arId] = &addressRecord{
|
|
ID: arId,
|
|
InUse: true,
|
|
}
|
|
options := map[string]string{}
|
|
options[OptAddressID] = "10.0.0.2/16"
|
|
addr, err := ap.requestAddress("10.0.0.1/16", options)
|
|
Expect(err).To(Equal(errAddressInUse))
|
|
Expect(addr).To(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("When OptAddressType is OptAddressTypeGateway", func() {
|
|
It("Should raise errAddressInUse", func() {
|
|
ap := &addressPool{
|
|
Gateway: net.IPv4(10, 0, 0, 1),
|
|
}
|
|
options := map[string]string{}
|
|
options[OptAddressType] = OptAddressTypeGateway
|
|
addr, err := ap.requestAddress("", options)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(addr).NotTo(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("When id match", func() {
|
|
It("Should return the addressRecord with given id", func() {
|
|
ap := &addressPool{
|
|
addrsByID: map[string]*addressRecord{},
|
|
}
|
|
arId := "10.0.0.1/16"
|
|
ap.addrsByID[arId] = &addressRecord{
|
|
ID: arId,
|
|
InUse: true,
|
|
}
|
|
options := map[string]string{}
|
|
options[OptAddressID] = arId
|
|
addr, err := ap.requestAddress("", options)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(addr).NotTo(BeEmpty())
|
|
Expect(ap.addrsByID[arId].ID).To(Equal(arId))
|
|
})
|
|
})
|
|
|
|
Context("When no available address", func() {
|
|
It("Should raise errNoAvailableAddresses", func() {
|
|
ap := &addressPool{
|
|
addrsByID: map[string]*addressRecord{},
|
|
}
|
|
// ar.InUse is true
|
|
ap.addrsByID["10.0.0.1/16"] = &addressRecord{
|
|
ID: "",
|
|
InUse: true,
|
|
}
|
|
// ad.Id != ""
|
|
ap.addrsByID["10.0.0.2/16"] = &addressRecord{
|
|
ID: "10.0.0.2/16",
|
|
InUse: false,
|
|
}
|
|
addr, err := ap.requestAddress("", nil)
|
|
Expect(err).To(Equal(errNoAvailableAddresses))
|
|
Expect(addr).To(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("Check if the InUse is set to true", func() {
|
|
It("InUse should be set to true", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
arId := "10.0.0.1/16"
|
|
ap.Addresses[arId] = &addressRecord{
|
|
InUse: false,
|
|
}
|
|
addr, err := ap.requestAddress("", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(addr).NotTo(BeEmpty())
|
|
Expect(ap.Addresses[arId].InUse).To(BeTrue())
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Test releaseAddress", func() {
|
|
Context("When address is equal to the gateway", func() {
|
|
It("Should return nil", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
Gateway: net.IPv4zero,
|
|
}
|
|
ar := ap.Gateway.String()
|
|
err := ap.releaseAddress(ar, nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Context("When address is equal to the gateway", func() {
|
|
It("Should return nil", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
Gateway: net.IPv4zero,
|
|
}
|
|
ar := ap.Gateway.String()
|
|
err := ap.releaseAddress(ar, nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Context("When addr is not in use", func() {
|
|
It("Should return nil", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
}
|
|
ap.Addresses["10.0.0.1/16"] = &addressRecord{InUse: false}
|
|
err := ap.releaseAddress("10.0.0.1/16", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap.Addresses["10.0.0.1/16"]).NotTo(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When delete by id", func() {
|
|
It("Should return nil", func() {
|
|
ap := &addressPool{
|
|
addrsByID: map[string]*addressRecord{},
|
|
Addresses: map[string]*addressRecord{},
|
|
as: &addressSpace{epoch: 1},
|
|
}
|
|
arId := "10.0.0.1/16"
|
|
ap.addrsByID[arId] = &addressRecord{
|
|
ID: arId,
|
|
Addr: net.IPv4zero,
|
|
InUse: true,
|
|
epoch: 1,
|
|
}
|
|
options := map[string]string{}
|
|
options[OptAddressID] = arId
|
|
err := ap.releaseAddress("", options)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap.addrsByID[arId]).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("When delete by address", func() {
|
|
It("Should return nil", func() {
|
|
ap := &addressPool{
|
|
Addresses: map[string]*addressRecord{},
|
|
as: &addressSpace{epoch: 2},
|
|
}
|
|
ap.Addresses["10.0.0.1/16"] = &addressRecord{
|
|
InUse: true,
|
|
epoch: 1,
|
|
}
|
|
err := ap.releaseAddress("10.0.0.1/16", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(ap.Addresses["10.0.0.1/16"]).To(BeNil())
|
|
})
|
|
})
|
|
})
|
|
})
|