Browse Source

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 10 years ago
parent
commit
c70cfcb150

+ 23 - 5
libnetwork/api/api.go

@@ -7,6 +7,7 @@ import (
 	"net/http"
 	"net/http"
 
 
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork"
+	"github.com/docker/libnetwork/types"
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 )
 )
 
 
@@ -434,7 +435,7 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N
 		panic(fmt.Sprintf("unexpected selector for network search: %d", by))
 		panic(fmt.Sprintf("unexpected selector for network search: %d", by))
 	}
 	}
 	if err != nil {
 	if err != nil {
-		if err == libnetwork.ErrNoSuchNetwork {
+		if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
 			return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound}
 			return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound}
 		}
 		}
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
@@ -460,7 +461,7 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int)
 		panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
 		panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
 	}
 	}
 	if err != nil {
 	if err != nil {
-		if err == libnetwork.ErrNoSuchEndpoint {
+		if _, ok := err.(libnetwork.ErrNoSuchEndpoint); ok {
 			return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
 			return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
 		}
 		}
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
@@ -469,9 +470,26 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int)
 }
 }
 
 
 func convertNetworkError(err error) *responseStatus {
 func convertNetworkError(err error) *responseStatus {
-	// No real libnetwork error => http error code conversion for now.
-	// Will came in later when new interface for libnetwork error is vailable
-	return &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
+	var code int
+	switch err.(type) {
+	case types.BadRequestError:
+		code = http.StatusBadRequest
+	case types.ForbiddenError:
+		code = http.StatusForbidden
+	case types.NotFoundError:
+		code = http.StatusNotFound
+	case types.TimeoutError:
+		code = http.StatusRequestTimeout
+	case types.NotImplementedError:
+		code = http.StatusNotImplemented
+	case types.NoServiceError:
+		code = http.StatusServiceUnavailable
+	case types.InternalError:
+		code = http.StatusInternalServerError
+	default:
+		code = http.StatusInternalServerError
+	}
+	return &responseStatus{Status: err.Error(), StatusCode: code}
 }
 }
 
 
 func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
 func writeJSON(w http.ResponseWriter, code int, v interface{}) error {

+ 91 - 2
libnetwork/api/api_test.go

@@ -193,8 +193,8 @@ func TestCreateDeleteNetwork(t *testing.T) {
 	if errRsp == &createdResponse {
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 		t.Fatalf("Expected to fail but succeeded")
 	}
 	}
-	if errRsp.StatusCode != http.StatusBadRequest {
-		t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
+	if errRsp.StatusCode != http.StatusNotFound {
+		t.Fatalf("Expected StatusNotFound status code, got: %v", errRsp)
 	}
 	}
 
 
 	ops := make(map[string]interface{})
 	ops := make(map[string]interface{})
@@ -1305,3 +1305,92 @@ func TestHttpHandlerGood(t *testing.T) {
 		t.Fatalf("Incongruent resource found")
 		t.Fatalf("Incongruent resource found")
 	}
 	}
 }
 }
+
+type bre struct{}
+
+func (b *bre) Error() string {
+	return "I am a bad request error"
+}
+func (b *bre) BadRequest() {}
+
+type nfe struct{}
+
+func (n *nfe) Error() string {
+	return "I am a not found error"
+}
+func (n *nfe) NotFound() {}
+
+type forb struct{}
+
+func (f *forb) Error() string {
+	return "I am a bad request error"
+}
+func (f *forb) Forbidden() {}
+
+type notimpl struct{}
+
+func (nip *notimpl) Error() string {
+	return "I am a not implemented error"
+}
+func (nip *notimpl) NotImplemented() {}
+
+type inter struct{}
+
+func (it *inter) Error() string {
+	return "I am a internal error"
+}
+func (it *inter) Internal() {}
+
+type tout struct{}
+
+func (to *tout) Error() string {
+	return "I am a timeout error"
+}
+func (to *tout) Timeout() {}
+
+type noserv struct{}
+
+func (nos *noserv) Error() string {
+	return "I am a no service error"
+}
+func (nos *noserv) NoService() {}
+
+type notclassified struct{}
+
+func (noc *notclassified) Error() string {
+	return "I am a non classified error"
+}
+
+func TestErrorConversion(t *testing.T) {
+	if convertNetworkError(new(bre)).StatusCode != http.StatusBadRequest {
+		t.Fatalf("Failed to recognize BadRequest error")
+	}
+
+	if convertNetworkError(new(nfe)).StatusCode != http.StatusNotFound {
+		t.Fatalf("Failed to recognize NotFound error")
+	}
+
+	if convertNetworkError(new(forb)).StatusCode != http.StatusForbidden {
+		t.Fatalf("Failed to recognize Forbidden error")
+	}
+
+	if convertNetworkError(new(notimpl)).StatusCode != http.StatusNotImplemented {
+		t.Fatalf("Failed to recognize NotImplemented error")
+	}
+
+	if convertNetworkError(new(inter)).StatusCode != http.StatusInternalServerError {
+		t.Fatalf("Failed to recognize Internal error")
+	}
+
+	if convertNetworkError(new(tout)).StatusCode != http.StatusRequestTimeout {
+		t.Fatalf("Failed to recognize Timeout error")
+	}
+
+	if convertNetworkError(new(noserv)).StatusCode != http.StatusServiceUnavailable {
+		t.Fatalf("Failed to recognize No Service error")
+	}
+
+	if convertNetworkError(new(notclassified)).StatusCode != http.StatusInternalServerError {
+		t.Fatalf("Failed to recognize not classified error as Internal error")
+	}
+}

+ 9 - 6
libnetwork/controller.go

@@ -134,7 +134,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver)
 // are network specific and modeled in a generic way.
 // are network specific and modeled in a generic way.
 func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
 func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
 	if name == "" {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	}
 	// Check if a driver for the specified network type is available
 	// Check if a driver for the specified network type is available
 	c.Lock()
 	c.Lock()
@@ -203,7 +203,7 @@ func (c *controller) WalkNetworks(walker NetworkWalker) {
 
 
 func (c *controller) NetworkByName(name string) (Network, error) {
 func (c *controller) NetworkByName(name string) (Network, error) {
 	if name == "" {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	}
 	var n Network
 	var n Network
 
 
@@ -218,7 +218,7 @@ func (c *controller) NetworkByName(name string) (Network, error) {
 	c.WalkNetworks(s)
 	c.WalkNetworks(s)
 
 
 	if n == nil {
 	if n == nil {
-		return nil, ErrNoSuchNetwork
+		return nil, ErrNoSuchNetwork(name)
 	}
 	}
 
 
 	return n, nil
 	return n, nil
@@ -226,14 +226,14 @@ func (c *controller) NetworkByName(name string) (Network, error) {
 
 
 func (c *controller) NetworkByID(id string) (Network, error) {
 func (c *controller) NetworkByID(id string) (Network, error) {
 	if id == "" {
 	if id == "" {
-		return nil, ErrInvalidID
+		return nil, ErrInvalidID(id)
 	}
 	}
 	c.Lock()
 	c.Lock()
 	defer c.Unlock()
 	defer c.Unlock()
 	if n, ok := c.networks[types.UUID(id)]; ok {
 	if n, ok := c.networks[types.UUID(id)]; ok {
 		return n, nil
 		return n, nil
 	}
 	}
-	return nil, ErrNoSuchNetwork
+	return nil, ErrNoSuchNetwork(id)
 }
 }
 
 
 func (c *controller) sandboxAdd(key string, create bool) (sandbox.Sandbox, error) {
 func (c *controller) sandboxAdd(key string, create bool) (sandbox.Sandbox, error) {
@@ -286,13 +286,16 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
 	if err != nil {
 	if err != nil {
+		if err == plugins.ErrNotFound {
+			return nil, types.NotFoundErrorf(err.Error())
+		}
 		return nil, err
 		return nil, err
 	}
 	}
 	c.Lock()
 	c.Lock()
 	defer c.Unlock()
 	defer c.Unlock()
 	d, ok := c.drivers[networkType]
 	d, ok := c.drivers[networkType]
 	if !ok {
 	if !ok {
-		return nil, ErrInvalidNetworkDriver
+		return nil, ErrInvalidNetworkDriver(networkType)
 	}
 	}
 	return d, nil
 	return d, nil
 }
 }

+ 0 - 21
libnetwork/driverapi/driverapi.go

@@ -1,24 +1,11 @@
 package driverapi
 package driverapi
 
 
 import (
 import (
-	"errors"
-	"fmt"
 	"net"
 	"net"
 
 
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
 )
 )
 
 
-var (
-	// ErrEndpointExists is returned if more than one endpoint is added to the network
-	ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
-	// ErrNoNetwork is returned if no network with the specified id exists
-	ErrNoNetwork = errors.New("No network exists")
-	// ErrNoEndpoint is returned if no endpoint with the specified id exists
-	ErrNoEndpoint = errors.New("No endpoint exists")
-	// ErrNotImplemented is returned when a Driver has not implemented an API yet
-	ErrNotImplemented = errors.New("The API is not implemented yet")
-)
-
 // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
 // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
 const NetworkPluginEndpointType = "NetworkDriver"
 const NetworkPluginEndpointType = "NetworkDriver"
 
 
@@ -124,14 +111,6 @@ type JoinInfo interface {
 	SetResolvConfPath(string) error
 	SetResolvConfPath(string) error
 }
 }
 
 
-// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered
-type ErrActiveRegistration string
-
-// Error interface for ErrActiveRegistration
-func (ar ErrActiveRegistration) Error() string {
-	return fmt.Sprintf("Driver already registered for type %q", string(ar))
-}
-
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
 type DriverCallback interface {
 type DriverCallback interface {
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance

+ 56 - 0
libnetwork/driverapi/errors.go

@@ -0,0 +1,56 @@
+package driverapi
+
+import (
+	"fmt"
+)
+
+// ErrNoNetwork is returned if no network with the specified id exists
+type ErrNoNetwork string
+
+func (enn ErrNoNetwork) Error() string {
+	return fmt.Sprintf("No network (%s) exists", string(enn))
+}
+
+// NotFound denotes the type of this error
+func (enn ErrNoNetwork) NotFound() {}
+
+// ErrEndpointExists is returned if more than one endpoint is added to the network
+type ErrEndpointExists string
+
+func (ee ErrEndpointExists) Error() string {
+	return fmt.Sprintf("Endpoint (%s) already exists (Only one endpoint allowed)", string(ee))
+}
+
+// Forbidden denotes the type of this error
+func (ee ErrEndpointExists) Forbidden() {}
+
+// ErrNotImplemented is returned when a Driver has not implemented an API yet
+type ErrNotImplemented struct{}
+
+func (eni *ErrNotImplemented) Error() string {
+	return "The API is not implemented yet"
+}
+
+// NotImplemented denotes the type of this error
+func (eni *ErrNotImplemented) NotImplemented() {}
+
+// ErrNoEndpoint is returned if no endpoint with the specified id exists
+type ErrNoEndpoint string
+
+func (ene ErrNoEndpoint) Error() string {
+	return fmt.Sprintf("No endpoint (%s) exists", string(ene))
+}
+
+// NotFound denotes the type of this error
+func (ene ErrNoEndpoint) NotFound() {}
+
+// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered
+type ErrActiveRegistration string
+
+// Error interface for ErrActiveRegistration
+func (ar ErrActiveRegistration) Error() string {
+	return fmt.Sprintf("Driver already registered for type %q", string(ar))
+}
+
+// Forbidden denotes the type of this error
+func (ar ErrActiveRegistration) Forbidden() {}

+ 19 - 19
libnetwork/drivers/bridge/bridge.go

@@ -109,7 +109,7 @@ func Init(dc driverapi.DriverCallback) error {
 // Whatever can be assessed a priori before attempting any programming.
 // Whatever can be assessed a priori before attempting any programming.
 func (c *NetworkConfiguration) Validate() error {
 func (c *NetworkConfiguration) Validate() error {
 	if c.Mtu < 0 {
 	if c.Mtu < 0 {
-		return ErrInvalidMtu
+		return ErrInvalidMtu(c.Mtu)
 	}
 	}
 
 
 	// If bridge v4 subnet is specified
 	// If bridge v4 subnet is specified
@@ -118,19 +118,19 @@ func (c *NetworkConfiguration) Validate() error {
 		if c.FixedCIDR != nil {
 		if c.FixedCIDR != nil {
 			// Check Network address
 			// Check Network address
 			if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
 			if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
-				return ErrInvalidContainerSubnet
+				return &ErrInvalidContainerSubnet{}
 			}
 			}
 			// Check it is effectively a subset
 			// Check it is effectively a subset
 			brNetLen, _ := c.AddressIPv4.Mask.Size()
 			brNetLen, _ := c.AddressIPv4.Mask.Size()
 			cnNetLen, _ := c.FixedCIDR.Mask.Size()
 			cnNetLen, _ := c.FixedCIDR.Mask.Size()
 			if brNetLen > cnNetLen {
 			if brNetLen > cnNetLen {
-				return ErrInvalidContainerSubnet
+				return &ErrInvalidContainerSubnet{}
 			}
 			}
 		}
 		}
 		// If default gw is specified, it must be part of bridge subnet
 		// If default gw is specified, it must be part of bridge subnet
 		if c.DefaultGatewayIPv4 != nil {
 		if c.DefaultGatewayIPv4 != nil {
 			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
 			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
-				return ErrInvalidGateway
+				return &ErrInvalidGateway{}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -138,7 +138,7 @@ func (c *NetworkConfiguration) Validate() error {
 	// If default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet
 	// If default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet
 	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
 	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
 		if c.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) {
 		if c.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) {
-			return ErrInvalidGateway
+			return &ErrInvalidGateway{}
 		}
 		}
 	}
 	}
 
 
@@ -167,7 +167,7 @@ func (d *driver) Config(option map[string]interface{}) error {
 	defer d.Unlock()
 	defer d.Unlock()
 
 
 	if d.config != nil {
 	if d.config != nil {
-		return ErrConfigExists
+		return &ErrConfigExists{}
 	}
 	}
 
 
 	genericData, ok := option[netlabel.GenericData]
 	genericData, ok := option[netlabel.GenericData]
@@ -182,7 +182,7 @@ func (d *driver) Config(option map[string]interface{}) error {
 		case *Configuration:
 		case *Configuration:
 			config = opt
 			config = opt
 		default:
 		default:
-			return ErrInvalidDriverConfig
+			return &ErrInvalidDriverConfig{}
 		}
 		}
 
 
 		d.config = config
 		d.config = config
@@ -220,7 +220,7 @@ func parseNetworkOptions(option options.Generic) (*NetworkConfiguration, error)
 		case *NetworkConfiguration:
 		case *NetworkConfiguration:
 			config = opt
 			config = opt
 		default:
 		default:
-			return nil, ErrInvalidNetworkConfig
+			return nil, &ErrInvalidNetworkConfig{}
 		}
 		}
 
 
 		if err := config.Validate(); err != nil {
 		if err := config.Validate(); err != nil {
@@ -247,7 +247,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
 	// Sanity checks
 	// Sanity checks
 	if d.network != nil {
 	if d.network != nil {
 		d.Unlock()
 		d.Unlock()
-		return ErrNetworkExists
+		return &ErrNetworkExists{}
 	}
 	}
 
 
 	// Create and set network handler in driver
 	// Create and set network handler in driver
@@ -361,7 +361,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
 
 
 	// Sanity check
 	// Sanity check
 	if n == nil {
 	if n == nil {
-		err = driverapi.ErrNoNetwork
+		err = driverapi.ErrNoNetwork(nid)
 		return err
 		return err
 	}
 	}
 
 
@@ -397,7 +397,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	config := n.config
 	config := n.config
 	d.Unlock()
 	d.Unlock()
 	if n == nil {
 	if n == nil {
-		return driverapi.ErrNoNetwork
+		return driverapi.ErrNoNetwork(nid)
 	}
 	}
 
 
 	// Sanity check
 	// Sanity check
@@ -416,7 +416,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 
 
 	// Endpoint with that id exists either on desired or other sandbox
 	// Endpoint with that id exists either on desired or other sandbox
 	if ep != nil {
 	if ep != nil {
-		return driverapi.ErrEndpointExists
+		return driverapi.ErrEndpointExists(eid)
 	}
 	}
 
 
 	// Try to convert the options to endpoint configuration
 	// Try to convert the options to endpoint configuration
@@ -578,7 +578,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
 	config := n.config
 	config := n.config
 	d.Unlock()
 	d.Unlock()
 	if n == nil {
 	if n == nil {
-		return driverapi.ErrNoNetwork
+		return driverapi.ErrNoNetwork(nid)
 	}
 	}
 
 
 	// Sanity Check
 	// Sanity Check
@@ -648,7 +648,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 	n := d.network
 	n := d.network
 	d.Unlock()
 	d.Unlock()
 	if n == nil {
 	if n == nil {
-		return nil, driverapi.ErrNoNetwork
+		return nil, driverapi.ErrNoNetwork(nid)
 	}
 	}
 
 
 	// Sanity check
 	// Sanity check
@@ -665,7 +665,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 		return nil, err
 		return nil, err
 	}
 	}
 	if ep == nil {
 	if ep == nil {
-		return nil, driverapi.ErrNoEndpoint
+		return nil, driverapi.ErrNoEndpoint(eid)
 	}
 	}
 
 
 	m := make(map[string]interface{})
 	m := make(map[string]interface{})
@@ -856,7 +856,7 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
 		if mac, ok := opt.(net.HardwareAddr); ok {
 		if mac, ok := opt.(net.HardwareAddr); ok {
 			ec.MacAddress = mac
 			ec.MacAddress = mac
 		} else {
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 		}
 	}
 	}
 
 
@@ -864,7 +864,7 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
 		if bs, ok := opt.([]types.PortBinding); ok {
 		if bs, ok := opt.([]types.PortBinding); ok {
 			ec.PortBindings = bs
 			ec.PortBindings = bs
 		} else {
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 		}
 	}
 	}
 
 
@@ -872,7 +872,7 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
 		if ports, ok := opt.([]types.TransportPort); ok {
 		if ports, ok := opt.([]types.TransportPort); ok {
 			ec.ExposedPorts = ports
 			ec.ExposedPorts = ports
 		} else {
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 		}
 	}
 	}
 
 
@@ -924,5 +924,5 @@ func generateIfaceName() (string, error) {
 			return "", err
 			return "", err
 		}
 		}
 	}
 	}
-	return "", ErrIfaceName
+	return "", &ErrIfaceName{}
 }
 }

+ 0 - 201
libnetwork/drivers/bridge/error.go

@@ -1,201 +0,0 @@
-package bridge
-
-import (
-	"errors"
-	"fmt"
-	"net"
-)
-
-var (
-	// ErrConfigExists error is returned when driver already has a config applied.
-	ErrConfigExists = errors.New("configuration already exists, bridge configuration can be applied only once")
-
-	// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config
-	ErrInvalidDriverConfig = errors.New("Invalid configuration passed to Bridge Driver")
-
-	// ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config.
-	ErrInvalidNetworkConfig = errors.New("trying to create a network on a driver without valid config")
-
-	// ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration.
-	ErrInvalidContainerConfig = errors.New("Error in joining a container due to invalid configuration")
-
-	// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration.
-	ErrInvalidEndpointConfig = errors.New("trying to create an endpoint with an invalid endpoint configuration")
-
-	// ErrNetworkExists error is returned when a network already exists and another network is created.
-	ErrNetworkExists = errors.New("network already exists, bridge can only have one network")
-
-	// ErrIfaceName error is returned when a new name could not be generated.
-	ErrIfaceName = errors.New("failed to find name for new interface")
-
-	// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
-	ErrNoIPAddr = errors.New("bridge has no IPv4 address configured")
-
-	// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
-	ErrInvalidGateway = errors.New("default gateway ip must be part of the network")
-
-	// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
-	ErrInvalidContainerSubnet = errors.New("container subnet must be a subset of bridge network")
-
-	// ErrInvalidMtu is returned when the user provided MTU is not valid.
-	ErrInvalidMtu = errors.New("invalid MTU number")
-
-	// ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration
-	// not enabled.
-	ErrIPFwdCfg = errors.New("unexpected request to enable IP Forwarding")
-)
-
-// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
-type ErrInvalidPort string
-
-func (ip ErrInvalidPort) Error() string {
-	return fmt.Sprintf("invalid transport port: %s", string(ip))
-}
-
-// ErrUnsupportedAddressType is returned when the specified address type is not supported.
-type ErrUnsupportedAddressType string
-
-func (uat ErrUnsupportedAddressType) Error() string {
-	return fmt.Sprintf("unsupported address type: %s", string(uat))
-}
-
-// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid.
-type ErrInvalidAddressBinding string
-
-func (iab ErrInvalidAddressBinding) Error() string {
-	return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
-}
-
-// ActiveEndpointsError is returned when there are
-// still active endpoints in the network being deleted.
-type ActiveEndpointsError string
-
-func (aee ActiveEndpointsError) Error() string {
-	return fmt.Sprintf("network %s has active endpoint", string(aee))
-}
-
-// InvalidNetworkIDError is returned when the passed
-// network id for an existing network is not a known id.
-type InvalidNetworkIDError string
-
-func (inie InvalidNetworkIDError) Error() string {
-	return fmt.Sprintf("invalid network id %s", string(inie))
-}
-
-// InvalidEndpointIDError is returned when the passed
-// endpoint id is not valid.
-type InvalidEndpointIDError string
-
-func (ieie InvalidEndpointIDError) Error() string {
-	return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
-}
-
-// InvalidSandboxIDError is returned when the passed
-// sandbox id valid.
-type InvalidSandboxIDError string
-
-func (isie InvalidSandboxIDError) Error() string {
-	return fmt.Sprintf("invalid sanbox id: %s", string(isie))
-}
-
-// EndpointNotFoundError is returned when the no endpoint
-// with the passed endpoint id is found.
-type EndpointNotFoundError string
-
-func (enfe EndpointNotFoundError) Error() string {
-	return fmt.Sprintf("endpoint not found: %s", string(enfe))
-}
-
-// NonDefaultBridgeExistError is returned when a non-default
-// bridge config is passed but it does not already exist.
-type NonDefaultBridgeExistError string
-
-func (ndbee NonDefaultBridgeExistError) Error() string {
-	return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
-}
-
-// FixedCIDRv4Error is returned when fixed-cidrv4 configuration
-// failed.
-type FixedCIDRv4Error struct {
-	net    *net.IPNet
-	subnet *net.IPNet
-	err    error
-}
-
-func (fcv4 *FixedCIDRv4Error) Error() string {
-	return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.subnet, fcv4.net, fcv4.err)
-}
-
-// FixedCIDRv6Error is returned when fixed-cidrv6 configuration
-// failed.
-type FixedCIDRv6Error struct {
-	net *net.IPNet
-	err error
-}
-
-func (fcv6 *FixedCIDRv6Error) Error() string {
-	return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.net, fcv6.net, fcv6.err)
-}
-
-type ipTableCfgError string
-
-func (name ipTableCfgError) Error() string {
-	return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
-}
-
-type invalidIPTablesCfgError string
-
-func (action invalidIPTablesCfgError) Error() string {
-	return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
-}
-
-// IPv4AddrRangeError is returned when a valid IP address range couldn't be found.
-type IPv4AddrRangeError string
-
-func (name IPv4AddrRangeError) Error() string {
-	return fmt.Sprintf("can't find an address range for interface %q", string(name))
-}
-
-// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge.
-type IPv4AddrAddError struct {
-	ip  *net.IPNet
-	err error
-}
-
-func (ipv4 *IPv4AddrAddError) Error() string {
-	return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.ip, ipv4.err)
-}
-
-// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge.
-type IPv6AddrAddError struct {
-	ip  *net.IPNet
-	err error
-}
-
-func (ipv6 *IPv6AddrAddError) Error() string {
-	return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.ip, ipv6.err)
-}
-
-// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured.
-type IPv4AddrNoMatchError struct {
-	ip    net.IP
-	cfgIP net.IP
-}
-
-func (ipv4 *IPv4AddrNoMatchError) Error() string {
-	return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.ip, ipv4.cfgIP)
-}
-
-// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured.
-type IPv6AddrNoMatchError net.IPNet
-
-func (ipv6 *IPv6AddrNoMatchError) Error() string {
-	return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
-}
-
-// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address
-type InvalidLinkIPAddrError string
-
-func (address InvalidLinkIPAddrError) Error() string {
-	return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
-}

+ 341 - 0
libnetwork/drivers/bridge/errors.go

@@ -0,0 +1,341 @@
+package bridge
+
+import (
+	"fmt"
+	"net"
+)
+
+// ErrConfigExists error is returned when driver already has a config applied.
+type ErrConfigExists struct{}
+
+func (ece *ErrConfigExists) Error() string {
+	return "configuration already exists, bridge configuration can be applied only once"
+}
+
+// Forbidden denotes the type of this error
+func (ece *ErrConfigExists) Forbidden() {}
+
+// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config
+type ErrInvalidDriverConfig struct{}
+
+func (eidc *ErrInvalidDriverConfig) Error() string {
+	return "Invalid configuration passed to Bridge Driver"
+}
+
+// BadRequest denotes the type of this error
+func (eidc *ErrInvalidDriverConfig) BadRequest() {}
+
+// ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config.
+type ErrInvalidNetworkConfig struct{}
+
+func (einc *ErrInvalidNetworkConfig) Error() string {
+	return "trying to create a network on a driver without valid config"
+}
+
+// Forbidden denotes the type of this error
+func (einc *ErrInvalidNetworkConfig) Forbidden() {}
+
+// ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration.
+type ErrInvalidContainerConfig struct{}
+
+func (eicc *ErrInvalidContainerConfig) Error() string {
+	return "Error in joining a container due to invalid configuration"
+}
+
+// BadRequest denotes the type of this error
+func (eicc *ErrInvalidContainerConfig) BadRequest() {}
+
+// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration.
+type ErrInvalidEndpointConfig struct{}
+
+func (eiec *ErrInvalidEndpointConfig) Error() string {
+	return "trying to create an endpoint with an invalid endpoint configuration"
+}
+
+// BadRequest denotes the type of this error
+func (eiec *ErrInvalidEndpointConfig) BadRequest() {}
+
+// ErrNetworkExists error is returned when a network already exists and another network is created.
+type ErrNetworkExists struct{}
+
+func (ene *ErrNetworkExists) Error() string {
+	return "network already exists, bridge can only have one network"
+}
+
+// Forbidden denotes the type of this error
+func (ene *ErrNetworkExists) Forbidden() {}
+
+// ErrIfaceName error is returned when a new name could not be generated.
+type ErrIfaceName struct{}
+
+func (ein *ErrIfaceName) Error() string {
+	return "failed to find name for new interface"
+}
+
+// InternalError denotes the type of this error
+func (ein *ErrIfaceName) InternalError() {}
+
+// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
+type ErrNoIPAddr struct{}
+
+func (enip *ErrNoIPAddr) Error() string {
+	return "bridge has no IPv4 address configured"
+}
+
+// InternalError denotes the type of this error
+func (enip *ErrNoIPAddr) InternalError() {}
+
+// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
+type ErrInvalidGateway struct{}
+
+func (eig *ErrInvalidGateway) Error() string {
+	return "default gateway ip must be part of the network"
+}
+
+// BadRequest denotes the type of this error
+func (eig *ErrInvalidGateway) BadRequest() {}
+
+// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
+type ErrInvalidContainerSubnet struct{}
+
+func (eis *ErrInvalidContainerSubnet) Error() string {
+	return "container subnet must be a subset of bridge network"
+}
+
+// BadRequest denotes the type of this error
+func (eis *ErrInvalidContainerSubnet) BadRequest() {}
+
+// ErrInvalidMtu is returned when the user provided MTU is not valid.
+type ErrInvalidMtu int
+
+func (eim ErrInvalidMtu) Error() string {
+	return fmt.Sprintf("invalid MTU number: %d", int(eim))
+}
+
+// BadRequest denotes the type of this error
+func (eim ErrInvalidMtu) BadRequest() {}
+
+// ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration
+// not enabled.
+type ErrIPFwdCfg struct{}
+
+func (eipf *ErrIPFwdCfg) Error() string {
+	return "unexpected request to enable IP Forwarding"
+}
+
+// BadRequest denotes the type of this error
+func (eipf *ErrIPFwdCfg) BadRequest() {}
+
+// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
+type ErrInvalidPort string
+
+func (ip ErrInvalidPort) Error() string {
+	return fmt.Sprintf("invalid transport port: %s", string(ip))
+}
+
+// BadRequest denotes the type of this error
+func (ip ErrInvalidPort) BadRequest() {}
+
+// ErrUnsupportedAddressType is returned when the specified address type is not supported.
+type ErrUnsupportedAddressType string
+
+func (uat ErrUnsupportedAddressType) Error() string {
+	return fmt.Sprintf("unsupported address type: %s", string(uat))
+}
+
+// BadRequest denotes the type of this error
+func (uat ErrUnsupportedAddressType) BadRequest() {}
+
+// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid.
+type ErrInvalidAddressBinding string
+
+func (iab ErrInvalidAddressBinding) Error() string {
+	return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
+}
+
+// BadRequest denotes the type of this error
+func (iab ErrInvalidAddressBinding) BadRequest() {}
+
+// ActiveEndpointsError is returned when there are
+// still active endpoints in the network being deleted.
+type ActiveEndpointsError string
+
+func (aee ActiveEndpointsError) Error() string {
+	return fmt.Sprintf("network %s has active endpoint", string(aee))
+}
+
+// Forbidden denotes the type of this error
+func (aee ActiveEndpointsError) Forbidden() {}
+
+// InvalidNetworkIDError is returned when the passed
+// network id for an existing network is not a known id.
+type InvalidNetworkIDError string
+
+func (inie InvalidNetworkIDError) Error() string {
+	return fmt.Sprintf("invalid network id %s", string(inie))
+}
+
+// NotFound denotes the type of this error
+func (inie InvalidNetworkIDError) NotFound() {}
+
+// InvalidEndpointIDError is returned when the passed
+// endpoint id is not valid.
+type InvalidEndpointIDError string
+
+func (ieie InvalidEndpointIDError) Error() string {
+	return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
+}
+
+// BadRequest denotes the type of this error
+func (ieie InvalidEndpointIDError) BadRequest() {}
+
+// InvalidSandboxIDError is returned when the passed
+// sandbox id is not valid.
+type InvalidSandboxIDError string
+
+func (isie InvalidSandboxIDError) Error() string {
+	return fmt.Sprintf("invalid sanbox id: %s", string(isie))
+}
+
+// BadRequest denotes the type of this error
+func (isie InvalidSandboxIDError) BadRequest() {}
+
+// EndpointNotFoundError is returned when the no endpoint
+// with the passed endpoint id is found.
+type EndpointNotFoundError string
+
+func (enfe EndpointNotFoundError) Error() string {
+	return fmt.Sprintf("endpoint not found: %s", string(enfe))
+}
+
+// NotFound denotes the type of this error
+func (enfe EndpointNotFoundError) NotFound() {}
+
+// NonDefaultBridgeExistError is returned when a non-default
+// bridge config is passed but it does not already exist.
+type NonDefaultBridgeExistError string
+
+func (ndbee NonDefaultBridgeExistError) Error() string {
+	return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
+}
+
+// Forbidden denotes the type of this error
+func (ndbee NonDefaultBridgeExistError) Forbidden() {}
+
+// FixedCIDRv4Error is returned when fixed-cidrv4 configuration
+// failed.
+type FixedCIDRv4Error struct {
+	Net    *net.IPNet
+	Subnet *net.IPNet
+	Err    error
+}
+
+func (fcv4 *FixedCIDRv4Error) Error() string {
+	return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.Subnet, fcv4.Net, fcv4.Err)
+}
+
+// InternalError denotes the type of this error
+func (fcv4 *FixedCIDRv4Error) InternalError() {}
+
+// FixedCIDRv6Error is returned when fixed-cidrv6 configuration
+// failed.
+type FixedCIDRv6Error struct {
+	Net *net.IPNet
+	Err error
+}
+
+func (fcv6 *FixedCIDRv6Error) Error() string {
+	return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.Net, fcv6.Net, fcv6.Err)
+}
+
+// InternalError denotes the type of this error
+func (fcv6 *FixedCIDRv6Error) InternalError() {}
+
+// IPTableCfgError is returned when an unexpected ip tables configuration is entered
+type IPTableCfgError string
+
+func (name IPTableCfgError) Error() string {
+	return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
+}
+
+// BadRequest denotes the type of this error
+func (name IPTableCfgError) BadRequest() {}
+
+// InvalidIPTablesCfgError is returned when an invalid ip tables configuration is entered
+type InvalidIPTablesCfgError string
+
+func (action InvalidIPTablesCfgError) Error() string {
+	return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
+}
+
+// BadRequest denotes the type of this error
+func (action InvalidIPTablesCfgError) BadRequest() {}
+
+// IPv4AddrRangeError is returned when a valid IP address range couldn't be found.
+type IPv4AddrRangeError string
+
+func (name IPv4AddrRangeError) Error() string {
+	return fmt.Sprintf("can't find an address range for interface %q", string(name))
+}
+
+// BadRequest denotes the type of this error
+func (name IPv4AddrRangeError) BadRequest() {}
+
+// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge.
+type IPv4AddrAddError struct {
+	IP  *net.IPNet
+	Err error
+}
+
+func (ipv4 *IPv4AddrAddError) Error() string {
+	return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.IP, ipv4.Err)
+}
+
+// InternalError denotes the type of this error
+func (ipv4 *IPv4AddrAddError) InternalError() {}
+
+// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge.
+type IPv6AddrAddError struct {
+	IP  *net.IPNet
+	Err error
+}
+
+func (ipv6 *IPv6AddrAddError) Error() string {
+	return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.IP, ipv6.Err)
+}
+
+// InternalError denotes the type of this error
+func (ipv6 *IPv6AddrAddError) InternalError() {}
+
+// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured.
+type IPv4AddrNoMatchError struct {
+	IP    net.IP
+	CfgIP net.IP
+}
+
+func (ipv4 *IPv4AddrNoMatchError) Error() string {
+	return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.IP, ipv4.CfgIP)
+}
+
+// BadRequest denotes the type of this error
+func (ipv4 *IPv4AddrNoMatchError) BadRequest() {}
+
+// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured.
+type IPv6AddrNoMatchError net.IPNet
+
+func (ipv6 *IPv6AddrNoMatchError) Error() string {
+	return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
+}
+
+// BadRequest denotes the type of this error
+func (ipv6 *IPv6AddrNoMatchError) BadRequest() {}
+
+// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address
+type InvalidLinkIPAddrError string
+
+func (address InvalidLinkIPAddrError) Error() string {
+	return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
+}
+
+// BadRequest denotes the type of this error
+func (address InvalidLinkIPAddrError) BadRequest() {}

+ 1 - 1
libnetwork/drivers/bridge/link.go

@@ -57,7 +57,7 @@ func linkContainers(action, parentIP, childIP string, ports []types.TransportPor
 	case "-D":
 	case "-D":
 		nfAction = iptables.Delete
 		nfAction = iptables.Delete
 	default:
 	default:
-		return invalidIPTablesCfgError(action)
+		return InvalidIPTablesCfgError(action)
 	}
 	}
 
 
 	ip1 := net.ParseIP(parentIP)
 	ip1 := net.ParseIP(parentIP)

+ 2 - 2
libnetwork/drivers/bridge/network_test.go

@@ -125,8 +125,8 @@ func TestLinkCreateTwo(t *testing.T) {
 	te2 := &testEndpoint{ifaces: []*testInterface{}}
 	te2 := &testEndpoint{ifaces: []*testInterface{}}
 	err = d.CreateEndpoint("dummy", "ep", te2, nil)
 	err = d.CreateEndpoint("dummy", "ep", te2, nil)
 	if err != nil {
 	if err != nil {
-		if err != driverapi.ErrEndpointExists {
-			t.Fatalf("Failed with a wrong error :%s", err.Error())
+		if _, ok := err.(driverapi.ErrEndpointExists); !ok {
+			t.Fatalf("Failed with a wrong error: %s", err.Error())
 		}
 		}
 	} else {
 	} else {
 		t.Fatalf("Expected to fail while trying to add same endpoint twice")
 		t.Fatalf("Expected to fail while trying to add same endpoint twice")

+ 4 - 2
libnetwork/drivers/bridge/setup_fixedcidrv4.go

@@ -1,6 +1,8 @@
 package bridge
 package bridge
 
 
-import log "github.com/Sirupsen/logrus"
+import (
+	log "github.com/Sirupsen/logrus"
+)
 
 
 func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
 	addrv4, _, err := i.addresses()
 	addrv4, _, err := i.addresses()
@@ -10,7 +12,7 @@ func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
 
 
 	log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR)
 	log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR)
 	if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil {
 	if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil {
-		return &FixedCIDRv4Error{subnet: config.FixedCIDR, net: addrv4.IPNet, err: err}
+		return &FixedCIDRv4Error{Subnet: config.FixedCIDR, Net: addrv4.IPNet, Err: err}
 	}
 	}
 
 
 	return nil
 	return nil

+ 4 - 2
libnetwork/drivers/bridge/setup_fixedcidrv6.go

@@ -1,11 +1,13 @@
 package bridge
 package bridge
 
 
-import log "github.com/Sirupsen/logrus"
+import (
+	log "github.com/Sirupsen/logrus"
+)
 
 
 func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error {
 	log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
 	log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
 	if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil {
 	if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil {
-		return &FixedCIDRv6Error{net: config.FixedCIDRv6, err: err}
+		return &FixedCIDRv6Error{Net: config.FixedCIDRv6, Err: err}
 	}
 	}
 
 
 	return nil
 	return nil

+ 1 - 1
libnetwork/drivers/bridge/setup_ip_forwarding.go

@@ -13,7 +13,7 @@ const (
 func setupIPForwarding(config *Configuration) error {
 func setupIPForwarding(config *Configuration) error {
 	// Sanity Check
 	// Sanity Check
 	if config.EnableIPForwarding == false {
 	if config.EnableIPForwarding == false {
-		return ErrIPFwdCfg
+		return &ErrIPFwdCfg{}
 	}
 	}
 
 
 	// Enable IPv4 forwarding
 	// Enable IPv4 forwarding

+ 1 - 1
libnetwork/drivers/bridge/setup_ip_forwarding_test.go

@@ -47,7 +47,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
 		t.Fatal("Setup IP forwarding was expected to fail")
 		t.Fatal("Setup IP forwarding was expected to fail")
 	}
 	}
 
 
-	if err != ErrIPFwdCfg {
+	if _, ok := err.(*ErrIPFwdCfg); !ok {
 		t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err)
 		t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err)
 	}
 	}
 }
 }

+ 1 - 1
libnetwork/drivers/bridge/setup_ip_tables.go

@@ -16,7 +16,7 @@ const (
 func setupIPTables(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupIPTables(config *NetworkConfiguration, i *bridgeInterface) error {
 	// Sanity check.
 	// Sanity check.
 	if config.EnableIPTables == false {
 	if config.EnableIPTables == false {
-		return ipTableCfgError(config.BridgeName)
+		return IPTableCfgError(config.BridgeName)
 	}
 	}
 
 
 	hairpinMode := !config.EnableUserlandProxy
 	hairpinMode := !config.EnableUserlandProxy

+ 2 - 2
libnetwork/drivers/bridge/setup_ipv4.go

@@ -71,7 +71,7 @@ func setupBridgeIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
 
 
 	log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4)
 	log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4)
 	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil {
 	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil {
-		return &IPv4AddrAddError{ip: bridgeIPv4, err: err}
+		return &IPv4AddrAddError{IP: bridgeIPv4, Err: err}
 	}
 	}
 
 
 	// Store bridge network and default gateway
 	// Store bridge network and default gateway
@@ -114,7 +114,7 @@ func electBridgeIPv4(config *NetworkConfiguration) (*net.IPNet, error) {
 
 
 func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
-		return ErrInvalidGateway
+		return &ErrInvalidGateway{}
 	}
 	}
 	if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
 	if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
 		return err
 		return err

+ 3 - 3
libnetwork/drivers/bridge/setup_ipv6.go

@@ -37,7 +37,7 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
 	// Add the default link local ipv6 address if it doesn't exist
 	// Add the default link local ipv6 address if it doesn't exist
 	if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
 	if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
 		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
 		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
-			return &IPv6AddrAddError{ip: bridgeIPv6, err: err}
+			return &IPv6AddrAddError{IP: bridgeIPv6, Err: err}
 		}
 		}
 	}
 	}
 
 
@@ -50,10 +50,10 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
 
 
 func setupGatewayIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupGatewayIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
 	if config.FixedCIDRv6 == nil {
 	if config.FixedCIDRv6 == nil {
-		return ErrInvalidContainerSubnet
+		return &ErrInvalidContainerSubnet{}
 	}
 	}
 	if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
 	if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
-		return ErrInvalidGateway
+		return &ErrInvalidGateway{}
 	}
 	}
 	if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
 	if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
 		return err
 		return err

+ 5 - 3
libnetwork/drivers/bridge/setup_verify.go

@@ -1,6 +1,8 @@
 package bridge
 package bridge
 
 
-import "github.com/vishvananda/netlink"
+import (
+	"github.com/vishvananda/netlink"
+)
 
 
 func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error {
 	// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
 	// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
@@ -11,12 +13,12 @@ func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) e
 
 
 	// Verify that the bridge does have an IPv4 address.
 	// Verify that the bridge does have an IPv4 address.
 	if addrv4.IPNet == nil {
 	if addrv4.IPNet == nil {
-		return ErrNoIPAddr
+		return &ErrNoIPAddr{}
 	}
 	}
 
 
 	// Verify that the bridge IPv4 address matches the requested configuration.
 	// Verify that the bridge IPv4 address matches the requested configuration.
 	if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
 	if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
-		return &IPv4AddrNoMatchError{ip: addrv4.IP, cfgIP: config.AddressIPv4.IP}
+		return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP}
 	}
 	}
 
 
 	// Verify that one of the bridge IPv6 addresses matches the requested
 	// Verify that one of the bridge IPv6 addresses matches the requested

+ 8 - 8
libnetwork/drivers/remote/driver.go

@@ -31,37 +31,37 @@ func Init(dc driverapi.DriverCallback) error {
 }
 }
 
 
 func (d *driver) Config(option map[string]interface{}) error {
 func (d *driver) Config(option map[string]interface{}) error {
-	return driverapi.ErrNotImplemented
+	return &driverapi.ErrNotImplemented{}
 }
 }
 
 
 func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
 func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
-	return driverapi.ErrNotImplemented
+	return &driverapi.ErrNotImplemented{}
 }
 }
 
 
 func (d *driver) DeleteNetwork(nid types.UUID) error {
 func (d *driver) DeleteNetwork(nid types.UUID) error {
-	return driverapi.ErrNotImplemented
+	return &driverapi.ErrNotImplemented{}
 }
 }
 
 
 func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
 func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
-	return driverapi.ErrNotImplemented
+	return &driverapi.ErrNotImplemented{}
 }
 }
 
 
 func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
 func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
-	return driverapi.ErrNotImplemented
+	return &driverapi.ErrNotImplemented{}
 }
 }
 
 
 func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
 func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
-	return nil, driverapi.ErrNotImplemented
+	return nil, &driverapi.ErrNotImplemented{}
 }
 }
 
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
 // Join method is invoked when a Sandbox is attached to an endpoint.
 func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
 func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
-	return driverapi.ErrNotImplemented
+	return &driverapi.ErrNotImplemented{}
 }
 }
 
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
 // Leave method is invoked when a Sandbox detaches from an endpoint.
 func (d *driver) Leave(nid, eid types.UUID) error {
 func (d *driver) Leave(nid, eid types.UUID) error {
-	return driverapi.ErrNotImplemented
+	return &driverapi.ErrNotImplemented{}
 }
 }
 
 
 func (d *driver) Type() string {
 func (d *driver) Type() string {

+ 6 - 6
libnetwork/endpoint.go

@@ -216,7 +216,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai
 	ep.Lock()
 	ep.Lock()
 	if ep.container != nil {
 	if ep.container != nil {
 		ep.Unlock()
 		ep.Unlock()
-		return nil, ErrInvalidJoin
+		return nil, ErrInvalidJoin{}
 	}
 	}
 
 
 	ep.container = &containerInfo{
 	ep.container = &containerInfo{
@@ -334,7 +334,7 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 	if container == nil || container.id == "" ||
 	if container == nil || container.id == "" ||
 		containerID == "" || container.id != containerID {
 		containerID == "" || container.id != containerID {
 		if container == nil {
 		if container == nil {
-			err = ErrNoContainer
+			err = ErrNoContainer{}
 		} else {
 		} else {
 			err = InvalidContainerIDError(containerID)
 			err = InvalidContainerIDError(containerID)
 		}
 		}
@@ -412,7 +412,7 @@ func (ep *endpoint) buildHostsFiles() error {
 	ep.Unlock()
 	ep.Unlock()
 
 
 	if container == nil {
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 	}
 
 
 	if container.config.hostsPath == "" {
 	if container.config.hostsPath == "" {
@@ -462,7 +462,7 @@ func (ep *endpoint) updateParentHosts() error {
 	ep.Unlock()
 	ep.Unlock()
 
 
 	if container == nil {
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 	}
 
 
 	for _, update := range container.config.parentUpdates {
 	for _, update := range container.config.parentUpdates {
@@ -495,7 +495,7 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error {
 	ep.Unlock()
 	ep.Unlock()
 
 
 	if container == nil {
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 	}
 
 
 	oldHash := []byte{}
 	oldHash := []byte{}
@@ -573,7 +573,7 @@ func (ep *endpoint) setupDNS() error {
 	ep.Unlock()
 	ep.Unlock()
 
 
 	if container == nil {
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 	}
 
 
 	if container.config.resolvConfPath == "" {
 	if container.config.resolvConfPath == "" {

+ 97 - 27
libnetwork/error.go

@@ -1,34 +1,83 @@
 package libnetwork
 package libnetwork
 
 
 import (
 import (
-	"errors"
 	"fmt"
 	"fmt"
 )
 )
 
 
-var (
-	// ErrNoSuchNetwork is returned when a network query finds no result
-	ErrNoSuchNetwork = errors.New("network not found")
-	// ErrNoSuchEndpoint is returned when a endpoint query finds no result
-	ErrNoSuchEndpoint = errors.New("endpoint not found")
-	// ErrNilNetworkDriver is returned if a nil network driver
-	// is passed to NewNetwork api.
-	ErrNilNetworkDriver = errors.New("nil NetworkDriver instance")
-	// ErrInvalidNetworkDriver is returned if an invalid driver
-	// instance is passed.
-	ErrInvalidNetworkDriver = errors.New("invalid driver bound to network")
-	// ErrInvalidJoin is returned if a join is attempted on an endpoint
-	// which already has a container joined.
-	ErrInvalidJoin = errors.New("a container has already joined the endpoint")
-	// ErrNoContainer is returned when the endpoint has no container
-	// attached to it.
-	ErrNoContainer = errors.New("no container attached to the endpoint")
-	// ErrInvalidID is returned when a query-by-id method is being invoked
-	// with an empty id parameter
-	ErrInvalidID = errors.New("invalid ID")
-	// ErrInvalidName is returned when a query-by-name or resource create method is
-	// invoked with an empty name parameter
-	ErrInvalidName = errors.New("invalid Name")
-)
+// ErrNoSuchNetwork is returned when a network query finds no result
+type ErrNoSuchNetwork string
+
+func (nsn ErrNoSuchNetwork) Error() string {
+	return fmt.Sprintf("network %s not found", string(nsn))
+}
+
+// BadRequest denotes the type of this error
+func (nsn ErrNoSuchNetwork) BadRequest() {}
+
+// ErrNoSuchEndpoint is returned when a endpoint query finds no result
+type ErrNoSuchEndpoint string
+
+func (nse ErrNoSuchEndpoint) Error() string {
+	return fmt.Sprintf("endpoint %s not found", string(nse))
+}
+
+// BadRequest denotes the type of this error
+func (nse ErrNoSuchEndpoint) BadRequest() {}
+
+// ErrInvalidNetworkDriver is returned if an invalid driver
+// name is passed.
+type ErrInvalidNetworkDriver string
+
+func (ind ErrInvalidNetworkDriver) Error() string {
+	return fmt.Sprintf("invalid driver bound to network: %s", string(ind))
+}
+
+// BadRequest denotes the type of this error
+func (ind ErrInvalidNetworkDriver) BadRequest() {}
+
+// ErrInvalidJoin is returned if a join is attempted on an endpoint
+// which already has a container joined.
+type ErrInvalidJoin struct{}
+
+func (ij ErrInvalidJoin) Error() string {
+	return "a container has already joined the endpoint"
+}
+
+// BadRequest denotes the type of this error
+func (ij ErrInvalidJoin) BadRequest() {}
+
+// ErrNoContainer is returned when the endpoint has no container
+// attached to it.
+type ErrNoContainer struct{}
+
+func (nc ErrNoContainer) Error() string {
+	return "a container has already joined the endpoint"
+}
+
+// Maskable denotes the type of this error
+func (nc ErrNoContainer) Maskable() {}
+
+// ErrInvalidID is returned when a query-by-id method is being invoked
+// with an empty id parameter
+type ErrInvalidID string
+
+func (ii ErrInvalidID) Error() string {
+	return fmt.Sprintf("invalid id: %s", string(ii))
+}
+
+// BadRequest denotes the type of this error
+func (ii ErrInvalidID) BadRequest() {}
+
+// ErrInvalidName is returned when a query-by-name or resource create method is
+// invoked with an empty name parameter
+type ErrInvalidName string
+
+func (in ErrInvalidName) Error() string {
+	return fmt.Sprintf("invalid name: %s", string(in))
+}
+
+// BadRequest denotes the type of this error
+func (in ErrInvalidName) BadRequest() {}
 
 
 // NetworkTypeError type is returned when the network type string is not
 // NetworkTypeError type is returned when the network type string is not
 // known to libnetwork.
 // known to libnetwork.
@@ -38,13 +87,19 @@ func (nt NetworkTypeError) Error() string {
 	return fmt.Sprintf("unknown driver %q", string(nt))
 	return fmt.Sprintf("unknown driver %q", string(nt))
 }
 }
 
 
+// NotFound denotes the type of this error
+func (nt NetworkTypeError) NotFound() {}
+
 // NetworkNameError is returned when a network with the same name already exists.
 // NetworkNameError is returned when a network with the same name already exists.
 type NetworkNameError string
 type NetworkNameError string
 
 
-func (name NetworkNameError) Error() string {
-	return fmt.Sprintf("network with name %s already exists", string(name))
+func (nnr NetworkNameError) Error() string {
+	return fmt.Sprintf("network with name %s already exists", string(nnr))
 }
 }
 
 
+// Forbidden denotes the type of this error
+func (nnr NetworkNameError) Forbidden() {}
+
 // UnknownNetworkError is returned when libnetwork could not find in it's database
 // UnknownNetworkError is returned when libnetwork could not find in it's database
 // a network with the same name and id.
 // a network with the same name and id.
 type UnknownNetworkError struct {
 type UnknownNetworkError struct {
@@ -56,6 +111,9 @@ func (une *UnknownNetworkError) Error() string {
 	return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
 	return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
 }
 }
 
 
+// NotFound denotes the type of this error
+func (une *UnknownNetworkError) NotFound() {}
+
 // ActiveEndpointsError is returned when a network is deleted which has active
 // ActiveEndpointsError is returned when a network is deleted which has active
 // endpoints in it.
 // endpoints in it.
 type ActiveEndpointsError struct {
 type ActiveEndpointsError struct {
@@ -67,6 +125,9 @@ func (aee *ActiveEndpointsError) Error() string {
 	return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id)
 	return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id)
 }
 }
 
 
+// Forbidden denotes the type of this error
+func (aee *ActiveEndpointsError) Forbidden() {}
+
 // UnknownEndpointError is returned when libnetwork could not find in it's database
 // UnknownEndpointError is returned when libnetwork could not find in it's database
 // an endpoint with the same name and id.
 // an endpoint with the same name and id.
 type UnknownEndpointError struct {
 type UnknownEndpointError struct {
@@ -78,6 +139,9 @@ func (uee *UnknownEndpointError) Error() string {
 	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
 	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
 }
 }
 
 
+// NotFound denotes the type of this error
+func (uee *UnknownEndpointError) NotFound() {}
+
 // ActiveContainerError is returned when an endpoint is deleted which has active
 // ActiveContainerError is returned when an endpoint is deleted which has active
 // containers attached to it.
 // containers attached to it.
 type ActiveContainerError struct {
 type ActiveContainerError struct {
@@ -89,6 +153,9 @@ func (ace *ActiveContainerError) Error() string {
 	return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id)
 	return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id)
 }
 }
 
 
+// Forbidden denotes the type of this error
+func (ace *ActiveContainerError) Forbidden() {}
+
 // InvalidContainerIDError is returned when an invalid container id is passed
 // InvalidContainerIDError is returned when an invalid container id is passed
 // in Join/Leave
 // in Join/Leave
 type InvalidContainerIDError string
 type InvalidContainerIDError string
@@ -96,3 +163,6 @@ type InvalidContainerIDError string
 func (id InvalidContainerIDError) Error() string {
 func (id InvalidContainerIDError) Error() string {
 	return fmt.Sprintf("invalid container id %s", string(id))
 	return fmt.Sprintf("invalid container id %s", string(id))
 }
 }
+
+// BadRequest denotes the type of this error
+func (id InvalidContainerIDError) BadRequest() {}

+ 51 - 0
libnetwork/errors_test.go

@@ -0,0 +1,51 @@
+package libnetwork
+
+import (
+	"testing"
+
+	"github.com/docker/libnetwork/types"
+)
+
+func TestErrorInterfaces(t *testing.T) {
+
+	badRequestErrorList := []error{ErrInvalidID(""), ErrInvalidName(""), ErrInvalidJoin{}, ErrInvalidNetworkDriver(""), InvalidContainerIDError(""), ErrNoSuchNetwork(""), ErrNoSuchEndpoint("")}
+	for _, err := range badRequestErrorList {
+		switch u := err.(type) {
+		case types.BadRequestError:
+			return
+		default:
+			t.Fatalf("Failed to detect err %v is of type BadRequestError. Got type: %T", err, u)
+		}
+	}
+
+	maskableErrorList := []error{ErrNoContainer{}}
+	for _, err := range maskableErrorList {
+		switch u := err.(type) {
+		case types.MaskableError:
+			return
+		default:
+			t.Fatalf("Failed to detect err %v is of type MaskableError. Got type: %T", err, u)
+		}
+	}
+
+	notFoundErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
+	for _, err := range notFoundErrorList {
+		switch u := err.(type) {
+		case types.NotFoundError:
+			return
+		default:
+			t.Fatalf("Failed to detect err %v is of type NotFoundError. Got type: %T", err, u)
+		}
+	}
+
+	forbiddenErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
+	for _, err := range forbiddenErrorList {
+		switch u := err.(type) {
+		case types.ForbiddenError:
+			return
+		default:
+			t.Fatalf("Failed to detect err %v is of type ForbiddenError. Got type: %T", err, u)
+		}
+	}
+
+}

+ 1 - 1
libnetwork/iptables/iptables_test.go

@@ -11,7 +11,7 @@ import (
 	_ "github.com/docker/libnetwork/netutils"
 	_ "github.com/docker/libnetwork/netutils"
 )
 )
 
 
-const chainName = "DOCKER-TEST"
+const chainName = "DOCKEREST"
 
 
 var natChain *Chain
 var natChain *Chain
 var filterChain *Chain
 var filterChain *Chain

+ 28 - 21
libnetwork/libnetwork_test.go

@@ -290,7 +290,7 @@ func TestNilRemoteDriver(t *testing.T) {
 		t.Fatal("Expected to fail. But instead succeeded")
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
 	}
 
 
-	if err != plugins.ErrNotFound {
+	if _, ok := err.(types.NotFoundError); !ok {
 		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
 		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
 	}
 	}
 }
 }
@@ -338,8 +338,9 @@ func TestNetworkName(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
 	}
-	if err != libnetwork.ErrInvalidName {
-		t.Fatal("Expected to fail with ErrInvalidName error")
+
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
+		t.Fatalf("Expected to fail with ErrInvalidName error. Got %v", err)
 	}
 	}
 
 
 	networkName := "testnetwork"
 	networkName := "testnetwork"
@@ -475,8 +476,8 @@ func TestUnknownEndpoint(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
 	}
-	if err != libnetwork.ErrInvalidName {
-		t.Fatal("Expected to fail with ErrInvalidName error")
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
+		t.Fatalf("Expected to fail with ErrInvalidName error. Actual error: %v", err)
 	}
 	}
 
 
 	ep, err := network.CreateEndpoint("testep")
 	ep, err := network.CreateEndpoint("testep")
@@ -613,15 +614,15 @@ func TestControllerQuery(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatalf("NetworkByName() succeeded with invalid target name")
 		t.Fatalf("NetworkByName() succeeded with invalid target name")
 	}
 	}
-	if err != libnetwork.ErrInvalidName {
-		t.Fatalf("NetworkByName() failed with unexpected error: %v", err)
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
+		t.Fatalf("Expected NetworkByName() to fail with ErrInvalidName error. Got: %v", err)
 	}
 	}
 
 
 	_, err = controller.NetworkByID("")
 	_, err = controller.NetworkByID("")
 	if err == nil {
 	if err == nil {
 		t.Fatalf("NetworkByID() succeeded with invalid target id")
 		t.Fatalf("NetworkByID() succeeded with invalid target id")
 	}
 	}
-	if err != libnetwork.ErrInvalidID {
+	if _, ok := err.(libnetwork.ErrInvalidID); !ok {
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
 	}
 	}
 
 
@@ -629,7 +630,7 @@ func TestControllerQuery(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatalf("Unexpected success for NetworkByID(): %v", g)
 		t.Fatalf("Unexpected success for NetworkByID(): %v", g)
 	}
 	}
-	if err != libnetwork.ErrNoSuchNetwork {
+	if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok {
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
 	}
 	}
 
 
@@ -695,15 +696,15 @@ func TestNetworkQuery(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatalf("EndpointByName() succeeded with invalid target name")
 		t.Fatalf("EndpointByName() succeeded with invalid target name")
 	}
 	}
-	if err != libnetwork.ErrInvalidName {
-		t.Fatalf("EndpointByName() failed with unexpected error: %v", err)
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
+		t.Fatalf("Expected EndpointByName() to fail with ErrInvalidName error. Got: %v", err)
 	}
 	}
 
 
 	e, err = net1.EndpointByName("IamNotAnEndpoint")
 	e, err = net1.EndpointByName("IamNotAnEndpoint")
 	if err == nil {
 	if err == nil {
 		t.Fatalf("EndpointByName() succeeded with unknown target name")
 		t.Fatalf("EndpointByName() succeeded with unknown target name")
 	}
 	}
-	if err != libnetwork.ErrNoSuchEndpoint {
+	if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	if e != nil {
 	if e != nil {
@@ -722,7 +723,7 @@ func TestNetworkQuery(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatalf("EndpointByID() succeeded with invalid target id")
 		t.Fatalf("EndpointByID() succeeded with invalid target id")
 	}
 	}
-	if err != libnetwork.ErrInvalidID {
+	if _, ok := err.(libnetwork.ErrInvalidID); !ok {
 		t.Fatalf("EndpointByID() failed with unexpected error: %v", err)
 		t.Fatalf("EndpointByID() failed with unexpected error: %v", err)
 	}
 	}
 }
 }
@@ -891,7 +892,7 @@ func TestEndpointMultipleJoins(t *testing.T) {
 		t.Fatal("Expected to fail multiple joins for the same endpoint")
 		t.Fatal("Expected to fail multiple joins for the same endpoint")
 	}
 	}
 
 
-	if err != libnetwork.ErrInvalidJoin {
+	if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
 		t.Fatalf("Failed for unexpected reason: %v", err)
 		t.Fatalf("Failed for unexpected reason: %v", err)
 	}
 	}
 }
 }
@@ -917,7 +918,7 @@ func TestEndpointInvalidLeave(t *testing.T) {
 	}
 	}
 
 
 	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
 	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
-		if err != libnetwork.ErrNoContainer {
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
 			t.Fatalf("Failed for unexpected reason: %v", err)
 			t.Fatalf("Failed for unexpected reason: %v", err)
 		}
 		}
 	}
 	}
@@ -1297,8 +1298,10 @@ func TestValidRemoteDriver(t *testing.T) {
 
 
 	_, err = controller.NewNetwork("valid-network-driver", "dummy",
 	_, err = controller.NewNetwork("valid-network-driver", "dummy",
 		libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
 		libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
-	if err != nil && err != driverapi.ErrNotImplemented {
-		t.Fatal(err)
+	if err != nil {
+		if _, ok := err.(*driverapi.ErrNotImplemented); !ok {
+			t.Fatal(err)
+		}
 	}
 	}
 }
 }
 
 
@@ -1371,8 +1374,10 @@ func parallelJoin(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
 	_, err := ep.Join("racing_container")
 	_, err := ep.Join("racing_container")
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 	if err != nil {
 	if err != nil {
-		if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin {
-			t.Fatal(err)
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
+			if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
+				t.Fatal(err)
+			}
 		}
 		}
 		debugf("JE%d(%v).", thrNumber, err)
 		debugf("JE%d(%v).", thrNumber, err)
 	}
 	}
@@ -1384,8 +1389,10 @@ func parallelLeave(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
 	err := ep.Leave("racing_container")
 	err := ep.Leave("racing_container")
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 	if err != nil {
 	if err != nil {
-		if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin {
-			t.Fatal(err)
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
+			if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
+				t.Fatal(err)
+			}
 		}
 		}
 		debugf("LE%d(%v).", thrNumber, err)
 		debugf("LE%d(%v).", thrNumber, err)
 	}
 	}

+ 5 - 5
libnetwork/network.go

@@ -133,7 +133,7 @@ func (n *network) Delete() error {
 
 
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
 	if name == "" {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	}
 	ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})}
 	ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})}
 	ep.id = types.UUID(stringid.GenerateRandomID())
 	ep.id = types.UUID(stringid.GenerateRandomID())
@@ -173,7 +173,7 @@ func (n *network) WalkEndpoints(walker EndpointWalker) {
 
 
 func (n *network) EndpointByName(name string) (Endpoint, error) {
 func (n *network) EndpointByName(name string) (Endpoint, error) {
 	if name == "" {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	}
 	var e Endpoint
 	var e Endpoint
 
 
@@ -188,7 +188,7 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
 	n.WalkEndpoints(s)
 	n.WalkEndpoints(s)
 
 
 	if e == nil {
 	if e == nil {
-		return nil, ErrNoSuchEndpoint
+		return nil, ErrNoSuchEndpoint(name)
 	}
 	}
 
 
 	return e, nil
 	return e, nil
@@ -196,12 +196,12 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
 
 
 func (n *network) EndpointByID(id string) (Endpoint, error) {
 func (n *network) EndpointByID(id string) (Endpoint, error) {
 	if id == "" {
 	if id == "" {
-		return nil, ErrInvalidID
+		return nil, ErrInvalidID(id)
 	}
 	}
 	n.Lock()
 	n.Lock()
 	defer n.Unlock()
 	defer n.Unlock()
 	if e, ok := n.endpoints[types.UUID(id)]; ok {
 	if e, ok := n.endpoints[types.UUID(id)]; ok {
 		return e, nil
 		return e, nil
 	}
 	}
-	return nil, ErrNoSuchEndpoint
+	return nil, ErrNoSuchEndpoint(id)
 }
 }

+ 167 - 7
libnetwork/types/types.go

@@ -11,13 +11,6 @@ import (
 // UUID represents a globally unique ID of various resources like network and endpoint
 // UUID represents a globally unique ID of various resources like network and endpoint
 type UUID string
 type UUID string
 
 
-// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid.
-type ErrInvalidProtocolBinding string
-
-func (ipb ErrInvalidProtocolBinding) Error() string {
-	return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
-}
-
 // TransportPort represent a local Layer 4 endpoint
 // TransportPort represent a local Layer 4 endpoint
 type TransportPort struct {
 type TransportPort struct {
 	Proto Protocol
 	Proto Protocol
@@ -110,6 +103,13 @@ func (p *PortBinding) Equal(o *PortBinding) bool {
 	return true
 	return true
 }
 }
 
 
+// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid.
+type ErrInvalidProtocolBinding string
+
+func (ipb ErrInvalidProtocolBinding) Error() string {
+	return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
+}
+
 const (
 const (
 	// ICMP is for the ICMP ip protocol
 	// ICMP is for the ICMP ip protocol
 	ICMP = 1
 	ICMP = 1
@@ -183,3 +183,163 @@ func CompareIPNet(a, b *net.IPNet) bool {
 	}
 	}
 	return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
 	return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
 }
 }
+
+/******************************
+ * Well-known Error Interfaces
+ ******************************/
+
+// MaskableError is an interface for errors which can be ignored by caller
+type MaskableError interface {
+	// Maskable makes implementer into MaskableError type
+	Maskable()
+}
+
+// BadRequestError is an interface for errors originated by a bad request
+type BadRequestError interface {
+	// BadRequest makes implementer into BadRequestError type
+	BadRequest()
+}
+
+// NotFoundError is an interface for errors raised because a needed resource is not available
+type NotFoundError interface {
+	// NotFound makes implementer into NotFoundError type
+	NotFound()
+}
+
+// ForbiddenError is an interface for errors which denote an valid request that cannot be honored
+type ForbiddenError interface {
+	// Forbidden makes implementer into ForbiddenError type
+	Forbidden()
+}
+
+// NoServiceError  is an interface for errors returned when the required service is not available
+type NoServiceError interface {
+	// NoService makes implementer into NoServiceError type
+	NoService()
+}
+
+// TimeoutError  is an interface for errors raised because of timeout
+type TimeoutError interface {
+	// Timeout makes implementer into TimeoutError type
+	Timeout()
+}
+
+// NotImplementedError  is an interface for errors raised because of requested functionality is not yet implemented
+type NotImplementedError interface {
+	// NotImplemented makes implementer into NotImplementedError type
+	NotImplemented()
+}
+
+// InternalError is an interface for errors raised because of an internal error
+type InternalError interface {
+	// Internal makes implementer into InternalError type
+	Internal()
+}
+
+/******************************
+ * Weel-known Error Formatters
+ ******************************/
+
+// BadRequestErrorf creates an instance of BadRequestError
+func BadRequestErrorf(format string, params ...interface{}) error {
+	return badRequest(fmt.Sprintf(format, params...))
+}
+
+// NotFoundErrorf creates an instance of NotFoundError
+func NotFoundErrorf(format string, params ...interface{}) error {
+	return notFound(fmt.Sprintf(format, params...))
+}
+
+// ForbiddenErrorf creates an instance of ForbiddenError
+func ForbiddenErrorf(format string, params ...interface{}) error {
+	return forbidden(fmt.Sprintf(format, params...))
+}
+
+// NoServiceErrorf creates an instance of NoServiceError
+func NoServiceErrorf(format string, params ...interface{}) error {
+	return noService(fmt.Sprintf(format, params...))
+}
+
+// NotImplementedErrorf creates an instance of NotImplementedError
+func NotImplementedErrorf(format string, params ...interface{}) error {
+	return notImpl(fmt.Sprintf(format, params...))
+}
+
+// TimeoutErrorf creates an instance of TimeoutError
+func TimeoutErrorf(format string, params ...interface{}) error {
+	return timeout(fmt.Sprintf(format, params...))
+}
+
+// InternalErrorf creates an instance of InternalError
+func InternalErrorf(format string, params ...interface{}) error {
+	return internal(fmt.Sprintf(format, params...))
+}
+
+// InternalMaskableErrorf creates an instance of InternalError and MaskableError
+func InternalMaskableErrorf(format string, params ...interface{}) error {
+	return maskInternal(fmt.Sprintf(format, params...))
+}
+
+/***********************
+ * Internal Error Types
+ ***********************/
+type badRequest string
+
+func (br badRequest) Error() string {
+	return string(br)
+}
+func (br badRequest) BadRequest() {}
+
+type maskBadRequest string
+
+type notFound string
+
+func (nf notFound) Error() string {
+	return string(nf)
+}
+func (nf notFound) NotFound() {}
+
+type forbidden string
+
+func (frb forbidden) Error() string {
+	return string(frb)
+}
+func (frb forbidden) Forbidden() {}
+
+type noService string
+
+func (ns noService) Error() string {
+	return string(ns)
+}
+func (ns noService) NoService() {}
+
+type maskNoService string
+
+type timeout string
+
+func (to timeout) Error() string {
+	return string(to)
+}
+func (to timeout) Timeout() {}
+
+type notImpl string
+
+func (ni notImpl) Error() string {
+	return string(ni)
+}
+func (ni notImpl) NotImplemented() {}
+
+type internal string
+
+func (nt internal) Error() string {
+	return string(nt)
+}
+func (nt internal) Internal() {}
+
+type maskInternal string
+
+func (mnt maskInternal) Error() string {
+	return string(mnt)
+}
+func (mnt maskInternal) Internal() {}
+func (mnt maskInternal) Maskable() {}

+ 99 - 0
libnetwork/types/types_test.go

@@ -0,0 +1,99 @@
+package types
+
+import (
+	"testing"
+
+	_ "github.com/docker/libnetwork/netutils"
+)
+
+func TestErrorConstructors(t *testing.T) {
+	var err error
+
+	err = BadRequestErrorf("Io ho %d uccello", 1)
+	if err.Error() != "Io ho 1 uccello" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(BadRequestError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = NotFoundErrorf("Can't find the %s", "keys")
+	if err.Error() != "Can't find the keys" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(NotFoundError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = ForbiddenErrorf("Can't open door %d", 2)
+	if err.Error() != "Can't open door 2" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(ForbiddenError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = NotImplementedErrorf("Functionality %s is not implemented", "x")
+	if err.Error() != "Functionality x is not implemented" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(NotImplementedError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = TimeoutErrorf("Process %s timed out", "abc")
+	if err.Error() != "Process abc timed out" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(TimeoutError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = NoServiceErrorf("Driver %s is not available", "mh")
+	if err.Error() != "Driver mh is not available" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(NoServiceError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = InternalErrorf("Not sure what happened")
+	if err.Error() != "Not sure what happened" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(InternalError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = InternalMaskableErrorf("Minor issue, it can be ignored")
+	if err.Error() != "Minor issue, it can be ignored" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(InternalError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); !ok {
+		t.Fatal(err)
+	}
+}