Browse code

Provide interface to categorize errors

- Package types to define the interfaces libnetwork errors
may implement, so that caller can categorize them.

Signed-off-by: Alessandro Boch <aboch@docker.com>

Alessandro Boch authored on 2015/05/15 06:56:15
Showing 27 changed files
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"net/http"
8 8
 
9 9
 	"github.com/docker/libnetwork"
10
+	"github.com/docker/libnetwork/types"
10 11
 	"github.com/gorilla/mux"
11 12
 )
12 13
 
... ...
@@ -434,7 +435,7 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N
434 434
 		panic(fmt.Sprintf("unexpected selector for network search: %d", by))
435 435
 	}
436 436
 	if err != nil {
437
-		if err == libnetwork.ErrNoSuchNetwork {
437
+		if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
438 438
 			return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound}
439 439
 		}
440 440
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
... ...
@@ -460,7 +461,7 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int)
460 460
 		panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
461 461
 	}
462 462
 	if err != nil {
463
-		if err == libnetwork.ErrNoSuchEndpoint {
463
+		if _, ok := err.(libnetwork.ErrNoSuchEndpoint); ok {
464 464
 			return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
465 465
 		}
466 466
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
... ...
@@ -469,9 +470,26 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int)
469 469
 }
470 470
 
471 471
 func convertNetworkError(err error) *responseStatus {
472
-	// No real libnetwork error => http error code conversion for now.
473
-	// Will came in later when new interface for libnetwork error is vailable
474
-	return &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
472
+	var code int
473
+	switch err.(type) {
474
+	case types.BadRequestError:
475
+		code = http.StatusBadRequest
476
+	case types.ForbiddenError:
477
+		code = http.StatusForbidden
478
+	case types.NotFoundError:
479
+		code = http.StatusNotFound
480
+	case types.TimeoutError:
481
+		code = http.StatusRequestTimeout
482
+	case types.NotImplementedError:
483
+		code = http.StatusNotImplemented
484
+	case types.NoServiceError:
485
+		code = http.StatusServiceUnavailable
486
+	case types.InternalError:
487
+		code = http.StatusInternalServerError
488
+	default:
489
+		code = http.StatusInternalServerError
490
+	}
491
+	return &responseStatus{Status: err.Error(), StatusCode: code}
475 492
 }
476 493
 
477 494
 func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
... ...
@@ -193,8 +193,8 @@ func TestCreateDeleteNetwork(t *testing.T) {
193 193
 	if errRsp == &createdResponse {
194 194
 		t.Fatalf("Expected to fail but succeeded")
195 195
 	}
196
-	if errRsp.StatusCode != http.StatusBadRequest {
197
-		t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
196
+	if errRsp.StatusCode != http.StatusNotFound {
197
+		t.Fatalf("Expected StatusNotFound status code, got: %v", errRsp)
198 198
 	}
199 199
 
200 200
 	ops := make(map[string]interface{})
... ...
@@ -1305,3 +1305,92 @@ func TestHttpHandlerGood(t *testing.T) {
1305 1305
 		t.Fatalf("Incongruent resource found")
1306 1306
 	}
1307 1307
 }
1308
+
1309
+type bre struct{}
1310
+
1311
+func (b *bre) Error() string {
1312
+	return "I am a bad request error"
1313
+}
1314
+func (b *bre) BadRequest() {}
1315
+
1316
+type nfe struct{}
1317
+
1318
+func (n *nfe) Error() string {
1319
+	return "I am a not found error"
1320
+}
1321
+func (n *nfe) NotFound() {}
1322
+
1323
+type forb struct{}
1324
+
1325
+func (f *forb) Error() string {
1326
+	return "I am a bad request error"
1327
+}
1328
+func (f *forb) Forbidden() {}
1329
+
1330
+type notimpl struct{}
1331
+
1332
+func (nip *notimpl) Error() string {
1333
+	return "I am a not implemented error"
1334
+}
1335
+func (nip *notimpl) NotImplemented() {}
1336
+
1337
+type inter struct{}
1338
+
1339
+func (it *inter) Error() string {
1340
+	return "I am a internal error"
1341
+}
1342
+func (it *inter) Internal() {}
1343
+
1344
+type tout struct{}
1345
+
1346
+func (to *tout) Error() string {
1347
+	return "I am a timeout error"
1348
+}
1349
+func (to *tout) Timeout() {}
1350
+
1351
+type noserv struct{}
1352
+
1353
+func (nos *noserv) Error() string {
1354
+	return "I am a no service error"
1355
+}
1356
+func (nos *noserv) NoService() {}
1357
+
1358
+type notclassified struct{}
1359
+
1360
+func (noc *notclassified) Error() string {
1361
+	return "I am a non classified error"
1362
+}
1363
+
1364
+func TestErrorConversion(t *testing.T) {
1365
+	if convertNetworkError(new(bre)).StatusCode != http.StatusBadRequest {
1366
+		t.Fatalf("Failed to recognize BadRequest error")
1367
+	}
1368
+
1369
+	if convertNetworkError(new(nfe)).StatusCode != http.StatusNotFound {
1370
+		t.Fatalf("Failed to recognize NotFound error")
1371
+	}
1372
+
1373
+	if convertNetworkError(new(forb)).StatusCode != http.StatusForbidden {
1374
+		t.Fatalf("Failed to recognize Forbidden error")
1375
+	}
1376
+
1377
+	if convertNetworkError(new(notimpl)).StatusCode != http.StatusNotImplemented {
1378
+		t.Fatalf("Failed to recognize NotImplemented error")
1379
+	}
1380
+
1381
+	if convertNetworkError(new(inter)).StatusCode != http.StatusInternalServerError {
1382
+		t.Fatalf("Failed to recognize Internal error")
1383
+	}
1384
+
1385
+	if convertNetworkError(new(tout)).StatusCode != http.StatusRequestTimeout {
1386
+		t.Fatalf("Failed to recognize Timeout error")
1387
+	}
1388
+
1389
+	if convertNetworkError(new(noserv)).StatusCode != http.StatusServiceUnavailable {
1390
+		t.Fatalf("Failed to recognize No Service error")
1391
+	}
1392
+
1393
+	if convertNetworkError(new(notclassified)).StatusCode != http.StatusInternalServerError {
1394
+		t.Fatalf("Failed to recognize not classified error as Internal error")
1395
+	}
1396
+}
... ...
@@ -134,7 +134,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver)
134 134
 // are network specific and modeled in a generic way.
135 135
 func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
136 136
 	if name == "" {
137
-		return nil, ErrInvalidName
137
+		return nil, ErrInvalidName(name)
138 138
 	}
139 139
 	// Check if a driver for the specified network type is available
140 140
 	c.Lock()
... ...
@@ -203,7 +203,7 @@ func (c *controller) WalkNetworks(walker NetworkWalker) {
203 203
 
204 204
 func (c *controller) NetworkByName(name string) (Network, error) {
205 205
 	if name == "" {
206
-		return nil, ErrInvalidName
206
+		return nil, ErrInvalidName(name)
207 207
 	}
208 208
 	var n Network
209 209
 
... ...
@@ -218,7 +218,7 @@ func (c *controller) NetworkByName(name string) (Network, error) {
218 218
 	c.WalkNetworks(s)
219 219
 
220 220
 	if n == nil {
221
-		return nil, ErrNoSuchNetwork
221
+		return nil, ErrNoSuchNetwork(name)
222 222
 	}
223 223
 
224 224
 	return n, nil
... ...
@@ -226,14 +226,14 @@ func (c *controller) NetworkByName(name string) (Network, error) {
226 226
 
227 227
 func (c *controller) NetworkByID(id string) (Network, error) {
228 228
 	if id == "" {
229
-		return nil, ErrInvalidID
229
+		return nil, ErrInvalidID(id)
230 230
 	}
231 231
 	c.Lock()
232 232
 	defer c.Unlock()
233 233
 	if n, ok := c.networks[types.UUID(id)]; ok {
234 234
 		return n, nil
235 235
 	}
236
-	return nil, ErrNoSuchNetwork
236
+	return nil, ErrNoSuchNetwork(id)
237 237
 }
238 238
 
239 239
 func (c *controller) sandboxAdd(key string, create bool) (sandbox.Sandbox, error) {
... ...
@@ -286,13 +286,16 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
286 286
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
287 287
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
288 288
 	if err != nil {
289
+		if err == plugins.ErrNotFound {
290
+			return nil, types.NotFoundErrorf(err.Error())
291
+		}
289 292
 		return nil, err
290 293
 	}
291 294
 	c.Lock()
292 295
 	defer c.Unlock()
293 296
 	d, ok := c.drivers[networkType]
294 297
 	if !ok {
295
-		return nil, ErrInvalidNetworkDriver
298
+		return nil, ErrInvalidNetworkDriver(networkType)
296 299
 	}
297 300
 	return d, nil
298 301
 }
... ...
@@ -1,24 +1,11 @@
1 1
 package driverapi
2 2
 
3 3
 import (
4
-	"errors"
5
-	"fmt"
6 4
 	"net"
7 5
 
8 6
 	"github.com/docker/libnetwork/types"
9 7
 )
10 8
 
11
-var (
12
-	// ErrEndpointExists is returned if more than one endpoint is added to the network
13
-	ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
14
-	// ErrNoNetwork is returned if no network with the specified id exists
15
-	ErrNoNetwork = errors.New("No network exists")
16
-	// ErrNoEndpoint is returned if no endpoint with the specified id exists
17
-	ErrNoEndpoint = errors.New("No endpoint exists")
18
-	// ErrNotImplemented is returned when a Driver has not implemented an API yet
19
-	ErrNotImplemented = errors.New("The API is not implemented yet")
20
-)
21
-
22 9
 // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
23 10
 const NetworkPluginEndpointType = "NetworkDriver"
24 11
 
... ...
@@ -124,14 +111,6 @@ type JoinInfo interface {
124 124
 	SetResolvConfPath(string) error
125 125
 }
126 126
 
127
-// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered
128
-type ErrActiveRegistration string
129
-
130
-// Error interface for ErrActiveRegistration
131
-func (ar ErrActiveRegistration) Error() string {
132
-	return fmt.Sprintf("Driver already registered for type %q", string(ar))
133
-}
134
-
135 127
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
136 128
 type DriverCallback interface {
137 129
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance
138 130
new file mode 100644
... ...
@@ -0,0 +1,56 @@
0
+package driverapi
1
+
2
+import (
3
+	"fmt"
4
+)
5
+
6
+// ErrNoNetwork is returned if no network with the specified id exists
7
+type ErrNoNetwork string
8
+
9
+func (enn ErrNoNetwork) Error() string {
10
+	return fmt.Sprintf("No network (%s) exists", string(enn))
11
+}
12
+
13
+// NotFound denotes the type of this error
14
+func (enn ErrNoNetwork) NotFound() {}
15
+
16
+// ErrEndpointExists is returned if more than one endpoint is added to the network
17
+type ErrEndpointExists string
18
+
19
+func (ee ErrEndpointExists) Error() string {
20
+	return fmt.Sprintf("Endpoint (%s) already exists (Only one endpoint allowed)", string(ee))
21
+}
22
+
23
+// Forbidden denotes the type of this error
24
+func (ee ErrEndpointExists) Forbidden() {}
25
+
26
+// ErrNotImplemented is returned when a Driver has not implemented an API yet
27
+type ErrNotImplemented struct{}
28
+
29
+func (eni *ErrNotImplemented) Error() string {
30
+	return "The API is not implemented yet"
31
+}
32
+
33
+// NotImplemented denotes the type of this error
34
+func (eni *ErrNotImplemented) NotImplemented() {}
35
+
36
+// ErrNoEndpoint is returned if no endpoint with the specified id exists
37
+type ErrNoEndpoint string
38
+
39
+func (ene ErrNoEndpoint) Error() string {
40
+	return fmt.Sprintf("No endpoint (%s) exists", string(ene))
41
+}
42
+
43
+// NotFound denotes the type of this error
44
+func (ene ErrNoEndpoint) NotFound() {}
45
+
46
+// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered
47
+type ErrActiveRegistration string
48
+
49
+// Error interface for ErrActiveRegistration
50
+func (ar ErrActiveRegistration) Error() string {
51
+	return fmt.Sprintf("Driver already registered for type %q", string(ar))
52
+}
53
+
54
+// Forbidden denotes the type of this error
55
+func (ar ErrActiveRegistration) Forbidden() {}
... ...
@@ -109,7 +109,7 @@ func Init(dc driverapi.DriverCallback) error {
109 109
 // Whatever can be assessed a priori before attempting any programming.
110 110
 func (c *NetworkConfiguration) Validate() error {
111 111
 	if c.Mtu < 0 {
112
-		return ErrInvalidMtu
112
+		return ErrInvalidMtu(c.Mtu)
113 113
 	}
114 114
 
115 115
 	// If bridge v4 subnet is specified
... ...
@@ -118,19 +118,19 @@ func (c *NetworkConfiguration) Validate() error {
118 118
 		if c.FixedCIDR != nil {
119 119
 			// Check Network address
120 120
 			if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
121
-				return ErrInvalidContainerSubnet
121
+				return &ErrInvalidContainerSubnet{}
122 122
 			}
123 123
 			// Check it is effectively a subset
124 124
 			brNetLen, _ := c.AddressIPv4.Mask.Size()
125 125
 			cnNetLen, _ := c.FixedCIDR.Mask.Size()
126 126
 			if brNetLen > cnNetLen {
127
-				return ErrInvalidContainerSubnet
127
+				return &ErrInvalidContainerSubnet{}
128 128
 			}
129 129
 		}
130 130
 		// If default gw is specified, it must be part of bridge subnet
131 131
 		if c.DefaultGatewayIPv4 != nil {
132 132
 			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
133
-				return ErrInvalidGateway
133
+				return &ErrInvalidGateway{}
134 134
 			}
135 135
 		}
136 136
 	}
... ...
@@ -138,7 +138,7 @@ func (c *NetworkConfiguration) Validate() error {
138 138
 	// If default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet
139 139
 	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
140 140
 		if c.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) {
141
-			return ErrInvalidGateway
141
+			return &ErrInvalidGateway{}
142 142
 		}
143 143
 	}
144 144
 
... ...
@@ -167,7 +167,7 @@ func (d *driver) Config(option map[string]interface{}) error {
167 167
 	defer d.Unlock()
168 168
 
169 169
 	if d.config != nil {
170
-		return ErrConfigExists
170
+		return &ErrConfigExists{}
171 171
 	}
172 172
 
173 173
 	genericData, ok := option[netlabel.GenericData]
... ...
@@ -182,7 +182,7 @@ func (d *driver) Config(option map[string]interface{}) error {
182 182
 		case *Configuration:
183 183
 			config = opt
184 184
 		default:
185
-			return ErrInvalidDriverConfig
185
+			return &ErrInvalidDriverConfig{}
186 186
 		}
187 187
 
188 188
 		d.config = config
... ...
@@ -220,7 +220,7 @@ func parseNetworkOptions(option options.Generic) (*NetworkConfiguration, error)
220 220
 		case *NetworkConfiguration:
221 221
 			config = opt
222 222
 		default:
223
-			return nil, ErrInvalidNetworkConfig
223
+			return nil, &ErrInvalidNetworkConfig{}
224 224
 		}
225 225
 
226 226
 		if err := config.Validate(); err != nil {
... ...
@@ -247,7 +247,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
247 247
 	// Sanity checks
248 248
 	if d.network != nil {
249 249
 		d.Unlock()
250
-		return ErrNetworkExists
250
+		return &ErrNetworkExists{}
251 251
 	}
252 252
 
253 253
 	// Create and set network handler in driver
... ...
@@ -361,7 +361,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
361 361
 
362 362
 	// Sanity check
363 363
 	if n == nil {
364
-		err = driverapi.ErrNoNetwork
364
+		err = driverapi.ErrNoNetwork(nid)
365 365
 		return err
366 366
 	}
367 367
 
... ...
@@ -397,7 +397,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
397 397
 	config := n.config
398 398
 	d.Unlock()
399 399
 	if n == nil {
400
-		return driverapi.ErrNoNetwork
400
+		return driverapi.ErrNoNetwork(nid)
401 401
 	}
402 402
 
403 403
 	// Sanity check
... ...
@@ -416,7 +416,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
416 416
 
417 417
 	// Endpoint with that id exists either on desired or other sandbox
418 418
 	if ep != nil {
419
-		return driverapi.ErrEndpointExists
419
+		return driverapi.ErrEndpointExists(eid)
420 420
 	}
421 421
 
422 422
 	// Try to convert the options to endpoint configuration
... ...
@@ -578,7 +578,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
578 578
 	config := n.config
579 579
 	d.Unlock()
580 580
 	if n == nil {
581
-		return driverapi.ErrNoNetwork
581
+		return driverapi.ErrNoNetwork(nid)
582 582
 	}
583 583
 
584 584
 	// Sanity Check
... ...
@@ -648,7 +648,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
648 648
 	n := d.network
649 649
 	d.Unlock()
650 650
 	if n == nil {
651
-		return nil, driverapi.ErrNoNetwork
651
+		return nil, driverapi.ErrNoNetwork(nid)
652 652
 	}
653 653
 
654 654
 	// Sanity check
... ...
@@ -665,7 +665,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
665 665
 		return nil, err
666 666
 	}
667 667
 	if ep == nil {
668
-		return nil, driverapi.ErrNoEndpoint
668
+		return nil, driverapi.ErrNoEndpoint(eid)
669 669
 	}
670 670
 
671 671
 	m := make(map[string]interface{})
... ...
@@ -856,7 +856,7 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
856 856
 		if mac, ok := opt.(net.HardwareAddr); ok {
857 857
 			ec.MacAddress = mac
858 858
 		} else {
859
-			return nil, ErrInvalidEndpointConfig
859
+			return nil, &ErrInvalidEndpointConfig{}
860 860
 		}
861 861
 	}
862 862
 
... ...
@@ -864,7 +864,7 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
864 864
 		if bs, ok := opt.([]types.PortBinding); ok {
865 865
 			ec.PortBindings = bs
866 866
 		} else {
867
-			return nil, ErrInvalidEndpointConfig
867
+			return nil, &ErrInvalidEndpointConfig{}
868 868
 		}
869 869
 	}
870 870
 
... ...
@@ -872,7 +872,7 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
872 872
 		if ports, ok := opt.([]types.TransportPort); ok {
873 873
 			ec.ExposedPorts = ports
874 874
 		} else {
875
-			return nil, ErrInvalidEndpointConfig
875
+			return nil, &ErrInvalidEndpointConfig{}
876 876
 		}
877 877
 	}
878 878
 
... ...
@@ -924,5 +924,5 @@ func generateIfaceName() (string, error) {
924 924
 			return "", err
925 925
 		}
926 926
 	}
927
-	return "", ErrIfaceName
927
+	return "", &ErrIfaceName{}
928 928
 }
929 929
deleted file mode 100644
... ...
@@ -1,201 +0,0 @@
1
-package bridge
2
-
3
-import (
4
-	"errors"
5
-	"fmt"
6
-	"net"
7
-)
8
-
9
-var (
10
-	// ErrConfigExists error is returned when driver already has a config applied.
11
-	ErrConfigExists = errors.New("configuration already exists, bridge configuration can be applied only once")
12
-
13
-	// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config
14
-	ErrInvalidDriverConfig = errors.New("Invalid configuration passed to Bridge Driver")
15
-
16
-	// ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config.
17
-	ErrInvalidNetworkConfig = errors.New("trying to create a network on a driver without valid config")
18
-
19
-	// ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration.
20
-	ErrInvalidContainerConfig = errors.New("Error in joining a container due to invalid configuration")
21
-
22
-	// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration.
23
-	ErrInvalidEndpointConfig = errors.New("trying to create an endpoint with an invalid endpoint configuration")
24
-
25
-	// ErrNetworkExists error is returned when a network already exists and another network is created.
26
-	ErrNetworkExists = errors.New("network already exists, bridge can only have one network")
27
-
28
-	// ErrIfaceName error is returned when a new name could not be generated.
29
-	ErrIfaceName = errors.New("failed to find name for new interface")
30
-
31
-	// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
32
-	ErrNoIPAddr = errors.New("bridge has no IPv4 address configured")
33
-
34
-	// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
35
-	ErrInvalidGateway = errors.New("default gateway ip must be part of the network")
36
-
37
-	// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
38
-	ErrInvalidContainerSubnet = errors.New("container subnet must be a subset of bridge network")
39
-
40
-	// ErrInvalidMtu is returned when the user provided MTU is not valid.
41
-	ErrInvalidMtu = errors.New("invalid MTU number")
42
-
43
-	// ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration
44
-	// not enabled.
45
-	ErrIPFwdCfg = errors.New("unexpected request to enable IP Forwarding")
46
-)
47
-
48
-// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
49
-type ErrInvalidPort string
50
-
51
-func (ip ErrInvalidPort) Error() string {
52
-	return fmt.Sprintf("invalid transport port: %s", string(ip))
53
-}
54
-
55
-// ErrUnsupportedAddressType is returned when the specified address type is not supported.
56
-type ErrUnsupportedAddressType string
57
-
58
-func (uat ErrUnsupportedAddressType) Error() string {
59
-	return fmt.Sprintf("unsupported address type: %s", string(uat))
60
-}
61
-
62
-// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid.
63
-type ErrInvalidAddressBinding string
64
-
65
-func (iab ErrInvalidAddressBinding) Error() string {
66
-	return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
67
-}
68
-
69
-// ActiveEndpointsError is returned when there are
70
-// still active endpoints in the network being deleted.
71
-type ActiveEndpointsError string
72
-
73
-func (aee ActiveEndpointsError) Error() string {
74
-	return fmt.Sprintf("network %s has active endpoint", string(aee))
75
-}
76
-
77
-// InvalidNetworkIDError is returned when the passed
78
-// network id for an existing network is not a known id.
79
-type InvalidNetworkIDError string
80
-
81
-func (inie InvalidNetworkIDError) Error() string {
82
-	return fmt.Sprintf("invalid network id %s", string(inie))
83
-}
84
-
85
-// InvalidEndpointIDError is returned when the passed
86
-// endpoint id is not valid.
87
-type InvalidEndpointIDError string
88
-
89
-func (ieie InvalidEndpointIDError) Error() string {
90
-	return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
91
-}
92
-
93
-// InvalidSandboxIDError is returned when the passed
94
-// sandbox id valid.
95
-type InvalidSandboxIDError string
96
-
97
-func (isie InvalidSandboxIDError) Error() string {
98
-	return fmt.Sprintf("invalid sanbox id: %s", string(isie))
99
-}
100
-
101
-// EndpointNotFoundError is returned when the no endpoint
102
-// with the passed endpoint id is found.
103
-type EndpointNotFoundError string
104
-
105
-func (enfe EndpointNotFoundError) Error() string {
106
-	return fmt.Sprintf("endpoint not found: %s", string(enfe))
107
-}
108
-
109
-// NonDefaultBridgeExistError is returned when a non-default
110
-// bridge config is passed but it does not already exist.
111
-type NonDefaultBridgeExistError string
112
-
113
-func (ndbee NonDefaultBridgeExistError) Error() string {
114
-	return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
115
-}
116
-
117
-// FixedCIDRv4Error is returned when fixed-cidrv4 configuration
118
-// failed.
119
-type FixedCIDRv4Error struct {
120
-	net    *net.IPNet
121
-	subnet *net.IPNet
122
-	err    error
123
-}
124
-
125
-func (fcv4 *FixedCIDRv4Error) Error() string {
126
-	return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.subnet, fcv4.net, fcv4.err)
127
-}
128
-
129
-// FixedCIDRv6Error is returned when fixed-cidrv6 configuration
130
-// failed.
131
-type FixedCIDRv6Error struct {
132
-	net *net.IPNet
133
-	err error
134
-}
135
-
136
-func (fcv6 *FixedCIDRv6Error) Error() string {
137
-	return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.net, fcv6.net, fcv6.err)
138
-}
139
-
140
-type ipTableCfgError string
141
-
142
-func (name ipTableCfgError) Error() string {
143
-	return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
144
-}
145
-
146
-type invalidIPTablesCfgError string
147
-
148
-func (action invalidIPTablesCfgError) Error() string {
149
-	return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
150
-}
151
-
152
-// IPv4AddrRangeError is returned when a valid IP address range couldn't be found.
153
-type IPv4AddrRangeError string
154
-
155
-func (name IPv4AddrRangeError) Error() string {
156
-	return fmt.Sprintf("can't find an address range for interface %q", string(name))
157
-}
158
-
159
-// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge.
160
-type IPv4AddrAddError struct {
161
-	ip  *net.IPNet
162
-	err error
163
-}
164
-
165
-func (ipv4 *IPv4AddrAddError) Error() string {
166
-	return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.ip, ipv4.err)
167
-}
168
-
169
-// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge.
170
-type IPv6AddrAddError struct {
171
-	ip  *net.IPNet
172
-	err error
173
-}
174
-
175
-func (ipv6 *IPv6AddrAddError) Error() string {
176
-	return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.ip, ipv6.err)
177
-}
178
-
179
-// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured.
180
-type IPv4AddrNoMatchError struct {
181
-	ip    net.IP
182
-	cfgIP net.IP
183
-}
184
-
185
-func (ipv4 *IPv4AddrNoMatchError) Error() string {
186
-	return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.ip, ipv4.cfgIP)
187
-}
188
-
189
-// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured.
190
-type IPv6AddrNoMatchError net.IPNet
191
-
192
-func (ipv6 *IPv6AddrNoMatchError) Error() string {
193
-	return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
194
-}
195
-
196
-// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address
197
-type InvalidLinkIPAddrError string
198
-
199
-func (address InvalidLinkIPAddrError) Error() string {
200
-	return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
201
-}
202 1
new file mode 100644
... ...
@@ -0,0 +1,341 @@
0
+package bridge
1
+
2
+import (
3
+	"fmt"
4
+	"net"
5
+)
6
+
7
+// ErrConfigExists error is returned when driver already has a config applied.
8
+type ErrConfigExists struct{}
9
+
10
+func (ece *ErrConfigExists) Error() string {
11
+	return "configuration already exists, bridge configuration can be applied only once"
12
+}
13
+
14
+// Forbidden denotes the type of this error
15
+func (ece *ErrConfigExists) Forbidden() {}
16
+
17
+// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config
18
+type ErrInvalidDriverConfig struct{}
19
+
20
+func (eidc *ErrInvalidDriverConfig) Error() string {
21
+	return "Invalid configuration passed to Bridge Driver"
22
+}
23
+
24
+// BadRequest denotes the type of this error
25
+func (eidc *ErrInvalidDriverConfig) BadRequest() {}
26
+
27
+// ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config.
28
+type ErrInvalidNetworkConfig struct{}
29
+
30
+func (einc *ErrInvalidNetworkConfig) Error() string {
31
+	return "trying to create a network on a driver without valid config"
32
+}
33
+
34
+// Forbidden denotes the type of this error
35
+func (einc *ErrInvalidNetworkConfig) Forbidden() {}
36
+
37
+// ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration.
38
+type ErrInvalidContainerConfig struct{}
39
+
40
+func (eicc *ErrInvalidContainerConfig) Error() string {
41
+	return "Error in joining a container due to invalid configuration"
42
+}
43
+
44
+// BadRequest denotes the type of this error
45
+func (eicc *ErrInvalidContainerConfig) BadRequest() {}
46
+
47
+// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration.
48
+type ErrInvalidEndpointConfig struct{}
49
+
50
+func (eiec *ErrInvalidEndpointConfig) Error() string {
51
+	return "trying to create an endpoint with an invalid endpoint configuration"
52
+}
53
+
54
+// BadRequest denotes the type of this error
55
+func (eiec *ErrInvalidEndpointConfig) BadRequest() {}
56
+
57
+// ErrNetworkExists error is returned when a network already exists and another network is created.
58
+type ErrNetworkExists struct{}
59
+
60
+func (ene *ErrNetworkExists) Error() string {
61
+	return "network already exists, bridge can only have one network"
62
+}
63
+
64
+// Forbidden denotes the type of this error
65
+func (ene *ErrNetworkExists) Forbidden() {}
66
+
67
+// ErrIfaceName error is returned when a new name could not be generated.
68
+type ErrIfaceName struct{}
69
+
70
+func (ein *ErrIfaceName) Error() string {
71
+	return "failed to find name for new interface"
72
+}
73
+
74
+// InternalError denotes the type of this error
75
+func (ein *ErrIfaceName) InternalError() {}
76
+
77
+// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
78
+type ErrNoIPAddr struct{}
79
+
80
+func (enip *ErrNoIPAddr) Error() string {
81
+	return "bridge has no IPv4 address configured"
82
+}
83
+
84
+// InternalError denotes the type of this error
85
+func (enip *ErrNoIPAddr) InternalError() {}
86
+
87
+// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
88
+type ErrInvalidGateway struct{}
89
+
90
+func (eig *ErrInvalidGateway) Error() string {
91
+	return "default gateway ip must be part of the network"
92
+}
93
+
94
+// BadRequest denotes the type of this error
95
+func (eig *ErrInvalidGateway) BadRequest() {}
96
+
97
+// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
98
+type ErrInvalidContainerSubnet struct{}
99
+
100
+func (eis *ErrInvalidContainerSubnet) Error() string {
101
+	return "container subnet must be a subset of bridge network"
102
+}
103
+
104
+// BadRequest denotes the type of this error
105
+func (eis *ErrInvalidContainerSubnet) BadRequest() {}
106
+
107
+// ErrInvalidMtu is returned when the user provided MTU is not valid.
108
+type ErrInvalidMtu int
109
+
110
+func (eim ErrInvalidMtu) Error() string {
111
+	return fmt.Sprintf("invalid MTU number: %d", int(eim))
112
+}
113
+
114
+// BadRequest denotes the type of this error
115
+func (eim ErrInvalidMtu) BadRequest() {}
116
+
117
+// ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration
118
+// not enabled.
119
+type ErrIPFwdCfg struct{}
120
+
121
+func (eipf *ErrIPFwdCfg) Error() string {
122
+	return "unexpected request to enable IP Forwarding"
123
+}
124
+
125
+// BadRequest denotes the type of this error
126
+func (eipf *ErrIPFwdCfg) BadRequest() {}
127
+
128
+// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
129
+type ErrInvalidPort string
130
+
131
+func (ip ErrInvalidPort) Error() string {
132
+	return fmt.Sprintf("invalid transport port: %s", string(ip))
133
+}
134
+
135
+// BadRequest denotes the type of this error
136
+func (ip ErrInvalidPort) BadRequest() {}
137
+
138
+// ErrUnsupportedAddressType is returned when the specified address type is not supported.
139
+type ErrUnsupportedAddressType string
140
+
141
+func (uat ErrUnsupportedAddressType) Error() string {
142
+	return fmt.Sprintf("unsupported address type: %s", string(uat))
143
+}
144
+
145
+// BadRequest denotes the type of this error
146
+func (uat ErrUnsupportedAddressType) BadRequest() {}
147
+
148
+// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid.
149
+type ErrInvalidAddressBinding string
150
+
151
+func (iab ErrInvalidAddressBinding) Error() string {
152
+	return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
153
+}
154
+
155
+// BadRequest denotes the type of this error
156
+func (iab ErrInvalidAddressBinding) BadRequest() {}
157
+
158
+// ActiveEndpointsError is returned when there are
159
+// still active endpoints in the network being deleted.
160
+type ActiveEndpointsError string
161
+
162
+func (aee ActiveEndpointsError) Error() string {
163
+	return fmt.Sprintf("network %s has active endpoint", string(aee))
164
+}
165
+
166
+// Forbidden denotes the type of this error
167
+func (aee ActiveEndpointsError) Forbidden() {}
168
+
169
+// InvalidNetworkIDError is returned when the passed
170
+// network id for an existing network is not a known id.
171
+type InvalidNetworkIDError string
172
+
173
+func (inie InvalidNetworkIDError) Error() string {
174
+	return fmt.Sprintf("invalid network id %s", string(inie))
175
+}
176
+
177
+// NotFound denotes the type of this error
178
+func (inie InvalidNetworkIDError) NotFound() {}
179
+
180
+// InvalidEndpointIDError is returned when the passed
181
+// endpoint id is not valid.
182
+type InvalidEndpointIDError string
183
+
184
+func (ieie InvalidEndpointIDError) Error() string {
185
+	return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
186
+}
187
+
188
+// BadRequest denotes the type of this error
189
+func (ieie InvalidEndpointIDError) BadRequest() {}
190
+
191
+// InvalidSandboxIDError is returned when the passed
192
+// sandbox id is not valid.
193
+type InvalidSandboxIDError string
194
+
195
+func (isie InvalidSandboxIDError) Error() string {
196
+	return fmt.Sprintf("invalid sanbox id: %s", string(isie))
197
+}
198
+
199
+// BadRequest denotes the type of this error
200
+func (isie InvalidSandboxIDError) BadRequest() {}
201
+
202
+// EndpointNotFoundError is returned when the no endpoint
203
+// with the passed endpoint id is found.
204
+type EndpointNotFoundError string
205
+
206
+func (enfe EndpointNotFoundError) Error() string {
207
+	return fmt.Sprintf("endpoint not found: %s", string(enfe))
208
+}
209
+
210
+// NotFound denotes the type of this error
211
+func (enfe EndpointNotFoundError) NotFound() {}
212
+
213
+// NonDefaultBridgeExistError is returned when a non-default
214
+// bridge config is passed but it does not already exist.
215
+type NonDefaultBridgeExistError string
216
+
217
+func (ndbee NonDefaultBridgeExistError) Error() string {
218
+	return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
219
+}
220
+
221
+// Forbidden denotes the type of this error
222
+func (ndbee NonDefaultBridgeExistError) Forbidden() {}
223
+
224
+// FixedCIDRv4Error is returned when fixed-cidrv4 configuration
225
+// failed.
226
+type FixedCIDRv4Error struct {
227
+	Net    *net.IPNet
228
+	Subnet *net.IPNet
229
+	Err    error
230
+}
231
+
232
+func (fcv4 *FixedCIDRv4Error) Error() string {
233
+	return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.Subnet, fcv4.Net, fcv4.Err)
234
+}
235
+
236
+// InternalError denotes the type of this error
237
+func (fcv4 *FixedCIDRv4Error) InternalError() {}
238
+
239
+// FixedCIDRv6Error is returned when fixed-cidrv6 configuration
240
+// failed.
241
+type FixedCIDRv6Error struct {
242
+	Net *net.IPNet
243
+	Err error
244
+}
245
+
246
+func (fcv6 *FixedCIDRv6Error) Error() string {
247
+	return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.Net, fcv6.Net, fcv6.Err)
248
+}
249
+
250
+// InternalError denotes the type of this error
251
+func (fcv6 *FixedCIDRv6Error) InternalError() {}
252
+
253
+// IPTableCfgError is returned when an unexpected ip tables configuration is entered
254
+type IPTableCfgError string
255
+
256
+func (name IPTableCfgError) Error() string {
257
+	return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
258
+}
259
+
260
+// BadRequest denotes the type of this error
261
+func (name IPTableCfgError) BadRequest() {}
262
+
263
+// InvalidIPTablesCfgError is returned when an invalid ip tables configuration is entered
264
+type InvalidIPTablesCfgError string
265
+
266
+func (action InvalidIPTablesCfgError) Error() string {
267
+	return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
268
+}
269
+
270
+// BadRequest denotes the type of this error
271
+func (action InvalidIPTablesCfgError) BadRequest() {}
272
+
273
+// IPv4AddrRangeError is returned when a valid IP address range couldn't be found.
274
+type IPv4AddrRangeError string
275
+
276
+func (name IPv4AddrRangeError) Error() string {
277
+	return fmt.Sprintf("can't find an address range for interface %q", string(name))
278
+}
279
+
280
+// BadRequest denotes the type of this error
281
+func (name IPv4AddrRangeError) BadRequest() {}
282
+
283
+// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge.
284
+type IPv4AddrAddError struct {
285
+	IP  *net.IPNet
286
+	Err error
287
+}
288
+
289
+func (ipv4 *IPv4AddrAddError) Error() string {
290
+	return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.IP, ipv4.Err)
291
+}
292
+
293
+// InternalError denotes the type of this error
294
+func (ipv4 *IPv4AddrAddError) InternalError() {}
295
+
296
+// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge.
297
+type IPv6AddrAddError struct {
298
+	IP  *net.IPNet
299
+	Err error
300
+}
301
+
302
+func (ipv6 *IPv6AddrAddError) Error() string {
303
+	return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.IP, ipv6.Err)
304
+}
305
+
306
+// InternalError denotes the type of this error
307
+func (ipv6 *IPv6AddrAddError) InternalError() {}
308
+
309
+// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured.
310
+type IPv4AddrNoMatchError struct {
311
+	IP    net.IP
312
+	CfgIP net.IP
313
+}
314
+
315
+func (ipv4 *IPv4AddrNoMatchError) Error() string {
316
+	return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.IP, ipv4.CfgIP)
317
+}
318
+
319
+// BadRequest denotes the type of this error
320
+func (ipv4 *IPv4AddrNoMatchError) BadRequest() {}
321
+
322
+// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured.
323
+type IPv6AddrNoMatchError net.IPNet
324
+
325
+func (ipv6 *IPv6AddrNoMatchError) Error() string {
326
+	return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
327
+}
328
+
329
+// BadRequest denotes the type of this error
330
+func (ipv6 *IPv6AddrNoMatchError) BadRequest() {}
331
+
332
+// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address
333
+type InvalidLinkIPAddrError string
334
+
335
+func (address InvalidLinkIPAddrError) Error() string {
336
+	return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
337
+}
338
+
339
+// BadRequest denotes the type of this error
340
+func (address InvalidLinkIPAddrError) BadRequest() {}
... ...
@@ -57,7 +57,7 @@ func linkContainers(action, parentIP, childIP string, ports []types.TransportPor
57 57
 	case "-D":
58 58
 		nfAction = iptables.Delete
59 59
 	default:
60
-		return invalidIPTablesCfgError(action)
60
+		return InvalidIPTablesCfgError(action)
61 61
 	}
62 62
 
63 63
 	ip1 := net.ParseIP(parentIP)
... ...
@@ -125,8 +125,8 @@ func TestLinkCreateTwo(t *testing.T) {
125 125
 	te2 := &testEndpoint{ifaces: []*testInterface{}}
126 126
 	err = d.CreateEndpoint("dummy", "ep", te2, nil)
127 127
 	if err != nil {
128
-		if err != driverapi.ErrEndpointExists {
129
-			t.Fatalf("Failed with a wrong error :%s", err.Error())
128
+		if _, ok := err.(driverapi.ErrEndpointExists); !ok {
129
+			t.Fatalf("Failed with a wrong error: %s", err.Error())
130 130
 		}
131 131
 	} else {
132 132
 		t.Fatalf("Expected to fail while trying to add same endpoint twice")
... ...
@@ -1,6 +1,8 @@
1 1
 package bridge
2 2
 
3
-import log "github.com/Sirupsen/logrus"
3
+import (
4
+	log "github.com/Sirupsen/logrus"
5
+)
4 6
 
5 7
 func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
6 8
 	addrv4, _, err := i.addresses()
... ...
@@ -10,7 +12,7 @@ func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
10 10
 
11 11
 	log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR)
12 12
 	if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil {
13
-		return &FixedCIDRv4Error{subnet: config.FixedCIDR, net: addrv4.IPNet, err: err}
13
+		return &FixedCIDRv4Error{Subnet: config.FixedCIDR, Net: addrv4.IPNet, Err: err}
14 14
 	}
15 15
 
16 16
 	return nil
... ...
@@ -1,11 +1,13 @@
1 1
 package bridge
2 2
 
3
-import log "github.com/Sirupsen/logrus"
3
+import (
4
+	log "github.com/Sirupsen/logrus"
5
+)
4 6
 
5 7
 func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error {
6 8
 	log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
7 9
 	if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil {
8
-		return &FixedCIDRv6Error{net: config.FixedCIDRv6, err: err}
10
+		return &FixedCIDRv6Error{Net: config.FixedCIDRv6, Err: err}
9 11
 	}
10 12
 
11 13
 	return nil
... ...
@@ -13,7 +13,7 @@ const (
13 13
 func setupIPForwarding(config *Configuration) error {
14 14
 	// Sanity Check
15 15
 	if config.EnableIPForwarding == false {
16
-		return ErrIPFwdCfg
16
+		return &ErrIPFwdCfg{}
17 17
 	}
18 18
 
19 19
 	// Enable IPv4 forwarding
... ...
@@ -47,7 +47,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
47 47
 		t.Fatal("Setup IP forwarding was expected to fail")
48 48
 	}
49 49
 
50
-	if err != ErrIPFwdCfg {
50
+	if _, ok := err.(*ErrIPFwdCfg); !ok {
51 51
 		t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err)
52 52
 	}
53 53
 }
... ...
@@ -16,7 +16,7 @@ const (
16 16
 func setupIPTables(config *NetworkConfiguration, i *bridgeInterface) error {
17 17
 	// Sanity check.
18 18
 	if config.EnableIPTables == false {
19
-		return ipTableCfgError(config.BridgeName)
19
+		return IPTableCfgError(config.BridgeName)
20 20
 	}
21 21
 
22 22
 	hairpinMode := !config.EnableUserlandProxy
... ...
@@ -71,7 +71,7 @@ func setupBridgeIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
71 71
 
72 72
 	log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4)
73 73
 	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil {
74
-		return &IPv4AddrAddError{ip: bridgeIPv4, err: err}
74
+		return &IPv4AddrAddError{IP: bridgeIPv4, Err: err}
75 75
 	}
76 76
 
77 77
 	// Store bridge network and default gateway
... ...
@@ -114,7 +114,7 @@ func electBridgeIPv4(config *NetworkConfiguration) (*net.IPNet, error) {
114 114
 
115 115
 func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
116 116
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
117
-		return ErrInvalidGateway
117
+		return &ErrInvalidGateway{}
118 118
 	}
119 119
 	if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
120 120
 		return err
... ...
@@ -37,7 +37,7 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
37 37
 	// Add the default link local ipv6 address if it doesn't exist
38 38
 	if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
39 39
 		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
40
-			return &IPv6AddrAddError{ip: bridgeIPv6, err: err}
40
+			return &IPv6AddrAddError{IP: bridgeIPv6, Err: err}
41 41
 		}
42 42
 	}
43 43
 
... ...
@@ -50,10 +50,10 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
50 50
 
51 51
 func setupGatewayIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
52 52
 	if config.FixedCIDRv6 == nil {
53
-		return ErrInvalidContainerSubnet
53
+		return &ErrInvalidContainerSubnet{}
54 54
 	}
55 55
 	if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
56
-		return ErrInvalidGateway
56
+		return &ErrInvalidGateway{}
57 57
 	}
58 58
 	if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
59 59
 		return err
... ...
@@ -1,6 +1,8 @@
1 1
 package bridge
2 2
 
3
-import "github.com/vishvananda/netlink"
3
+import (
4
+	"github.com/vishvananda/netlink"
5
+)
4 6
 
5 7
 func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error {
6 8
 	// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
... ...
@@ -11,12 +13,12 @@ func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) e
11 11
 
12 12
 	// Verify that the bridge does have an IPv4 address.
13 13
 	if addrv4.IPNet == nil {
14
-		return ErrNoIPAddr
14
+		return &ErrNoIPAddr{}
15 15
 	}
16 16
 
17 17
 	// Verify that the bridge IPv4 address matches the requested configuration.
18 18
 	if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
19
-		return &IPv4AddrNoMatchError{ip: addrv4.IP, cfgIP: config.AddressIPv4.IP}
19
+		return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP}
20 20
 	}
21 21
 
22 22
 	// Verify that one of the bridge IPv6 addresses matches the requested
... ...
@@ -31,37 +31,37 @@ func Init(dc driverapi.DriverCallback) error {
31 31
 }
32 32
 
33 33
 func (d *driver) Config(option map[string]interface{}) error {
34
-	return driverapi.ErrNotImplemented
34
+	return &driverapi.ErrNotImplemented{}
35 35
 }
36 36
 
37 37
 func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
38
-	return driverapi.ErrNotImplemented
38
+	return &driverapi.ErrNotImplemented{}
39 39
 }
40 40
 
41 41
 func (d *driver) DeleteNetwork(nid types.UUID) error {
42
-	return driverapi.ErrNotImplemented
42
+	return &driverapi.ErrNotImplemented{}
43 43
 }
44 44
 
45 45
 func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
46
-	return driverapi.ErrNotImplemented
46
+	return &driverapi.ErrNotImplemented{}
47 47
 }
48 48
 
49 49
 func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
50
-	return driverapi.ErrNotImplemented
50
+	return &driverapi.ErrNotImplemented{}
51 51
 }
52 52
 
53 53
 func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
54
-	return nil, driverapi.ErrNotImplemented
54
+	return nil, &driverapi.ErrNotImplemented{}
55 55
 }
56 56
 
57 57
 // Join method is invoked when a Sandbox is attached to an endpoint.
58 58
 func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
59
-	return driverapi.ErrNotImplemented
59
+	return &driverapi.ErrNotImplemented{}
60 60
 }
61 61
 
62 62
 // Leave method is invoked when a Sandbox detaches from an endpoint.
63 63
 func (d *driver) Leave(nid, eid types.UUID) error {
64
-	return driverapi.ErrNotImplemented
64
+	return &driverapi.ErrNotImplemented{}
65 65
 }
66 66
 
67 67
 func (d *driver) Type() string {
... ...
@@ -216,7 +216,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai
216 216
 	ep.Lock()
217 217
 	if ep.container != nil {
218 218
 		ep.Unlock()
219
-		return nil, ErrInvalidJoin
219
+		return nil, ErrInvalidJoin{}
220 220
 	}
221 221
 
222 222
 	ep.container = &containerInfo{
... ...
@@ -334,7 +334,7 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
334 334
 	if container == nil || container.id == "" ||
335 335
 		containerID == "" || container.id != containerID {
336 336
 		if container == nil {
337
-			err = ErrNoContainer
337
+			err = ErrNoContainer{}
338 338
 		} else {
339 339
 			err = InvalidContainerIDError(containerID)
340 340
 		}
... ...
@@ -412,7 +412,7 @@ func (ep *endpoint) buildHostsFiles() error {
412 412
 	ep.Unlock()
413 413
 
414 414
 	if container == nil {
415
-		return ErrNoContainer
415
+		return ErrNoContainer{}
416 416
 	}
417 417
 
418 418
 	if container.config.hostsPath == "" {
... ...
@@ -462,7 +462,7 @@ func (ep *endpoint) updateParentHosts() error {
462 462
 	ep.Unlock()
463 463
 
464 464
 	if container == nil {
465
-		return ErrNoContainer
465
+		return ErrNoContainer{}
466 466
 	}
467 467
 
468 468
 	for _, update := range container.config.parentUpdates {
... ...
@@ -495,7 +495,7 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error {
495 495
 	ep.Unlock()
496 496
 
497 497
 	if container == nil {
498
-		return ErrNoContainer
498
+		return ErrNoContainer{}
499 499
 	}
500 500
 
501 501
 	oldHash := []byte{}
... ...
@@ -573,7 +573,7 @@ func (ep *endpoint) setupDNS() error {
573 573
 	ep.Unlock()
574 574
 
575 575
 	if container == nil {
576
-		return ErrNoContainer
576
+		return ErrNoContainer{}
577 577
 	}
578 578
 
579 579
 	if container.config.resolvConfPath == "" {
... ...
@@ -1,34 +1,83 @@
1 1
 package libnetwork
2 2
 
3 3
 import (
4
-	"errors"
5 4
 	"fmt"
6 5
 )
7 6
 
8
-var (
9
-	// ErrNoSuchNetwork is returned when a network query finds no result
10
-	ErrNoSuchNetwork = errors.New("network not found")
11
-	// ErrNoSuchEndpoint is returned when a endpoint query finds no result
12
-	ErrNoSuchEndpoint = errors.New("endpoint not found")
13
-	// ErrNilNetworkDriver is returned if a nil network driver
14
-	// is passed to NewNetwork api.
15
-	ErrNilNetworkDriver = errors.New("nil NetworkDriver instance")
16
-	// ErrInvalidNetworkDriver is returned if an invalid driver
17
-	// instance is passed.
18
-	ErrInvalidNetworkDriver = errors.New("invalid driver bound to network")
19
-	// ErrInvalidJoin is returned if a join is attempted on an endpoint
20
-	// which already has a container joined.
21
-	ErrInvalidJoin = errors.New("a container has already joined the endpoint")
22
-	// ErrNoContainer is returned when the endpoint has no container
23
-	// attached to it.
24
-	ErrNoContainer = errors.New("no container attached to the endpoint")
25
-	// ErrInvalidID is returned when a query-by-id method is being invoked
26
-	// with an empty id parameter
27
-	ErrInvalidID = errors.New("invalid ID")
28
-	// ErrInvalidName is returned when a query-by-name or resource create method is
29
-	// invoked with an empty name parameter
30
-	ErrInvalidName = errors.New("invalid Name")
31
-)
7
+// ErrNoSuchNetwork is returned when a network query finds no result
8
+type ErrNoSuchNetwork string
9
+
10
+func (nsn ErrNoSuchNetwork) Error() string {
11
+	return fmt.Sprintf("network %s not found", string(nsn))
12
+}
13
+
14
+// BadRequest denotes the type of this error
15
+func (nsn ErrNoSuchNetwork) BadRequest() {}
16
+
17
+// ErrNoSuchEndpoint is returned when a endpoint query finds no result
18
+type ErrNoSuchEndpoint string
19
+
20
+func (nse ErrNoSuchEndpoint) Error() string {
21
+	return fmt.Sprintf("endpoint %s not found", string(nse))
22
+}
23
+
24
+// BadRequest denotes the type of this error
25
+func (nse ErrNoSuchEndpoint) BadRequest() {}
26
+
27
+// ErrInvalidNetworkDriver is returned if an invalid driver
28
+// name is passed.
29
+type ErrInvalidNetworkDriver string
30
+
31
+func (ind ErrInvalidNetworkDriver) Error() string {
32
+	return fmt.Sprintf("invalid driver bound to network: %s", string(ind))
33
+}
34
+
35
+// BadRequest denotes the type of this error
36
+func (ind ErrInvalidNetworkDriver) BadRequest() {}
37
+
38
+// ErrInvalidJoin is returned if a join is attempted on an endpoint
39
+// which already has a container joined.
40
+type ErrInvalidJoin struct{}
41
+
42
+func (ij ErrInvalidJoin) Error() string {
43
+	return "a container has already joined the endpoint"
44
+}
45
+
46
+// BadRequest denotes the type of this error
47
+func (ij ErrInvalidJoin) BadRequest() {}
48
+
49
+// ErrNoContainer is returned when the endpoint has no container
50
+// attached to it.
51
+type ErrNoContainer struct{}
52
+
53
+func (nc ErrNoContainer) Error() string {
54
+	return "a container has already joined the endpoint"
55
+}
56
+
57
+// Maskable denotes the type of this error
58
+func (nc ErrNoContainer) Maskable() {}
59
+
60
+// ErrInvalidID is returned when a query-by-id method is being invoked
61
+// with an empty id parameter
62
+type ErrInvalidID string
63
+
64
+func (ii ErrInvalidID) Error() string {
65
+	return fmt.Sprintf("invalid id: %s", string(ii))
66
+}
67
+
68
+// BadRequest denotes the type of this error
69
+func (ii ErrInvalidID) BadRequest() {}
70
+
71
+// ErrInvalidName is returned when a query-by-name or resource create method is
72
+// invoked with an empty name parameter
73
+type ErrInvalidName string
74
+
75
+func (in ErrInvalidName) Error() string {
76
+	return fmt.Sprintf("invalid name: %s", string(in))
77
+}
78
+
79
+// BadRequest denotes the type of this error
80
+func (in ErrInvalidName) BadRequest() {}
32 81
 
33 82
 // NetworkTypeError type is returned when the network type string is not
34 83
 // known to libnetwork.
... ...
@@ -38,13 +87,19 @@ func (nt NetworkTypeError) Error() string {
38 38
 	return fmt.Sprintf("unknown driver %q", string(nt))
39 39
 }
40 40
 
41
+// NotFound denotes the type of this error
42
+func (nt NetworkTypeError) NotFound() {}
43
+
41 44
 // NetworkNameError is returned when a network with the same name already exists.
42 45
 type NetworkNameError string
43 46
 
44
-func (name NetworkNameError) Error() string {
45
-	return fmt.Sprintf("network with name %s already exists", string(name))
47
+func (nnr NetworkNameError) Error() string {
48
+	return fmt.Sprintf("network with name %s already exists", string(nnr))
46 49
 }
47 50
 
51
+// Forbidden denotes the type of this error
52
+func (nnr NetworkNameError) Forbidden() {}
53
+
48 54
 // UnknownNetworkError is returned when libnetwork could not find in it's database
49 55
 // a network with the same name and id.
50 56
 type UnknownNetworkError struct {
... ...
@@ -56,6 +111,9 @@ func (une *UnknownNetworkError) Error() string {
56 56
 	return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
57 57
 }
58 58
 
59
+// NotFound denotes the type of this error
60
+func (une *UnknownNetworkError) NotFound() {}
61
+
59 62
 // ActiveEndpointsError is returned when a network is deleted which has active
60 63
 // endpoints in it.
61 64
 type ActiveEndpointsError struct {
... ...
@@ -67,6 +125,9 @@ func (aee *ActiveEndpointsError) Error() string {
67 67
 	return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id)
68 68
 }
69 69
 
70
+// Forbidden denotes the type of this error
71
+func (aee *ActiveEndpointsError) Forbidden() {}
72
+
70 73
 // UnknownEndpointError is returned when libnetwork could not find in it's database
71 74
 // an endpoint with the same name and id.
72 75
 type UnknownEndpointError struct {
... ...
@@ -78,6 +139,9 @@ func (uee *UnknownEndpointError) Error() string {
78 78
 	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
79 79
 }
80 80
 
81
+// NotFound denotes the type of this error
82
+func (uee *UnknownEndpointError) NotFound() {}
83
+
81 84
 // ActiveContainerError is returned when an endpoint is deleted which has active
82 85
 // containers attached to it.
83 86
 type ActiveContainerError struct {
... ...
@@ -89,6 +153,9 @@ func (ace *ActiveContainerError) Error() string {
89 89
 	return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id)
90 90
 }
91 91
 
92
+// Forbidden denotes the type of this error
93
+func (ace *ActiveContainerError) Forbidden() {}
94
+
92 95
 // InvalidContainerIDError is returned when an invalid container id is passed
93 96
 // in Join/Leave
94 97
 type InvalidContainerIDError string
... ...
@@ -96,3 +163,6 @@ type InvalidContainerIDError string
96 96
 func (id InvalidContainerIDError) Error() string {
97 97
 	return fmt.Sprintf("invalid container id %s", string(id))
98 98
 }
99
+
100
+// BadRequest denotes the type of this error
101
+func (id InvalidContainerIDError) BadRequest() {}
99 102
new file mode 100644
... ...
@@ -0,0 +1,51 @@
0
+package libnetwork
1
+
2
+import (
3
+	"testing"
4
+
5
+	"github.com/docker/libnetwork/types"
6
+)
7
+
8
+func TestErrorInterfaces(t *testing.T) {
9
+
10
+	badRequestErrorList := []error{ErrInvalidID(""), ErrInvalidName(""), ErrInvalidJoin{}, ErrInvalidNetworkDriver(""), InvalidContainerIDError(""), ErrNoSuchNetwork(""), ErrNoSuchEndpoint("")}
11
+	for _, err := range badRequestErrorList {
12
+		switch u := err.(type) {
13
+		case types.BadRequestError:
14
+			return
15
+		default:
16
+			t.Fatalf("Failed to detect err %v is of type BadRequestError. Got type: %T", err, u)
17
+		}
18
+	}
19
+
20
+	maskableErrorList := []error{ErrNoContainer{}}
21
+	for _, err := range maskableErrorList {
22
+		switch u := err.(type) {
23
+		case types.MaskableError:
24
+			return
25
+		default:
26
+			t.Fatalf("Failed to detect err %v is of type MaskableError. Got type: %T", err, u)
27
+		}
28
+	}
29
+
30
+	notFoundErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
31
+	for _, err := range notFoundErrorList {
32
+		switch u := err.(type) {
33
+		case types.NotFoundError:
34
+			return
35
+		default:
36
+			t.Fatalf("Failed to detect err %v is of type NotFoundError. Got type: %T", err, u)
37
+		}
38
+	}
39
+
40
+	forbiddenErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
41
+	for _, err := range forbiddenErrorList {
42
+		switch u := err.(type) {
43
+		case types.ForbiddenError:
44
+			return
45
+		default:
46
+			t.Fatalf("Failed to detect err %v is of type ForbiddenError. Got type: %T", err, u)
47
+		}
48
+	}
49
+
50
+}
... ...
@@ -11,7 +11,7 @@ import (
11 11
 	_ "github.com/docker/libnetwork/netutils"
12 12
 )
13 13
 
14
-const chainName = "DOCKER-TEST"
14
+const chainName = "DOCKEREST"
15 15
 
16 16
 var natChain *Chain
17 17
 var filterChain *Chain
... ...
@@ -290,7 +290,7 @@ func TestNilRemoteDriver(t *testing.T) {
290 290
 		t.Fatal("Expected to fail. But instead succeeded")
291 291
 	}
292 292
 
293
-	if err != plugins.ErrNotFound {
293
+	if _, ok := err.(types.NotFoundError); !ok {
294 294
 		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
295 295
 	}
296 296
 }
... ...
@@ -338,8 +338,9 @@ func TestNetworkName(t *testing.T) {
338 338
 	if err == nil {
339 339
 		t.Fatal("Expected to fail. But instead succeeded")
340 340
 	}
341
-	if err != libnetwork.ErrInvalidName {
342
-		t.Fatal("Expected to fail with ErrInvalidName error")
341
+
342
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
343
+		t.Fatalf("Expected to fail with ErrInvalidName error. Got %v", err)
343 344
 	}
344 345
 
345 346
 	networkName := "testnetwork"
... ...
@@ -475,8 +476,8 @@ func TestUnknownEndpoint(t *testing.T) {
475 475
 	if err == nil {
476 476
 		t.Fatal("Expected to fail. But instead succeeded")
477 477
 	}
478
-	if err != libnetwork.ErrInvalidName {
479
-		t.Fatal("Expected to fail with ErrInvalidName error")
478
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
479
+		t.Fatalf("Expected to fail with ErrInvalidName error. Actual error: %v", err)
480 480
 	}
481 481
 
482 482
 	ep, err := network.CreateEndpoint("testep")
... ...
@@ -613,15 +614,15 @@ func TestControllerQuery(t *testing.T) {
613 613
 	if err == nil {
614 614
 		t.Fatalf("NetworkByName() succeeded with invalid target name")
615 615
 	}
616
-	if err != libnetwork.ErrInvalidName {
617
-		t.Fatalf("NetworkByName() failed with unexpected error: %v", err)
616
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
617
+		t.Fatalf("Expected NetworkByName() to fail with ErrInvalidName error. Got: %v", err)
618 618
 	}
619 619
 
620 620
 	_, err = controller.NetworkByID("")
621 621
 	if err == nil {
622 622
 		t.Fatalf("NetworkByID() succeeded with invalid target id")
623 623
 	}
624
-	if err != libnetwork.ErrInvalidID {
624
+	if _, ok := err.(libnetwork.ErrInvalidID); !ok {
625 625
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
626 626
 	}
627 627
 
... ...
@@ -629,7 +630,7 @@ func TestControllerQuery(t *testing.T) {
629 629
 	if err == nil {
630 630
 		t.Fatalf("Unexpected success for NetworkByID(): %v", g)
631 631
 	}
632
-	if err != libnetwork.ErrNoSuchNetwork {
632
+	if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok {
633 633
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
634 634
 	}
635 635
 
... ...
@@ -695,15 +696,15 @@ func TestNetworkQuery(t *testing.T) {
695 695
 	if err == nil {
696 696
 		t.Fatalf("EndpointByName() succeeded with invalid target name")
697 697
 	}
698
-	if err != libnetwork.ErrInvalidName {
699
-		t.Fatalf("EndpointByName() failed with unexpected error: %v", err)
698
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
699
+		t.Fatalf("Expected EndpointByName() to fail with ErrInvalidName error. Got: %v", err)
700 700
 	}
701 701
 
702 702
 	e, err = net1.EndpointByName("IamNotAnEndpoint")
703 703
 	if err == nil {
704 704
 		t.Fatalf("EndpointByName() succeeded with unknown target name")
705 705
 	}
706
-	if err != libnetwork.ErrNoSuchEndpoint {
706
+	if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
707 707
 		t.Fatal(err)
708 708
 	}
709 709
 	if e != nil {
... ...
@@ -722,7 +723,7 @@ func TestNetworkQuery(t *testing.T) {
722 722
 	if err == nil {
723 723
 		t.Fatalf("EndpointByID() succeeded with invalid target id")
724 724
 	}
725
-	if err != libnetwork.ErrInvalidID {
725
+	if _, ok := err.(libnetwork.ErrInvalidID); !ok {
726 726
 		t.Fatalf("EndpointByID() failed with unexpected error: %v", err)
727 727
 	}
728 728
 }
... ...
@@ -891,7 +892,7 @@ func TestEndpointMultipleJoins(t *testing.T) {
891 891
 		t.Fatal("Expected to fail multiple joins for the same endpoint")
892 892
 	}
893 893
 
894
-	if err != libnetwork.ErrInvalidJoin {
894
+	if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
895 895
 		t.Fatalf("Failed for unexpected reason: %v", err)
896 896
 	}
897 897
 }
... ...
@@ -917,7 +918,7 @@ func TestEndpointInvalidLeave(t *testing.T) {
917 917
 	}
918 918
 
919 919
 	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
920
-		if err != libnetwork.ErrNoContainer {
920
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
921 921
 			t.Fatalf("Failed for unexpected reason: %v", err)
922 922
 		}
923 923
 	}
... ...
@@ -1297,8 +1298,10 @@ func TestValidRemoteDriver(t *testing.T) {
1297 1297
 
1298 1298
 	_, err = controller.NewNetwork("valid-network-driver", "dummy",
1299 1299
 		libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
1300
-	if err != nil && err != driverapi.ErrNotImplemented {
1301
-		t.Fatal(err)
1300
+	if err != nil {
1301
+		if _, ok := err.(*driverapi.ErrNotImplemented); !ok {
1302
+			t.Fatal(err)
1303
+		}
1302 1304
 	}
1303 1305
 }
1304 1306
 
... ...
@@ -1371,8 +1374,10 @@ func parallelJoin(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
1371 1371
 	_, err := ep.Join("racing_container")
1372 1372
 	runtime.LockOSThread()
1373 1373
 	if err != nil {
1374
-		if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin {
1375
-			t.Fatal(err)
1374
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
1375
+			if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
1376
+				t.Fatal(err)
1377
+			}
1376 1378
 		}
1377 1379
 		debugf("JE%d(%v).", thrNumber, err)
1378 1380
 	}
... ...
@@ -1384,8 +1389,10 @@ func parallelLeave(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
1384 1384
 	err := ep.Leave("racing_container")
1385 1385
 	runtime.LockOSThread()
1386 1386
 	if err != nil {
1387
-		if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin {
1388
-			t.Fatal(err)
1387
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
1388
+			if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
1389
+				t.Fatal(err)
1390
+			}
1389 1391
 		}
1390 1392
 		debugf("LE%d(%v).", thrNumber, err)
1391 1393
 	}
... ...
@@ -133,7 +133,7 @@ func (n *network) Delete() error {
133 133
 
134 134
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
135 135
 	if name == "" {
136
-		return nil, ErrInvalidName
136
+		return nil, ErrInvalidName(name)
137 137
 	}
138 138
 	ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})}
139 139
 	ep.id = types.UUID(stringid.GenerateRandomID())
... ...
@@ -173,7 +173,7 @@ func (n *network) WalkEndpoints(walker EndpointWalker) {
173 173
 
174 174
 func (n *network) EndpointByName(name string) (Endpoint, error) {
175 175
 	if name == "" {
176
-		return nil, ErrInvalidName
176
+		return nil, ErrInvalidName(name)
177 177
 	}
178 178
 	var e Endpoint
179 179
 
... ...
@@ -188,7 +188,7 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
188 188
 	n.WalkEndpoints(s)
189 189
 
190 190
 	if e == nil {
191
-		return nil, ErrNoSuchEndpoint
191
+		return nil, ErrNoSuchEndpoint(name)
192 192
 	}
193 193
 
194 194
 	return e, nil
... ...
@@ -196,12 +196,12 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
196 196
 
197 197
 func (n *network) EndpointByID(id string) (Endpoint, error) {
198 198
 	if id == "" {
199
-		return nil, ErrInvalidID
199
+		return nil, ErrInvalidID(id)
200 200
 	}
201 201
 	n.Lock()
202 202
 	defer n.Unlock()
203 203
 	if e, ok := n.endpoints[types.UUID(id)]; ok {
204 204
 		return e, nil
205 205
 	}
206
-	return nil, ErrNoSuchEndpoint
206
+	return nil, ErrNoSuchEndpoint(id)
207 207
 }
... ...
@@ -11,13 +11,6 @@ import (
11 11
 // UUID represents a globally unique ID of various resources like network and endpoint
12 12
 type UUID string
13 13
 
14
-// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid.
15
-type ErrInvalidProtocolBinding string
16
-
17
-func (ipb ErrInvalidProtocolBinding) Error() string {
18
-	return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
19
-}
20
-
21 14
 // TransportPort represent a local Layer 4 endpoint
22 15
 type TransportPort struct {
23 16
 	Proto Protocol
... ...
@@ -110,6 +103,13 @@ func (p *PortBinding) Equal(o *PortBinding) bool {
110 110
 	return true
111 111
 }
112 112
 
113
+// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid.
114
+type ErrInvalidProtocolBinding string
115
+
116
+func (ipb ErrInvalidProtocolBinding) Error() string {
117
+	return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
118
+}
119
+
113 120
 const (
114 121
 	// ICMP is for the ICMP ip protocol
115 122
 	ICMP = 1
... ...
@@ -183,3 +183,163 @@ func CompareIPNet(a, b *net.IPNet) bool {
183 183
 	}
184 184
 	return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
185 185
 }
186
+
187
+/******************************
188
+ * Well-known Error Interfaces
189
+ ******************************/
190
+
191
+// MaskableError is an interface for errors which can be ignored by caller
192
+type MaskableError interface {
193
+	// Maskable makes implementer into MaskableError type
194
+	Maskable()
195
+}
196
+
197
+// BadRequestError is an interface for errors originated by a bad request
198
+type BadRequestError interface {
199
+	// BadRequest makes implementer into BadRequestError type
200
+	BadRequest()
201
+}
202
+
203
+// NotFoundError is an interface for errors raised because a needed resource is not available
204
+type NotFoundError interface {
205
+	// NotFound makes implementer into NotFoundError type
206
+	NotFound()
207
+}
208
+
209
+// ForbiddenError is an interface for errors which denote an valid request that cannot be honored
210
+type ForbiddenError interface {
211
+	// Forbidden makes implementer into ForbiddenError type
212
+	Forbidden()
213
+}
214
+
215
+// NoServiceError  is an interface for errors returned when the required service is not available
216
+type NoServiceError interface {
217
+	// NoService makes implementer into NoServiceError type
218
+	NoService()
219
+}
220
+
221
+// TimeoutError  is an interface for errors raised because of timeout
222
+type TimeoutError interface {
223
+	// Timeout makes implementer into TimeoutError type
224
+	Timeout()
225
+}
226
+
227
+// NotImplementedError  is an interface for errors raised because of requested functionality is not yet implemented
228
+type NotImplementedError interface {
229
+	// NotImplemented makes implementer into NotImplementedError type
230
+	NotImplemented()
231
+}
232
+
233
+// InternalError is an interface for errors raised because of an internal error
234
+type InternalError interface {
235
+	// Internal makes implementer into InternalError type
236
+	Internal()
237
+}
238
+
239
+/******************************
240
+ * Weel-known Error Formatters
241
+ ******************************/
242
+
243
+// BadRequestErrorf creates an instance of BadRequestError
244
+func BadRequestErrorf(format string, params ...interface{}) error {
245
+	return badRequest(fmt.Sprintf(format, params...))
246
+}
247
+
248
+// NotFoundErrorf creates an instance of NotFoundError
249
+func NotFoundErrorf(format string, params ...interface{}) error {
250
+	return notFound(fmt.Sprintf(format, params...))
251
+}
252
+
253
+// ForbiddenErrorf creates an instance of ForbiddenError
254
+func ForbiddenErrorf(format string, params ...interface{}) error {
255
+	return forbidden(fmt.Sprintf(format, params...))
256
+}
257
+
258
+// NoServiceErrorf creates an instance of NoServiceError
259
+func NoServiceErrorf(format string, params ...interface{}) error {
260
+	return noService(fmt.Sprintf(format, params...))
261
+}
262
+
263
+// NotImplementedErrorf creates an instance of NotImplementedError
264
+func NotImplementedErrorf(format string, params ...interface{}) error {
265
+	return notImpl(fmt.Sprintf(format, params...))
266
+}
267
+
268
+// TimeoutErrorf creates an instance of TimeoutError
269
+func TimeoutErrorf(format string, params ...interface{}) error {
270
+	return timeout(fmt.Sprintf(format, params...))
271
+}
272
+
273
+// InternalErrorf creates an instance of InternalError
274
+func InternalErrorf(format string, params ...interface{}) error {
275
+	return internal(fmt.Sprintf(format, params...))
276
+}
277
+
278
+// InternalMaskableErrorf creates an instance of InternalError and MaskableError
279
+func InternalMaskableErrorf(format string, params ...interface{}) error {
280
+	return maskInternal(fmt.Sprintf(format, params...))
281
+}
282
+
283
+/***********************
284
+ * Internal Error Types
285
+ ***********************/
286
+type badRequest string
287
+
288
+func (br badRequest) Error() string {
289
+	return string(br)
290
+}
291
+func (br badRequest) BadRequest() {}
292
+
293
+type maskBadRequest string
294
+
295
+type notFound string
296
+
297
+func (nf notFound) Error() string {
298
+	return string(nf)
299
+}
300
+func (nf notFound) NotFound() {}
301
+
302
+type forbidden string
303
+
304
+func (frb forbidden) Error() string {
305
+	return string(frb)
306
+}
307
+func (frb forbidden) Forbidden() {}
308
+
309
+type noService string
310
+
311
+func (ns noService) Error() string {
312
+	return string(ns)
313
+}
314
+func (ns noService) NoService() {}
315
+
316
+type maskNoService string
317
+
318
+type timeout string
319
+
320
+func (to timeout) Error() string {
321
+	return string(to)
322
+}
323
+func (to timeout) Timeout() {}
324
+
325
+type notImpl string
326
+
327
+func (ni notImpl) Error() string {
328
+	return string(ni)
329
+}
330
+func (ni notImpl) NotImplemented() {}
331
+
332
+type internal string
333
+
334
+func (nt internal) Error() string {
335
+	return string(nt)
336
+}
337
+func (nt internal) Internal() {}
338
+
339
+type maskInternal string
340
+
341
+func (mnt maskInternal) Error() string {
342
+	return string(mnt)
343
+}
344
+func (mnt maskInternal) Internal() {}
345
+func (mnt maskInternal) Maskable() {}
186 346
new file mode 100644
... ...
@@ -0,0 +1,99 @@
0
+package types
1
+
2
+import (
3
+	"testing"
4
+
5
+	_ "github.com/docker/libnetwork/netutils"
6
+)
7
+
8
+func TestErrorConstructors(t *testing.T) {
9
+	var err error
10
+
11
+	err = BadRequestErrorf("Io ho %d uccello", 1)
12
+	if err.Error() != "Io ho 1 uccello" {
13
+		t.Fatal(err)
14
+	}
15
+	if _, ok := err.(BadRequestError); !ok {
16
+		t.Fatal(err)
17
+	}
18
+	if _, ok := err.(MaskableError); ok {
19
+		t.Fatal(err)
20
+	}
21
+
22
+	err = NotFoundErrorf("Can't find the %s", "keys")
23
+	if err.Error() != "Can't find the keys" {
24
+		t.Fatal(err)
25
+	}
26
+	if _, ok := err.(NotFoundError); !ok {
27
+		t.Fatal(err)
28
+	}
29
+	if _, ok := err.(MaskableError); ok {
30
+		t.Fatal(err)
31
+	}
32
+
33
+	err = ForbiddenErrorf("Can't open door %d", 2)
34
+	if err.Error() != "Can't open door 2" {
35
+		t.Fatal(err)
36
+	}
37
+	if _, ok := err.(ForbiddenError); !ok {
38
+		t.Fatal(err)
39
+	}
40
+	if _, ok := err.(MaskableError); ok {
41
+		t.Fatal(err)
42
+	}
43
+
44
+	err = NotImplementedErrorf("Functionality %s is not implemented", "x")
45
+	if err.Error() != "Functionality x is not implemented" {
46
+		t.Fatal(err)
47
+	}
48
+	if _, ok := err.(NotImplementedError); !ok {
49
+		t.Fatal(err)
50
+	}
51
+	if _, ok := err.(MaskableError); ok {
52
+		t.Fatal(err)
53
+	}
54
+
55
+	err = TimeoutErrorf("Process %s timed out", "abc")
56
+	if err.Error() != "Process abc timed out" {
57
+		t.Fatal(err)
58
+	}
59
+	if _, ok := err.(TimeoutError); !ok {
60
+		t.Fatal(err)
61
+	}
62
+	if _, ok := err.(MaskableError); ok {
63
+		t.Fatal(err)
64
+	}
65
+
66
+	err = NoServiceErrorf("Driver %s is not available", "mh")
67
+	if err.Error() != "Driver mh is not available" {
68
+		t.Fatal(err)
69
+	}
70
+	if _, ok := err.(NoServiceError); !ok {
71
+		t.Fatal(err)
72
+	}
73
+	if _, ok := err.(MaskableError); ok {
74
+		t.Fatal(err)
75
+	}
76
+
77
+	err = InternalErrorf("Not sure what happened")
78
+	if err.Error() != "Not sure what happened" {
79
+		t.Fatal(err)
80
+	}
81
+	if _, ok := err.(InternalError); !ok {
82
+		t.Fatal(err)
83
+	}
84
+	if _, ok := err.(MaskableError); ok {
85
+		t.Fatal(err)
86
+	}
87
+
88
+	err = InternalMaskableErrorf("Minor issue, it can be ignored")
89
+	if err.Error() != "Minor issue, it can be ignored" {
90
+		t.Fatal(err)
91
+	}
92
+	if _, ok := err.(InternalError); !ok {
93
+		t.Fatal(err)
94
+	}
95
+	if _, ok := err.(MaskableError); !ok {
96
+		t.Fatal(err)
97
+	}
98
+}