Adjust ipam errors
- Remove from contract predefined errors which are no longer valid (ex. ErrInvalidIpamService, ErrInvalidIpamConfigService) - Do not use network driver error for ipam load failure in controller.go - Bitseq to expose two well-known errors (no more bit available, bit is already set) - Default ipam to report proper well-known error on RequestAddress() based on bitseq returned error - Default ipam errors to comply with types error interface Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
6f3c0e34f3
commit
dc4285b9a4
7 changed files with 60 additions and 55 deletions
|
@ -24,7 +24,10 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
errNoBitAvailable = fmt.Errorf("no bit available")
|
||||
// ErrNoBitAvailable is returned when no more bits are available to set
|
||||
ErrNoBitAvailable = fmt.Errorf("no bit available")
|
||||
// ErrBitAllocated is returned when the specific bit requested is already set
|
||||
ErrBitAllocated = fmt.Errorf("requested bit is already allocated")
|
||||
)
|
||||
|
||||
// Handle contains the sequece representing the bitmask and its identifier
|
||||
|
@ -94,7 +97,7 @@ func (s *sequence) toString() string {
|
|||
// GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence
|
||||
func (s *sequence) getAvailableBit(from uint64) (uint64, uint64, error) {
|
||||
if s.block == blockMAX || s.count == 0 {
|
||||
return invalidPos, invalidPos, errNoBitAvailable
|
||||
return invalidPos, invalidPos, ErrNoBitAvailable
|
||||
}
|
||||
bits := from
|
||||
bitSel := blockFirstBit >> from
|
||||
|
@ -197,7 +200,7 @@ func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) {
|
|||
return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end)
|
||||
}
|
||||
if h.Unselected() == 0 {
|
||||
return invalidPos, errNoBitAvailable
|
||||
return invalidPos, ErrNoBitAvailable
|
||||
}
|
||||
return h.set(0, start, end, true, false)
|
||||
}
|
||||
|
@ -205,7 +208,7 @@ func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) {
|
|||
// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
|
||||
func (h *Handle) SetAny() (uint64, error) {
|
||||
if h.Unselected() == 0 {
|
||||
return invalidPos, errNoBitAvailable
|
||||
return invalidPos, ErrNoBitAvailable
|
||||
}
|
||||
return h.set(0, 0, h.bits-1, true, false)
|
||||
}
|
||||
|
@ -269,7 +272,7 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64
|
|||
bytePos, bitPos, err = getFirstAvailable(h.head, start)
|
||||
ret = posToOrdinal(bytePos, bitPos)
|
||||
if end < ret {
|
||||
err = errNoBitAvailable
|
||||
err = ErrNoBitAvailable
|
||||
}
|
||||
} else {
|
||||
bytePos, bitPos, err = checkIfAvailable(h.head, ordinal)
|
||||
|
@ -449,7 +452,7 @@ func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
|
|||
byteOffset += current.count * blockBytes
|
||||
current = current.next
|
||||
}
|
||||
return invalidPos, invalidPos, errNoBitAvailable
|
||||
return invalidPos, invalidPos, ErrNoBitAvailable
|
||||
}
|
||||
|
||||
// checkIfAvailable checks if the bit correspondent to the specified ordinal is unset
|
||||
|
@ -467,7 +470,7 @@ func checkIfAvailable(head *sequence, ordinal uint64) (uint64, uint64, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return invalidPos, invalidPos, fmt.Errorf("requested bit is not available")
|
||||
return invalidPos, invalidPos, ErrBitAllocated
|
||||
}
|
||||
|
||||
// Given the byte position and the sequences list head, return the pointer to the
|
||||
|
|
|
@ -657,7 +657,7 @@ func TestSetInRange(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
|
||||
}
|
||||
if err != errNoBitAvailable {
|
||||
if err != ErrNoBitAvailable {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
|
@ -673,7 +673,7 @@ func TestSetInRange(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
|
||||
}
|
||||
if err != errNoBitAvailable {
|
||||
if err != ErrNoBitAvailable {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
|
@ -687,7 +687,7 @@ func TestSetInRange(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
|
||||
}
|
||||
if err != errNoBitAvailable {
|
||||
if err != ErrNoBitAvailable {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -315,17 +315,17 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error
|
|||
_, ok := c.ipamDrivers[name]
|
||||
c.Unlock()
|
||||
if ok {
|
||||
return driverapi.ErrActiveRegistration(name)
|
||||
return types.ForbiddenErrorf("ipam driver %q already registered", name)
|
||||
}
|
||||
locAS, glbAS, err := driver.GetDefaultAddressSpaces()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ipam driver %s failed to return default address spaces: %v", name, err)
|
||||
return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err)
|
||||
}
|
||||
c.Lock()
|
||||
c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS}
|
||||
c.Unlock()
|
||||
|
||||
log.Debugf("Registering ipam provider: %s", name)
|
||||
log.Debugf("Registering ipam driver: %q", name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -667,7 +667,7 @@ func (c *controller) loadIpamDriver(name string) (*ipamData, error) {
|
|||
id, ok := c.ipamDrivers[name]
|
||||
c.Unlock()
|
||||
if !ok {
|
||||
return nil, ErrInvalidNetworkDriver(name)
|
||||
return nil, types.BadRequestErrorf("invalid ipam driver: %q", name)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
|
|
@ -76,8 +76,7 @@ func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
|
|||
func (a *Allocator) refresh(as string) error {
|
||||
aSpace, err := a.getAddressSpaceFromStore(as)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting pools config from store during init: %v",
|
||||
err)
|
||||
return types.InternalErrorf("error getting pools config from store: %v", err)
|
||||
}
|
||||
|
||||
if aSpace == nil {
|
||||
|
@ -239,7 +238,7 @@ func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
|
|||
|
||||
store := a.getStore(key.AddressSpace)
|
||||
if store == nil {
|
||||
return fmt.Errorf("could not find store for address space %s while inserting bit mask", key.AddressSpace)
|
||||
return types.InternalErrorf("could not find store for address space %s while inserting bit mask", key.AddressSpace)
|
||||
}
|
||||
|
||||
ipVer := getAddressVersion(pool.IP)
|
||||
|
@ -279,7 +278,7 @@ func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle,
|
|||
if !ok {
|
||||
log.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String())
|
||||
if err := a.insertBitMask(k, n); err != nil {
|
||||
return nil, fmt.Errorf("could not find bitmask in datastore for %s", k.String())
|
||||
return nil, types.InternalErrorf("could not find bitmask in datastore for %s", k.String())
|
||||
}
|
||||
a.Lock()
|
||||
bm = a.addresses[k]
|
||||
|
@ -306,7 +305,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error)
|
|||
}
|
||||
|
||||
if as != localAddressSpace && as != globalAddressSpace {
|
||||
return nil, fmt.Errorf("no default pool available for non-default address spaces")
|
||||
return nil, types.NotImplementedErrorf("no default pool availbale for non-default addresss spaces")
|
||||
}
|
||||
|
||||
aSpace, err := a.getAddrSpace(as)
|
||||
|
@ -378,7 +377,7 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s
|
|||
|
||||
bm, err := a.retrieveBitmask(k, c.Pool)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
|
||||
return nil, nil, types.InternalErrorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
|
||||
k.String(), prefAddress, poolID, err)
|
||||
}
|
||||
ip, err := a.getAddress(p.Pool, bm, prefAddress, p.Range)
|
||||
|
@ -410,12 +409,12 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
|
|||
p, ok := aSpace.subnets[k]
|
||||
if !ok {
|
||||
aSpace.Unlock()
|
||||
return ipamapi.ErrBadPool
|
||||
return types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
|
||||
}
|
||||
|
||||
if address == nil {
|
||||
aSpace.Unlock()
|
||||
return ipamapi.ErrInvalidRequest
|
||||
return types.BadRequestErrorf("invalid address: nil")
|
||||
}
|
||||
|
||||
if !p.Pool.Contains(address) {
|
||||
|
@ -434,12 +433,12 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
|
|||
|
||||
h, err := types.GetHostPartIP(address, mask)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to release address %s: %v", address.String(), err)
|
||||
return types.InternalErrorf("failed to release address %s: %v", address.String(), err)
|
||||
}
|
||||
|
||||
bm, err := a.retrieveBitmask(k, c.Pool)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
|
||||
return types.InternalErrorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
|
||||
k.String(), address, poolID, err)
|
||||
}
|
||||
|
||||
|
@ -463,19 +462,25 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
|
|||
} else if prefAddress != nil {
|
||||
hostPart, e := types.GetHostPartIP(prefAddress, base.Mask)
|
||||
if e != nil {
|
||||
return nil, fmt.Errorf("failed to allocate preferred address %s: %v", prefAddress.String(), e)
|
||||
return nil, types.InternalErrorf("failed to allocate preferred address %s: %v", prefAddress.String(), e)
|
||||
}
|
||||
ordinal = ipToUint64(types.GetMinimalIP(hostPart))
|
||||
err = bitmask.Set(ordinal)
|
||||
} else {
|
||||
ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, ipamapi.ErrNoAvailableIPs
|
||||
}
|
||||
|
||||
// Convert IP ordinal for this subnet into IP address
|
||||
return generateAddress(ordinal, base), nil
|
||||
switch err {
|
||||
case nil:
|
||||
// Convert IP ordinal for this subnet into IP address
|
||||
return generateAddress(ordinal, base), nil
|
||||
case bitseq.ErrBitAllocated:
|
||||
return nil, ipamapi.ErrIPAlreadyAllocated
|
||||
case bitseq.ErrNoBitAvailable:
|
||||
return nil, ipamapi.ErrNoAvailableIPs
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// DumpDatabase dumps the internal info
|
||||
|
|
|
@ -2,7 +2,6 @@ package ipam
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
|
@ -84,7 +83,7 @@ func (a *Allocator) getStore(as string) datastore.DataStore {
|
|||
func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
|
||||
store := a.getStore(as)
|
||||
if store == nil {
|
||||
return nil, fmt.Errorf("store for address space %s not found", as)
|
||||
return nil, types.InternalErrorf("store for address space %s not found", as)
|
||||
}
|
||||
|
||||
pc := &addrSpace{id: dsConfigKey + "/" + as, ds: store, alloc: a}
|
||||
|
@ -93,7 +92,7 @@ func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not get pools config from store: %v", err)
|
||||
return nil, types.InternalErrorf("could not get pools config from store: %v", err)
|
||||
}
|
||||
|
||||
return pc, nil
|
||||
|
@ -102,7 +101,7 @@ func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
|
|||
func (a *Allocator) writeToStore(aSpace *addrSpace) error {
|
||||
store := aSpace.store()
|
||||
if store == nil {
|
||||
return fmt.Errorf("invalid store while trying to write %s address space", aSpace.DataScope())
|
||||
return types.InternalErrorf("invalid store while trying to write %s address space", aSpace.DataScope())
|
||||
}
|
||||
|
||||
err := store.PutObjectAtomic(aSpace)
|
||||
|
@ -116,7 +115,7 @@ func (a *Allocator) writeToStore(aSpace *addrSpace) error {
|
|||
func (a *Allocator) deleteFromStore(aSpace *addrSpace) error {
|
||||
store := aSpace.store()
|
||||
if store == nil {
|
||||
return fmt.Errorf("invalid store while trying to delete %s address space", aSpace.DataScope())
|
||||
return types.InternalErrorf("invalid store while trying to delete %s address space", aSpace.DataScope())
|
||||
}
|
||||
|
||||
return store.DeleteObjectAtomic(aSpace)
|
||||
|
|
|
@ -88,12 +88,12 @@ func (s *SubnetKey) String() string {
|
|||
// FromString populate the SubnetKey object reading it from string
|
||||
func (s *SubnetKey) FromString(str string) error {
|
||||
if str == "" || !strings.Contains(str, "/") {
|
||||
return fmt.Errorf("invalid string form for subnetkey: %s", str)
|
||||
return types.BadRequestErrorf("invalid string form for subnetkey: %s", str)
|
||||
}
|
||||
|
||||
p := strings.Split(str, "/")
|
||||
if len(p) != 3 && len(p) != 5 {
|
||||
return fmt.Errorf("invalid string form for subnetkey: %s", str)
|
||||
return types.BadRequestErrorf("invalid string form for subnetkey: %s", str)
|
||||
}
|
||||
s.AddressSpace = p[0]
|
||||
s.Subnet = fmt.Sprintf("%s/%s", p[1], p[2])
|
||||
|
@ -317,7 +317,7 @@ func (aSpace *addrSpace) updatePoolDBOnRemoval(k SubnetKey) (func() error, error
|
|||
return func() error {
|
||||
bm, err := aSpace.alloc.retrieveBitmask(k, c.Pool)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
|
||||
return types.InternalErrorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
|
||||
}
|
||||
return bm.Destroy()
|
||||
}, nil
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
package ipamapi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
/********************
|
||||
|
@ -29,22 +30,19 @@ type Callback interface {
|
|||
|
||||
// Weel-known errors returned by IPAM
|
||||
var (
|
||||
ErrInvalidIpamService = errors.New("Invalid IPAM Service")
|
||||
ErrInvalidIpamConfigService = errors.New("Invalid IPAM Config Service")
|
||||
ErrIpamNotAvailable = errors.New("IPAM Service not available")
|
||||
ErrIpamInternalError = errors.New("IPAM Internal Error")
|
||||
ErrInvalidAddressSpace = errors.New("Invalid Address Space")
|
||||
ErrInvalidPool = errors.New("Invalid Address Pool")
|
||||
ErrInvalidSubPool = errors.New("Invalid Address SubPool")
|
||||
ErrInvalidRequest = errors.New("Invalid Request")
|
||||
ErrPoolNotFound = errors.New("Address Pool not found")
|
||||
ErrOverlapPool = errors.New("Address pool overlaps with existing pool on this address space")
|
||||
ErrNoAvailablePool = errors.New("No available pool")
|
||||
ErrNoAvailableIPs = errors.New("No available addresses on this pool")
|
||||
ErrIPAlreadyAllocated = errors.New("Address already in use")
|
||||
ErrIPOutOfRange = errors.New("Requested address is out of range")
|
||||
ErrPoolOverlap = errors.New("Pool overlaps with other one on this address space")
|
||||
ErrBadPool = errors.New("Address space does not contain specified address pool")
|
||||
ErrIpamInternalError = types.InternalErrorf("IPAM Internal Error")
|
||||
ErrInvalidAddressSpace = types.BadRequestErrorf("Invalid Address Space")
|
||||
ErrInvalidPool = types.BadRequestErrorf("Invalid Address Pool")
|
||||
ErrInvalidSubPool = types.BadRequestErrorf("Invalid Address SubPool")
|
||||
ErrInvalidRequest = types.BadRequestErrorf("Invalid Request")
|
||||
ErrPoolNotFound = types.BadRequestErrorf("Address Pool not found")
|
||||
ErrOverlapPool = types.ForbiddenErrorf("Address pool overlaps with existing pool on this address space")
|
||||
ErrNoAvailablePool = types.NoServiceErrorf("No available pool")
|
||||
ErrNoAvailableIPs = types.NoServiceErrorf("No available addresses on this pool")
|
||||
ErrIPAlreadyAllocated = types.ForbiddenErrorf("Address already in use")
|
||||
ErrIPOutOfRange = types.BadRequestErrorf("Requested address is out of range")
|
||||
ErrPoolOverlap = types.ForbiddenErrorf("Pool overlaps with other one on this address space")
|
||||
ErrBadPool = types.BadRequestErrorf("Address space does not contain specified address pool")
|
||||
)
|
||||
|
||||
/*******************************
|
||||
|
|
Loading…
Reference in a new issue