소스 검색

Merge pull request #687 from aboch/id

Adjust ipam errors
Madhu Venugopal 9 년 전
부모
커밋
15a70d92dc

+ 10 - 7
libnetwork/bitseq/sequence.go

@@ -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

+ 3 - 3
libnetwork/bitseq/sequence_test.go

@@ -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)
 	}
 }

+ 4 - 4
libnetwork/controller.go

@@ -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
 }

+ 20 - 15
libnetwork/ipam/allocator.go

@@ -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 {
+
+	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
 	}
-
-	// Convert IP ordinal for this subnet into IP address
-	return generateAddress(ordinal, base), nil
 }
 
 // DumpDatabase dumps the internal info

+ 4 - 5
libnetwork/ipam/store.go

@@ -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)

+ 3 - 3
libnetwork/ipam/structures.go

@@ -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

+ 15 - 17
libnetwork/ipamapi/contract.go

@@ -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")
 )
 
 /*******************************