diff --git a/libnetwork/bitseq/sequence.go b/libnetwork/bitseq/sequence.go index 422cb9fe42..a537ed0107 100644 --- a/libnetwork/bitseq/sequence.go +++ b/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 diff --git a/libnetwork/bitseq/sequence_test.go b/libnetwork/bitseq/sequence_test.go index 87c3641d40..b4817feb27 100644 --- a/libnetwork/bitseq/sequence_test.go +++ b/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) } } diff --git a/libnetwork/controller.go b/libnetwork/controller.go index e1d8277fac..be9b726a28 100644 --- a/libnetwork/controller.go +++ b/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 } diff --git a/libnetwork/ipam/allocator.go b/libnetwork/ipam/allocator.go index 7481fa2f69..1ca9127cc2 100644 --- a/libnetwork/ipam/allocator.go +++ b/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 { - 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 diff --git a/libnetwork/ipam/store.go b/libnetwork/ipam/store.go index 29cd753b60..ba44ef9dd9 100644 --- a/libnetwork/ipam/store.go +++ b/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) diff --git a/libnetwork/ipam/structures.go b/libnetwork/ipam/structures.go index 9ac171887c..cd0593ceff 100644 --- a/libnetwork/ipam/structures.go +++ b/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 diff --git a/libnetwork/ipamapi/contract.go b/libnetwork/ipamapi/contract.go index 2b11b303a4..a3d98d1e92 100644 --- a/libnetwork/ipamapi/contract.go +++ b/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") ) /*******************************