Skip to content

Commit 50964c9

Browse files
committed
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 <[email protected]>
1 parent e2bdf92 commit 50964c9

27 files changed

Lines changed: 1025 additions & 347 deletions

api/api.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net/http"
88

99
"github.com/docker/libnetwork"
10+
"github.com/docker/libnetwork/types"
1011
"github.com/gorilla/mux"
1112
)
1213

@@ -434,7 +435,7 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N
434435
panic(fmt.Sprintf("unexpected selector for network search: %d", by))
435436
}
436437
if err != nil {
437-
if err == libnetwork.ErrNoSuchNetwork {
438+
if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
438439
return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound}
439440
}
440441
return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
@@ -460,7 +461,7 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int)
460461
panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
461462
}
462463
if err != nil {
463-
if err == libnetwork.ErrNoSuchEndpoint {
464+
if _, ok := err.(libnetwork.ErrNoSuchEndpoint); ok {
464465
return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
465466
}
466467
return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
@@ -469,9 +470,26 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int)
469470
}
470471

471472
func convertNetworkError(err error) *responseStatus {
472-
// No real libnetwork error => http error code conversion for now.
473-
// Will came in later when new interface for libnetwork error is vailable
474-
return &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
473+
var code int
474+
switch err.(type) {
475+
case types.BadRequestError:
476+
code = http.StatusBadRequest
477+
case types.ForbiddenError:
478+
code = http.StatusForbidden
479+
case types.NotFoundError:
480+
code = http.StatusNotFound
481+
case types.TimeoutError:
482+
code = http.StatusRequestTimeout
483+
case types.NotImplementedError:
484+
code = http.StatusNotImplemented
485+
case types.NoServiceError:
486+
code = http.StatusServiceUnavailable
487+
case types.InternalError:
488+
code = http.StatusInternalServerError
489+
default:
490+
code = http.StatusInternalServerError
491+
}
492+
return &responseStatus{Status: err.Error(), StatusCode: code}
475493
}
476494

477495
func writeJSON(w http.ResponseWriter, code int, v interface{}) error {

api/api_test.go

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ func TestCreateDeleteNetwork(t *testing.T) {
193193
if errRsp == &createdResponse {
194194
t.Fatalf("Expected to fail but succeeded")
195195
}
196-
if errRsp.StatusCode != http.StatusBadRequest {
197-
t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
196+
if errRsp.StatusCode != http.StatusNotFound {
197+
t.Fatalf("Expected StatusNotFound status code, got: %v", errRsp)
198198
}
199199

200200
ops := make(map[string]interface{})
@@ -1305,3 +1305,92 @@ func TestHttpHandlerGood(t *testing.T) {
13051305
t.Fatalf("Incongruent resource found")
13061306
}
13071307
}
1308+
1309+
type bre struct{}
1310+
1311+
func (b *bre) Error() string {
1312+
return "I am a bad request error"
1313+
}
1314+
func (b *bre) BadRequest() {}
1315+
1316+
type nfe struct{}
1317+
1318+
func (n *nfe) Error() string {
1319+
return "I am a not found error"
1320+
}
1321+
func (n *nfe) NotFound() {}
1322+
1323+
type forb struct{}
1324+
1325+
func (f *forb) Error() string {
1326+
return "I am a bad request error"
1327+
}
1328+
func (f *forb) Forbidden() {}
1329+
1330+
type notimpl struct{}
1331+
1332+
func (nip *notimpl) Error() string {
1333+
return "I am a not implemented error"
1334+
}
1335+
func (nip *notimpl) NotImplemented() {}
1336+
1337+
type inter struct{}
1338+
1339+
func (it *inter) Error() string {
1340+
return "I am a internal error"
1341+
}
1342+
func (it *inter) Internal() {}
1343+
1344+
type tout struct{}
1345+
1346+
func (to *tout) Error() string {
1347+
return "I am a timeout error"
1348+
}
1349+
func (to *tout) Timeout() {}
1350+
1351+
type noserv struct{}
1352+
1353+
func (nos *noserv) Error() string {
1354+
return "I am a no service error"
1355+
}
1356+
func (nos *noserv) NoService() {}
1357+
1358+
type notclassified struct{}
1359+
1360+
func (noc *notclassified) Error() string {
1361+
return "I am a non classified error"
1362+
}
1363+
1364+
func TestErrorConversion(t *testing.T) {
1365+
if convertNetworkError(new(bre)).StatusCode != http.StatusBadRequest {
1366+
t.Fatalf("Failed to recognize BadRequest error")
1367+
}
1368+
1369+
if convertNetworkError(new(nfe)).StatusCode != http.StatusNotFound {
1370+
t.Fatalf("Failed to recognize NotFound error")
1371+
}
1372+
1373+
if convertNetworkError(new(forb)).StatusCode != http.StatusForbidden {
1374+
t.Fatalf("Failed to recognize Forbidden error")
1375+
}
1376+
1377+
if convertNetworkError(new(notimpl)).StatusCode != http.StatusNotImplemented {
1378+
t.Fatalf("Failed to recognize NotImplemented error")
1379+
}
1380+
1381+
if convertNetworkError(new(inter)).StatusCode != http.StatusInternalServerError {
1382+
t.Fatalf("Failed to recognize Internal error")
1383+
}
1384+
1385+
if convertNetworkError(new(tout)).StatusCode != http.StatusRequestTimeout {
1386+
t.Fatalf("Failed to recognize Timeout error")
1387+
}
1388+
1389+
if convertNetworkError(new(noserv)).StatusCode != http.StatusServiceUnavailable {
1390+
t.Fatalf("Failed to recognize No Service error")
1391+
}
1392+
1393+
if convertNetworkError(new(notclassified)).StatusCode != http.StatusInternalServerError {
1394+
t.Fatalf("Failed to recognize not classified error as Internal error")
1395+
}
1396+
}

controller.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver)
134134
// are network specific and modeled in a generic way.
135135
func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
136136
if name == "" {
137-
return nil, ErrInvalidName
137+
return nil, ErrInvalidName(name)
138138
}
139139
// Check if a driver for the specified network type is available
140140
c.Lock()
@@ -203,7 +203,7 @@ func (c *controller) WalkNetworks(walker NetworkWalker) {
203203

204204
func (c *controller) NetworkByName(name string) (Network, error) {
205205
if name == "" {
206-
return nil, ErrInvalidName
206+
return nil, ErrInvalidName(name)
207207
}
208208
var n Network
209209

@@ -218,22 +218,22 @@ func (c *controller) NetworkByName(name string) (Network, error) {
218218
c.WalkNetworks(s)
219219

220220
if n == nil {
221-
return nil, ErrNoSuchNetwork
221+
return nil, ErrNoSuchNetwork(name)
222222
}
223223

224224
return n, nil
225225
}
226226

227227
func (c *controller) NetworkByID(id string) (Network, error) {
228228
if id == "" {
229-
return nil, ErrInvalidID
229+
return nil, ErrInvalidID(id)
230230
}
231231
c.Lock()
232232
defer c.Unlock()
233233
if n, ok := c.networks[types.UUID(id)]; ok {
234234
return n, nil
235235
}
236-
return nil, ErrNoSuchNetwork
236+
return nil, ErrNoSuchNetwork(id)
237237
}
238238

239239
func (c *controller) sandboxAdd(key string, create bool) (sandbox.Sandbox, error) {
@@ -286,13 +286,16 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
286286
// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
287287
_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
288288
if err != nil {
289+
if err == plugins.ErrNotFound {
290+
return nil, types.NotFoundErrorf(err.Error())
291+
}
289292
return nil, err
290293
}
291294
c.Lock()
292295
defer c.Unlock()
293296
d, ok := c.drivers[networkType]
294297
if !ok {
295-
return nil, ErrInvalidNetworkDriver
298+
return nil, ErrInvalidNetworkDriver(networkType)
296299
}
297300
return d, nil
298301
}

driverapi/driverapi.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,11 @@
11
package driverapi
22

33
import (
4-
"errors"
5-
"fmt"
64
"net"
75

86
"github.com/docker/libnetwork/types"
97
)
108

11-
var (
12-
// ErrEndpointExists is returned if more than one endpoint is added to the network
13-
ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
14-
// ErrNoNetwork is returned if no network with the specified id exists
15-
ErrNoNetwork = errors.New("No network exists")
16-
// ErrNoEndpoint is returned if no endpoint with the specified id exists
17-
ErrNoEndpoint = errors.New("No endpoint exists")
18-
// ErrNotImplemented is returned when a Driver has not implemented an API yet
19-
ErrNotImplemented = errors.New("The API is not implemented yet")
20-
)
21-
229
// NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
2310
const NetworkPluginEndpointType = "NetworkDriver"
2411

@@ -124,14 +111,6 @@ type JoinInfo interface {
124111
SetResolvConfPath(string) error
125112
}
126113

127-
// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered
128-
type ErrActiveRegistration string
129-
130-
// Error interface for ErrActiveRegistration
131-
func (ar ErrActiveRegistration) Error() string {
132-
return fmt.Sprintf("Driver already registered for type %q", string(ar))
133-
}
134-
135114
// DriverCallback provides a Callback interface for Drivers into LibNetwork
136115
type DriverCallback interface {
137116
// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance

driverapi/errors.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package driverapi
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
// ErrNoNetwork is returned if no network with the specified id exists
8+
type ErrNoNetwork string
9+
10+
func (enn ErrNoNetwork) Error() string {
11+
return fmt.Sprintf("No network (%s) exists", string(enn))
12+
}
13+
14+
// NotFound denotes the type of this error
15+
func (enn ErrNoNetwork) NotFound() {}
16+
17+
// ErrEndpointExists is returned if more than one endpoint is added to the network
18+
type ErrEndpointExists string
19+
20+
func (ee ErrEndpointExists) Error() string {
21+
return fmt.Sprintf("Endpoint (%s) already exists (Only one endpoint allowed)", string(ee))
22+
}
23+
24+
// Forbidden denotes the type of this error
25+
func (ee ErrEndpointExists) Forbidden() {}
26+
27+
// ErrNotImplemented is returned when a Driver has not implemented an API yet
28+
type ErrNotImplemented struct{}
29+
30+
func (eni *ErrNotImplemented) Error() string {
31+
return "The API is not implemented yet"
32+
}
33+
34+
// NotImplemented denotes the type of this error
35+
func (eni *ErrNotImplemented) NotImplemented() {}
36+
37+
// ErrNoEndpoint is returned if no endpoint with the specified id exists
38+
type ErrNoEndpoint string
39+
40+
func (ene ErrNoEndpoint) Error() string {
41+
return fmt.Sprintf("No endpoint (%s) exists", string(ene))
42+
}
43+
44+
// NotFound denotes the type of this error
45+
func (ene ErrNoEndpoint) NotFound() {}
46+
47+
// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered
48+
type ErrActiveRegistration string
49+
50+
// Error interface for ErrActiveRegistration
51+
func (ar ErrActiveRegistration) Error() string {
52+
return fmt.Sprintf("Driver already registered for type %q", string(ar))
53+
}
54+
55+
// Forbidden denotes the type of this error
56+
func (ar ErrActiveRegistration) Forbidden() {}

0 commit comments

Comments
 (0)