Browse code

Refactor volume store's error usage

Uses an errors API similar the `net` package.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2015/10/20 09:41:22
Showing 5 changed files
... ...
@@ -7,7 +7,7 @@ import (
7 7
 
8 8
 	"github.com/Sirupsen/logrus"
9 9
 	derr "github.com/docker/docker/errors"
10
-	"github.com/docker/docker/volume/store"
10
+	volumestore "github.com/docker/docker/volume/store"
11 11
 )
12 12
 
13 13
 // ContainerRmConfig is a holder for passing in runtime config.
... ...
@@ -153,7 +153,7 @@ func (daemon *Daemon) VolumeRm(name string) error {
153 153
 		return err
154 154
 	}
155 155
 	if err := daemon.volumes.Remove(v); err != nil {
156
-		if err == store.ErrVolumeInUse {
156
+		if volumestore.IsInUse(err) {
157 157
 			return derr.ErrorCodeRmVolumeInUse.WithArgs(err)
158 158
 		}
159 159
 		return derr.ErrorCodeRmVolume.WithArgs(name, err)
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"strings"
5 5
 
6 6
 	derr "github.com/docker/docker/errors"
7
-	"github.com/docker/docker/volume/store"
7
+	volumestore "github.com/docker/docker/volume/store"
8 8
 )
9 9
 
10 10
 func (daemon *Daemon) prepareMountPoints(container *Container) error {
... ...
@@ -34,7 +34,7 @@ func (daemon *Daemon) removeMountPoints(container *Container, rm bool) error {
34 34
 			// not an error, but an implementation detail.
35 35
 			// This prevents docker from logging "ERROR: Volume in use"
36 36
 			// where there is another container using the volume.
37
-			if err != nil && err != store.ErrVolumeInUse {
37
+			if err != nil && !volumestore.IsInUse(err) {
38 38
 				rmErrors = append(rmErrors, err.Error())
39 39
 			}
40 40
 		}
41 41
new file mode 100644
... ...
@@ -0,0 +1,58 @@
0
+package store
1
+
2
+import "errors"
3
+
4
+var (
5
+	// errVolumeInUse is a typed error returned when trying to remove a volume that is currently in use by a container
6
+	errVolumeInUse = errors.New("volume is in use")
7
+	// errNoSuchVolume is a typed error returned if the requested volume doesn't exist in the volume store
8
+	errNoSuchVolume = errors.New("no such volume")
9
+	// errInvalidName is a typed error returned when creating a volume with a name that is not valid on the platform
10
+	errInvalidName = errors.New("volume name is not valid on this platform")
11
+)
12
+
13
+// OpErr is the error type returned by functions in the store package. It describes
14
+// the operation, volume name, and error.
15
+type OpErr struct {
16
+	// Err is the error that occurred during the operation.
17
+	Err error
18
+	// Op is the operation which caused the error, such as "create", or "list".
19
+	Op string
20
+	// Name is the name of the resource being requested for this op, typically the volume name or the driver name.
21
+	Name string
22
+}
23
+
24
+// Error satifies the built-in error interface type.
25
+func (e *OpErr) Error() string {
26
+	if e == nil {
27
+		return "<nil>"
28
+	}
29
+	s := e.Op
30
+	if e.Name != "" {
31
+		s = s + " " + e.Name
32
+	}
33
+
34
+	s = s + ": " + e.Err.Error()
35
+	return s
36
+}
37
+
38
+// IsInUse returns a boolean indicating whether the error indicates that a
39
+// volume is in use
40
+func IsInUse(err error) bool {
41
+	return isErr(err, errVolumeInUse)
42
+}
43
+
44
+// IsNotExist returns a boolean indicating whether the error indicates that the volume does not exist
45
+func IsNotExist(err error) bool {
46
+	return isErr(err, errNoSuchVolume)
47
+}
48
+
49
+func isErr(err error, expected error) bool {
50
+	switch pe := err.(type) {
51
+	case nil:
52
+		return false
53
+	case *OpErr:
54
+		err = pe.Err
55
+	}
56
+	return err == expected
57
+}
... ...
@@ -1,7 +1,6 @@
1 1
 package store
2 2
 
3 3
 import (
4
-	"errors"
5 4
 	"sync"
6 5
 
7 6
 	"github.com/Sirupsen/logrus"
... ...
@@ -10,15 +9,6 @@ import (
10 10
 	"github.com/docker/docker/volume/drivers"
11 11
 )
12 12
 
13
-var (
14
-	// ErrVolumeInUse is a typed error returned when trying to remove a volume that is currently in use by a container
15
-	ErrVolumeInUse = errors.New("volume is in use")
16
-	// ErrNoSuchVolume is a typed error returned if the requested volume doesn't exist in the volume store
17
-	ErrNoSuchVolume = errors.New("no such volume")
18
-	// ErrInvalidName is a typed error returned when creating a volume with a name that is not valid on the platform
19
-	ErrInvalidName = errors.New("volume name is not valid on this platform")
20
-)
21
-
22 13
 // New initializes a VolumeStore to keep
23 14
 // reference counting of volumes in the system.
24 15
 func New() *VolumeStore {
... ...
@@ -81,7 +71,7 @@ func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (v
81 81
 
82 82
 	vd, err := volumedrivers.GetDriver(driverName)
83 83
 	if err != nil {
84
-		return nil, err
84
+		return nil, &OpErr{Err: err, Name: driverName, Op: "create"}
85 85
 	}
86 86
 
87 87
 	// Validate the name in a platform-specific manner
... ...
@@ -90,12 +80,12 @@ func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (v
90 90
 		return nil, err
91 91
 	}
92 92
 	if !valid {
93
-		return nil, ErrInvalidName
93
+		return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"}
94 94
 	}
95 95
 
96 96
 	v, err := vd.Create(name, opts)
97 97
 	if err != nil {
98
-		return nil, err
98
+		return nil, &OpErr{Op: "create", Name: name, Err: err}
99 99
 	}
100 100
 
101 101
 	s.set(name, &volumeCounter{v, 0})
... ...
@@ -110,7 +100,7 @@ func (s *VolumeStore) Get(name string) (volume.Volume, error) {
110 110
 
111 111
 	vc, exists := s.get(name)
112 112
 	if !exists {
113
-		return nil, ErrNoSuchVolume
113
+		return nil, &OpErr{Err: errNoSuchVolume, Name: name, Op: "get"}
114 114
 	}
115 115
 	return vc.Volume, nil
116 116
 }
... ...
@@ -124,19 +114,19 @@ func (s *VolumeStore) Remove(v volume.Volume) error {
124 124
 	logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
125 125
 	vc, exists := s.get(name)
126 126
 	if !exists {
127
-		return ErrNoSuchVolume
127
+		return &OpErr{Err: errNoSuchVolume, Name: name, Op: "remove"}
128 128
 	}
129 129
 
130 130
 	if vc.count > 0 {
131
-		return ErrVolumeInUse
131
+		return &OpErr{Err: errVolumeInUse, Name: name, Op: "remove"}
132 132
 	}
133 133
 
134 134
 	vd, err := volumedrivers.GetDriver(vc.DriverName())
135 135
 	if err != nil {
136
-		return err
136
+		return &OpErr{Err: err, Name: vc.DriverName(), Op: "remove"}
137 137
 	}
138 138
 	if err := vd.Remove(vc.Volume); err != nil {
139
-		return err
139
+		return &OpErr{Err: err, Name: name, Op: "remove"}
140 140
 	}
141 141
 
142 142
 	s.remove(name)
... ...
@@ -1,6 +1,7 @@
1 1
 package store
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"testing"
5 6
 
6 7
 	"github.com/docker/docker/volume"
... ...
@@ -30,8 +31,8 @@ func TestGet(t *testing.T) {
30 30
 		t.Fatalf("Expected fake1 volume, got %v", v)
31 31
 	}
32 32
 
33
-	if _, err := s.Get("fake4"); err != ErrNoSuchVolume {
34
-		t.Fatalf("Expected ErrNoSuchVolume error, got %v", err)
33
+	if _, err := s.Get("fake4"); !IsNotExist(err) {
34
+		t.Fatalf("Expected IsNotExist error, got %v", err)
35 35
 	}
36 36
 }
37 37
 
... ...
@@ -54,24 +55,25 @@ func TestCreate(t *testing.T) {
54 54
 	}
55 55
 
56 56
 	_, err = s.Create("fakeError", "fake", map[string]string{"error": "create error"})
57
-	if err == nil || err.Error() != "create error" {
58
-		t.Fatalf("Expected create error, got %v", err)
57
+	expected := &OpErr{Op: "create", Name: "fakeError", Err: errors.New("create error")}
58
+	if err != nil && err.Error() != expected.Error() {
59
+		t.Fatalf("Expected create fakeError: create error, got %v", err)
59 60
 	}
60 61
 }
61 62
 
62 63
 func TestRemove(t *testing.T) {
63 64
 	volumedrivers.Register(vt.FakeDriver{}, "fake")
64 65
 	s := New()
65
-	if err := s.Remove(vt.NoopVolume{}); err != ErrNoSuchVolume {
66
-		t.Fatalf("Expected ErrNoSuchVolume error, got %v", err)
66
+	if err := s.Remove(vt.NoopVolume{}); !IsNotExist(err) {
67
+		t.Fatalf("Expected IsNotExist error, got %v", err)
67 68
 	}
68 69
 	v, err := s.Create("fake1", "fake", nil)
69 70
 	if err != nil {
70 71
 		t.Fatal(err)
71 72
 	}
72 73
 	s.Increment(v)
73
-	if err := s.Remove(v); err != ErrVolumeInUse {
74
-		t.Fatalf("Expected ErrVolumeInUse error, got %v", err)
74
+	if err := s.Remove(v); !IsInUse(err) {
75
+		t.Fatalf("Expected IsInUse error, got %v", err)
75 76
 	}
76 77
 	s.Decrement(v)
77 78
 	if err := s.Remove(v); err != nil {