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>
This commit is contained in:
Alessandro Boch 2015-05-14 14:56:15 -07:00
parent e2bdf92d6b
commit 50964c9948
27 changed files with 1025 additions and 347 deletions

View File

@ -7,6 +7,7 @@ import (
"net/http"
"github.com/docker/libnetwork"
"github.com/docker/libnetwork/types"
"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))
}
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: 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))
}
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: 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 {
// 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 {

View File

@ -193,8 +193,8 @@ func TestCreateDeleteNetwork(t *testing.T) {
if errRsp == &createdResponse {
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{})
@ -1305,3 +1305,92 @@ func TestHttpHandlerGood(t *testing.T) {
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")
}
}

View File

@ -134,7 +134,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver)
// are network specific and modeled in a generic way.
func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
if name == "" {
return nil, ErrInvalidName
return nil, ErrInvalidName(name)
}
// Check if a driver for the specified network type is available
c.Lock()
@ -203,7 +203,7 @@ func (c *controller) WalkNetworks(walker NetworkWalker) {
func (c *controller) NetworkByName(name string) (Network, error) {
if name == "" {
return nil, ErrInvalidName
return nil, ErrInvalidName(name)
}
var n Network
@ -218,7 +218,7 @@ func (c *controller) NetworkByName(name string) (Network, error) {
c.WalkNetworks(s)
if n == nil {
return nil, ErrNoSuchNetwork
return nil, ErrNoSuchNetwork(name)
}
return n, nil
@ -226,14 +226,14 @@ func (c *controller) NetworkByName(name string) (Network, error) {
func (c *controller) NetworkByID(id string) (Network, error) {
if id == "" {
return nil, ErrInvalidID
return nil, ErrInvalidID(id)
}
c.Lock()
defer c.Unlock()
if n, ok := c.networks[types.UUID(id)]; ok {
return n, nil
}
return nil, ErrNoSuchNetwork
return nil, ErrNoSuchNetwork(id)
}
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.
_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
if err != nil {
if err == plugins.ErrNotFound {
return nil, types.NotFoundErrorf(err.Error())
}
return nil, err
}
c.Lock()
defer c.Unlock()
d, ok := c.drivers[networkType]
if !ok {
return nil, ErrInvalidNetworkDriver
return nil, ErrInvalidNetworkDriver(networkType)
}
return d, nil
}

View File

@ -1,24 +1,11 @@
package driverapi
import (
"errors"
"fmt"
"net"
"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
const NetworkPluginEndpointType = "NetworkDriver"
@ -124,14 +111,6 @@ type JoinInfo interface {
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
type DriverCallback interface {
// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance

56
driverapi/errors.go Normal file
View File

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

View File

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

View File

@ -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
drivers/bridge/errors.go Normal file
View File

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

View File

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

View File

@ -125,8 +125,8 @@ func TestLinkCreateTwo(t *testing.T) {
te2 := &testEndpoint{ifaces: []*testInterface{}}
err = d.CreateEndpoint("dummy", "ep", te2, 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 {
t.Fatalf("Expected to fail while trying to add same endpoint twice")

View File

@ -1,6 +1,8 @@
package bridge
import log "github.com/Sirupsen/logrus"
import (
log "github.com/Sirupsen/logrus"
)
func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
addrv4, _, err := i.addresses()
@ -10,7 +12,7 @@ func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR)
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

View File

@ -1,11 +1,13 @@
package bridge
import log "github.com/Sirupsen/logrus"
import (
log "github.com/Sirupsen/logrus"
)
func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error {
log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
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

View File

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

View File

@ -47,7 +47,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
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)
}
}

View File

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

View File

@ -71,7 +71,7 @@ func setupBridgeIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4)
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
@ -114,7 +114,7 @@ func electBridgeIPv4(config *NetworkConfiguration) (*net.IPNet, error) {
func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
return ErrInvalidGateway
return &ErrInvalidGateway{}
}
if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
return err

View File

@ -37,7 +37,7 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
// Add the default link local ipv6 address if it doesn't exist
if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
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 {
if config.FixedCIDRv6 == nil {
return ErrInvalidContainerSubnet
return &ErrInvalidContainerSubnet{}
}
if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
return ErrInvalidGateway
return &ErrInvalidGateway{}
}
if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
return err

View File

@ -1,6 +1,8 @@
package bridge
import "github.com/vishvananda/netlink"
import (
"github.com/vishvananda/netlink"
)
func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error {
// 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.
if addrv4.IPNet == nil {
return ErrNoIPAddr
return &ErrNoIPAddr{}
}
// Verify that the bridge IPv4 address matches the requested configuration.
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

View File

@ -31,37 +31,37 @@ func Init(dc driverapi.DriverCallback) 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 {
return driverapi.ErrNotImplemented
return &driverapi.ErrNotImplemented{}
}
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 {
return driverapi.ErrNotImplemented
return &driverapi.ErrNotImplemented{}
}
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) {
return nil, driverapi.ErrNotImplemented
return nil, &driverapi.ErrNotImplemented{}
}
// 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 {
return driverapi.ErrNotImplemented
return &driverapi.ErrNotImplemented{}
}
// Leave method is invoked when a Sandbox detaches from an endpoint.
func (d *driver) Leave(nid, eid types.UUID) error {
return driverapi.ErrNotImplemented
return &driverapi.ErrNotImplemented{}
}
func (d *driver) Type() string {

View File

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

124
error.go
View File

@ -1,34 +1,83 @@
package libnetwork
import (
"errors"
"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
// known to libnetwork.
@ -38,13 +87,19 @@ func (nt NetworkTypeError) Error() string {
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.
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
// a network with the same name and id.
type UnknownNetworkError struct {
@ -56,6 +111,9 @@ func (une *UnknownNetworkError) Error() string {
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
// endpoints in it.
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)
}
// Forbidden denotes the type of this error
func (aee *ActiveEndpointsError) Forbidden() {}
// UnknownEndpointError is returned when libnetwork could not find in it's database
// an endpoint with the same name and id.
type UnknownEndpointError struct {
@ -78,6 +139,9 @@ func (uee *UnknownEndpointError) Error() string {
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
// containers attached to it.
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)
}
// Forbidden denotes the type of this error
func (ace *ActiveContainerError) Forbidden() {}
// InvalidContainerIDError is returned when an invalid container id is passed
// in Join/Leave
type InvalidContainerIDError string
@ -96,3 +163,6 @@ type InvalidContainerIDError string
func (id InvalidContainerIDError) Error() string {
return fmt.Sprintf("invalid container id %s", string(id))
}
// BadRequest denotes the type of this error
func (id InvalidContainerIDError) BadRequest() {}

51
errors_test.go Normal file
View File

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

View File

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

View File

@ -290,7 +290,7 @@ func TestNilRemoteDriver(t *testing.T) {
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)
}
}
@ -338,8 +338,9 @@ func TestNetworkName(t *testing.T) {
if err == nil {
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"
@ -475,8 +476,8 @@ func TestUnknownEndpoint(t *testing.T) {
if err == nil {
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")
@ -613,15 +614,15 @@ func TestControllerQuery(t *testing.T) {
if err == nil {
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("")
if err == nil {
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)
}
@ -629,7 +630,7 @@ func TestControllerQuery(t *testing.T) {
if err == nil {
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)
}
@ -695,15 +696,15 @@ func TestNetworkQuery(t *testing.T) {
if err == nil {
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")
if err == nil {
t.Fatalf("EndpointByName() succeeded with unknown target name")
}
if err != libnetwork.ErrNoSuchEndpoint {
if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
t.Fatal(err)
}
if e != nil {
@ -722,7 +723,7 @@ func TestNetworkQuery(t *testing.T) {
if err == nil {
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)
}
}
@ -891,7 +892,7 @@ func TestEndpointMultipleJoins(t *testing.T) {
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)
}
}
@ -917,7 +918,7 @@ func TestEndpointInvalidLeave(t *testing.T) {
}
if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
if err != libnetwork.ErrNoContainer {
if _, ok := err.(libnetwork.ErrNoContainer); !ok {
t.Fatalf("Failed for unexpected reason: %v", err)
}
}
@ -1297,8 +1298,10 @@ func TestValidRemoteDriver(t *testing.T) {
_, err = controller.NewNetwork("valid-network-driver", "dummy",
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")
runtime.LockOSThread()
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)
}
@ -1384,8 +1389,10 @@ func parallelLeave(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
err := ep.Leave("racing_container")
runtime.LockOSThread()
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)
}

View File

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

View File

@ -11,13 +11,6 @@ import (
// UUID represents a globally unique ID of various resources like network and endpoint
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
type TransportPort struct {
Proto Protocol
@ -110,6 +103,13 @@ func (p *PortBinding) Equal(o *PortBinding) bool {
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 (
// ICMP is for the ICMP ip protocol
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)
}
/******************************
* 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
types/types_test.go Normal file
View File

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