Browse code

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>

Alessandro Boch authored on 2015/10/21 09:05:01
Showing 7 changed files
... ...
@@ -24,7 +24,10 @@ const (
24 24
 )
25 25
 
26 26
 var (
27
-	errNoBitAvailable = fmt.Errorf("no bit available")
27
+	// ErrNoBitAvailable is returned when no more bits are available to set
28
+	ErrNoBitAvailable = fmt.Errorf("no bit available")
29
+	// ErrBitAllocated is returned when the specific bit requested is already set
30
+	ErrBitAllocated = fmt.Errorf("requested bit is already allocated")
28 31
 )
29 32
 
30 33
 // Handle contains the sequece representing the bitmask and its identifier
... ...
@@ -94,7 +97,7 @@ func (s *sequence) toString() string {
94 94
 // GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence
95 95
 func (s *sequence) getAvailableBit(from uint64) (uint64, uint64, error) {
96 96
 	if s.block == blockMAX || s.count == 0 {
97
-		return invalidPos, invalidPos, errNoBitAvailable
97
+		return invalidPos, invalidPos, ErrNoBitAvailable
98 98
 	}
99 99
 	bits := from
100 100
 	bitSel := blockFirstBit >> from
... ...
@@ -197,7 +200,7 @@ func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) {
197 197
 		return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end)
198 198
 	}
199 199
 	if h.Unselected() == 0 {
200
-		return invalidPos, errNoBitAvailable
200
+		return invalidPos, ErrNoBitAvailable
201 201
 	}
202 202
 	return h.set(0, start, end, true, false)
203 203
 }
... ...
@@ -205,7 +208,7 @@ func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) {
205 205
 // SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
206 206
 func (h *Handle) SetAny() (uint64, error) {
207 207
 	if h.Unselected() == 0 {
208
-		return invalidPos, errNoBitAvailable
208
+		return invalidPos, ErrNoBitAvailable
209 209
 	}
210 210
 	return h.set(0, 0, h.bits-1, true, false)
211 211
 }
... ...
@@ -269,7 +272,7 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64
269 269
 				bytePos, bitPos, err = getFirstAvailable(h.head, start)
270 270
 				ret = posToOrdinal(bytePos, bitPos)
271 271
 				if end < ret {
272
-					err = errNoBitAvailable
272
+					err = ErrNoBitAvailable
273 273
 				}
274 274
 			} else {
275 275
 				bytePos, bitPos, err = checkIfAvailable(h.head, ordinal)
... ...
@@ -449,7 +452,7 @@ func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
449 449
 		byteOffset += current.count * blockBytes
450 450
 		current = current.next
451 451
 	}
452
-	return invalidPos, invalidPos, errNoBitAvailable
452
+	return invalidPos, invalidPos, ErrNoBitAvailable
453 453
 }
454 454
 
455 455
 // 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) {
467 467
 		}
468 468
 	}
469 469
 
470
-	return invalidPos, invalidPos, fmt.Errorf("requested bit is not available")
470
+	return invalidPos, invalidPos, ErrBitAllocated
471 471
 }
472 472
 
473 473
 // Given the byte position and the sequences list head, return the pointer to the
... ...
@@ -657,7 +657,7 @@ func TestSetInRange(t *testing.T) {
657 657
 	if err == nil {
658 658
 		t.Fatalf("Expected failure. Got success with ordinal:%d", o)
659 659
 	}
660
-	if err != errNoBitAvailable {
660
+	if err != ErrNoBitAvailable {
661 661
 		t.Fatalf("Unexpected error: %v", err)
662 662
 	}
663 663
 
... ...
@@ -673,7 +673,7 @@ func TestSetInRange(t *testing.T) {
673 673
 	if err == nil {
674 674
 		t.Fatalf("Expected failure. Got success with ordinal:%d", o)
675 675
 	}
676
-	if err != errNoBitAvailable {
676
+	if err != ErrNoBitAvailable {
677 677
 		t.Fatalf("Unexpected error: %v", err)
678 678
 	}
679 679
 
... ...
@@ -687,7 +687,7 @@ func TestSetInRange(t *testing.T) {
687 687
 	if err == nil {
688 688
 		t.Fatalf("Expected failure. Got success with ordinal:%d", o)
689 689
 	}
690
-	if err != errNoBitAvailable {
690
+	if err != ErrNoBitAvailable {
691 691
 		t.Fatalf("Unexpected error: %v", err)
692 692
 	}
693 693
 }
... ...
@@ -315,17 +315,17 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error
315 315
 	_, ok := c.ipamDrivers[name]
316 316
 	c.Unlock()
317 317
 	if ok {
318
-		return driverapi.ErrActiveRegistration(name)
318
+		return types.ForbiddenErrorf("ipam driver %q already registered", name)
319 319
 	}
320 320
 	locAS, glbAS, err := driver.GetDefaultAddressSpaces()
321 321
 	if err != nil {
322
-		return fmt.Errorf("ipam driver %s failed to return default address spaces: %v", name, err)
322
+		return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err)
323 323
 	}
324 324
 	c.Lock()
325 325
 	c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS}
326 326
 	c.Unlock()
327 327
 
328
-	log.Debugf("Registering ipam provider: %s", name)
328
+	log.Debugf("Registering ipam driver: %q", name)
329 329
 
330 330
 	return nil
331 331
 }
... ...
@@ -667,7 +667,7 @@ func (c *controller) loadIpamDriver(name string) (*ipamData, error) {
667 667
 	id, ok := c.ipamDrivers[name]
668 668
 	c.Unlock()
669 669
 	if !ok {
670
-		return nil, ErrInvalidNetworkDriver(name)
670
+		return nil, types.BadRequestErrorf("invalid ipam driver: %q", name)
671 671
 	}
672 672
 	return id, nil
673 673
 }
... ...
@@ -76,8 +76,7 @@ func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
76 76
 func (a *Allocator) refresh(as string) error {
77 77
 	aSpace, err := a.getAddressSpaceFromStore(as)
78 78
 	if err != nil {
79
-		return fmt.Errorf("error getting pools config from store during init: %v",
80
-			err)
79
+		return types.InternalErrorf("error getting pools config from store: %v", err)
81 80
 	}
82 81
 
83 82
 	if aSpace == nil {
... ...
@@ -239,7 +238,7 @@ func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
239 239
 
240 240
 	store := a.getStore(key.AddressSpace)
241 241
 	if store == nil {
242
-		return fmt.Errorf("could not find store for address space %s while inserting bit mask", key.AddressSpace)
242
+		return types.InternalErrorf("could not find store for address space %s while inserting bit mask", key.AddressSpace)
243 243
 	}
244 244
 
245 245
 	ipVer := getAddressVersion(pool.IP)
... ...
@@ -279,7 +278,7 @@ func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle,
279 279
 	if !ok {
280 280
 		log.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String())
281 281
 		if err := a.insertBitMask(k, n); err != nil {
282
-			return nil, fmt.Errorf("could not find bitmask in datastore for %s", k.String())
282
+			return nil, types.InternalErrorf("could not find bitmask in datastore for %s", k.String())
283 283
 		}
284 284
 		a.Lock()
285 285
 		bm = a.addresses[k]
... ...
@@ -306,7 +305,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error)
306 306
 	}
307 307
 
308 308
 	if as != localAddressSpace && as != globalAddressSpace {
309
-		return nil, fmt.Errorf("no default pool available for non-default address spaces")
309
+		return nil, types.NotImplementedErrorf("no default pool availbale for non-default addresss spaces")
310 310
 	}
311 311
 
312 312
 	aSpace, err := a.getAddrSpace(as)
... ...
@@ -378,7 +377,7 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s
378 378
 
379 379
 	bm, err := a.retrieveBitmask(k, c.Pool)
380 380
 	if err != nil {
381
-		return nil, nil, fmt.Errorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
381
+		return nil, nil, types.InternalErrorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
382 382
 			k.String(), prefAddress, poolID, err)
383 383
 	}
384 384
 	ip, err := a.getAddress(p.Pool, bm, prefAddress, p.Range)
... ...
@@ -410,12 +409,12 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
410 410
 	p, ok := aSpace.subnets[k]
411 411
 	if !ok {
412 412
 		aSpace.Unlock()
413
-		return ipamapi.ErrBadPool
413
+		return types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
414 414
 	}
415 415
 
416 416
 	if address == nil {
417 417
 		aSpace.Unlock()
418
-		return ipamapi.ErrInvalidRequest
418
+		return types.BadRequestErrorf("invalid address: nil")
419 419
 	}
420 420
 
421 421
 	if !p.Pool.Contains(address) {
... ...
@@ -434,12 +433,12 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
434 434
 
435 435
 	h, err := types.GetHostPartIP(address, mask)
436 436
 	if err != nil {
437
-		return fmt.Errorf("failed to release address %s: %v", address.String(), err)
437
+		return types.InternalErrorf("failed to release address %s: %v", address.String(), err)
438 438
 	}
439 439
 
440 440
 	bm, err := a.retrieveBitmask(k, c.Pool)
441 441
 	if err != nil {
442
-		return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
442
+		return types.InternalErrorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
443 443
 			k.String(), address, poolID, err)
444 444
 	}
445 445
 
... ...
@@ -463,19 +462,25 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
463 463
 	} else if prefAddress != nil {
464 464
 		hostPart, e := types.GetHostPartIP(prefAddress, base.Mask)
465 465
 		if e != nil {
466
-			return nil, fmt.Errorf("failed to allocate preferred address %s: %v", prefAddress.String(), e)
466
+			return nil, types.InternalErrorf("failed to allocate preferred address %s: %v", prefAddress.String(), e)
467 467
 		}
468 468
 		ordinal = ipToUint64(types.GetMinimalIP(hostPart))
469 469
 		err = bitmask.Set(ordinal)
470 470
 	} else {
471 471
 		ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End)
472 472
 	}
473
-	if err != nil {
473
+
474
+	switch err {
475
+	case nil:
476
+		// Convert IP ordinal for this subnet into IP address
477
+		return generateAddress(ordinal, base), nil
478
+	case bitseq.ErrBitAllocated:
479
+		return nil, ipamapi.ErrIPAlreadyAllocated
480
+	case bitseq.ErrNoBitAvailable:
474 481
 		return nil, ipamapi.ErrNoAvailableIPs
482
+	default:
483
+		return nil, err
475 484
 	}
476
-
477
-	// Convert IP ordinal for this subnet into IP address
478
-	return generateAddress(ordinal, base), nil
479 485
 }
480 486
 
481 487
 // DumpDatabase dumps the internal info
... ...
@@ -2,7 +2,6 @@ package ipam
2 2
 
3 3
 import (
4 4
 	"encoding/json"
5
-	"fmt"
6 5
 
7 6
 	log "github.com/Sirupsen/logrus"
8 7
 	"github.com/docker/libnetwork/datastore"
... ...
@@ -84,7 +83,7 @@ func (a *Allocator) getStore(as string) datastore.DataStore {
84 84
 func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
85 85
 	store := a.getStore(as)
86 86
 	if store == nil {
87
-		return nil, fmt.Errorf("store for address space %s not found", as)
87
+		return nil, types.InternalErrorf("store for address space %s not found", as)
88 88
 	}
89 89
 
90 90
 	pc := &addrSpace{id: dsConfigKey + "/" + as, ds: store, alloc: a}
... ...
@@ -93,7 +92,7 @@ func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
93 93
 			return nil, nil
94 94
 		}
95 95
 
96
-		return nil, fmt.Errorf("could not get pools config from store: %v", err)
96
+		return nil, types.InternalErrorf("could not get pools config from store: %v", err)
97 97
 	}
98 98
 
99 99
 	return pc, nil
... ...
@@ -102,7 +101,7 @@ func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
102 102
 func (a *Allocator) writeToStore(aSpace *addrSpace) error {
103 103
 	store := aSpace.store()
104 104
 	if store == nil {
105
-		return fmt.Errorf("invalid store while trying to write %s address space", aSpace.DataScope())
105
+		return types.InternalErrorf("invalid store while trying to write %s address space", aSpace.DataScope())
106 106
 	}
107 107
 
108 108
 	err := store.PutObjectAtomic(aSpace)
... ...
@@ -116,7 +115,7 @@ func (a *Allocator) writeToStore(aSpace *addrSpace) error {
116 116
 func (a *Allocator) deleteFromStore(aSpace *addrSpace) error {
117 117
 	store := aSpace.store()
118 118
 	if store == nil {
119
-		return fmt.Errorf("invalid store while trying to delete %s address space", aSpace.DataScope())
119
+		return types.InternalErrorf("invalid store while trying to delete %s address space", aSpace.DataScope())
120 120
 	}
121 121
 
122 122
 	return store.DeleteObjectAtomic(aSpace)
... ...
@@ -88,12 +88,12 @@ func (s *SubnetKey) String() string {
88 88
 // FromString populate the SubnetKey object reading it from string
89 89
 func (s *SubnetKey) FromString(str string) error {
90 90
 	if str == "" || !strings.Contains(str, "/") {
91
-		return fmt.Errorf("invalid string form for subnetkey: %s", str)
91
+		return types.BadRequestErrorf("invalid string form for subnetkey: %s", str)
92 92
 	}
93 93
 
94 94
 	p := strings.Split(str, "/")
95 95
 	if len(p) != 3 && len(p) != 5 {
96
-		return fmt.Errorf("invalid string form for subnetkey: %s", str)
96
+		return types.BadRequestErrorf("invalid string form for subnetkey: %s", str)
97 97
 	}
98 98
 	s.AddressSpace = p[0]
99 99
 	s.Subnet = fmt.Sprintf("%s/%s", p[1], p[2])
... ...
@@ -317,7 +317,7 @@ func (aSpace *addrSpace) updatePoolDBOnRemoval(k SubnetKey) (func() error, error
317 317
 				return func() error {
318 318
 					bm, err := aSpace.alloc.retrieveBitmask(k, c.Pool)
319 319
 					if err != nil {
320
-						return fmt.Errorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
320
+						return types.InternalErrorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
321 321
 					}
322 322
 					return bm.Destroy()
323 323
 				}, nil
... ...
@@ -2,8 +2,9 @@
2 2
 package ipamapi
3 3
 
4 4
 import (
5
-	"errors"
6 5
 	"net"
6
+
7
+	"github.com/docker/libnetwork/types"
7 8
 )
8 9
 
9 10
 /********************
... ...
@@ -29,22 +30,19 @@ type Callback interface {
29 29
 
30 30
 // Weel-known errors returned by IPAM
31 31
 var (
32
-	ErrInvalidIpamService       = errors.New("Invalid IPAM Service")
33
-	ErrInvalidIpamConfigService = errors.New("Invalid IPAM Config Service")
34
-	ErrIpamNotAvailable         = errors.New("IPAM Service not available")
35
-	ErrIpamInternalError        = errors.New("IPAM Internal Error")
36
-	ErrInvalidAddressSpace      = errors.New("Invalid Address Space")
37
-	ErrInvalidPool              = errors.New("Invalid Address Pool")
38
-	ErrInvalidSubPool           = errors.New("Invalid Address SubPool")
39
-	ErrInvalidRequest           = errors.New("Invalid Request")
40
-	ErrPoolNotFound             = errors.New("Address Pool not found")
41
-	ErrOverlapPool              = errors.New("Address pool overlaps with existing pool on this address space")
42
-	ErrNoAvailablePool          = errors.New("No available pool")
43
-	ErrNoAvailableIPs           = errors.New("No available addresses on this pool")
44
-	ErrIPAlreadyAllocated       = errors.New("Address already in use")
45
-	ErrIPOutOfRange             = errors.New("Requested address is out of range")
46
-	ErrPoolOverlap              = errors.New("Pool overlaps with other one on this address space")
47
-	ErrBadPool                  = errors.New("Address space does not contain specified address pool")
32
+	ErrIpamInternalError   = types.InternalErrorf("IPAM Internal Error")
33
+	ErrInvalidAddressSpace = types.BadRequestErrorf("Invalid Address Space")
34
+	ErrInvalidPool         = types.BadRequestErrorf("Invalid Address Pool")
35
+	ErrInvalidSubPool      = types.BadRequestErrorf("Invalid Address SubPool")
36
+	ErrInvalidRequest      = types.BadRequestErrorf("Invalid Request")
37
+	ErrPoolNotFound        = types.BadRequestErrorf("Address Pool not found")
38
+	ErrOverlapPool         = types.ForbiddenErrorf("Address pool overlaps with existing pool on this address space")
39
+	ErrNoAvailablePool     = types.NoServiceErrorf("No available pool")
40
+	ErrNoAvailableIPs      = types.NoServiceErrorf("No available addresses on this pool")
41
+	ErrIPAlreadyAllocated  = types.ForbiddenErrorf("Address already in use")
42
+	ErrIPOutOfRange        = types.BadRequestErrorf("Requested address is out of range")
43
+	ErrPoolOverlap         = types.ForbiddenErrorf("Pool overlaps with other one on this address space")
44
+	ErrBadPool             = types.BadRequestErrorf("Address space does not contain specified address pool")
48 45
 )
49 46
 
50 47
 /*******************************