Browse code

Fix some places where low-level errors bubbled up

Found a couple of places where pretty low level errors were never being
wrapped with any sort of context.

For example, if you try to create a local volume using some bad mount
options, the kernel will return `invalid argument` when we try to mount
it at container start.
What would happen is a user would `docker run` with this volume and get
an error like `Error response from daemon: invalid argument`.

This uses github.com/pkg/errors to provide some context to the error
message without masking the original error.

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

Brian Goff authored on 2016/09/23 23:38:19
Showing 4 changed files
... ...
@@ -12,6 +12,8 @@ import (
12 12
 	"reflect"
13 13
 	"sync"
14 14
 
15
+	"github.com/pkg/errors"
16
+
15 17
 	"github.com/Sirupsen/logrus"
16 18
 	"github.com/docker/docker/pkg/idtools"
17 19
 	"github.com/docker/docker/pkg/mount"
... ...
@@ -93,7 +95,7 @@ func New(scope string, rootUID, rootGID int) (*Root, error) {
93 93
 		if b, err := ioutil.ReadFile(optsFilePath); err == nil {
94 94
 			opts := optsConfig{}
95 95
 			if err := json.Unmarshal(b, &opts); err != nil {
96
-				return nil, err
96
+				return nil, errors.Wrapf(err, "error while unmarshaling volume options for volume: %s", name)
97 97
 			}
98 98
 			// Make sure this isn't an empty optsConfig.
99 99
 			// This could be empty due to buggy behavior in older versions of Docker.
... ...
@@ -168,7 +170,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error
168 168
 		if os.IsExist(err) {
169 169
 			return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path))
170 170
 		}
171
-		return nil, err
171
+		return nil, errors.Wrapf(err, "error while creating volume path '%s'", path)
172 172
 	}
173 173
 
174 174
 	var err error
... ...
@@ -194,7 +196,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error
194 194
 			return nil, err
195 195
 		}
196 196
 		if err = ioutil.WriteFile(filepath.Join(filepath.Dir(path), "opts.json"), b, 600); err != nil {
197
-			return nil, err
197
+			return nil, errors.Wrap(err, "error while persisting volume options")
198 198
 		}
199 199
 	}
200 200
 
... ...
@@ -240,7 +242,7 @@ func removePath(path string) error {
240 240
 		if os.IsNotExist(err) {
241 241
 			return nil
242 242
 		}
243
-		return err
243
+		return errors.Wrapf(err, "error removing volume path '%s'", path)
244 244
 	}
245 245
 	return nil
246 246
 }
... ...
@@ -327,7 +329,7 @@ func (v *localVolume) Unmount(id string) error {
327 327
 		if v.active.count == 0 {
328 328
 			if err := mount.Unmount(v.path); err != nil {
329 329
 				v.active.count++
330
-				return err
330
+				return errors.Wrapf(err, "error while unmounting volume path '%s'", v.path)
331 331
 			}
332 332
 			v.active.mounted = false
333 333
 		}
... ...
@@ -10,6 +10,8 @@ import (
10 10
 	"path/filepath"
11 11
 	"strings"
12 12
 
13
+	"src/github.com/pkg/errors"
14
+
13 15
 	"github.com/docker/docker/pkg/mount"
14 16
 )
15 17
 
... ...
@@ -29,6 +31,10 @@ type optsConfig struct {
29 29
 	MountDevice string
30 30
 }
31 31
 
32
+func (o *optsConfig) String() string {
33
+	return fmt.Sprintf("type='%s' device='%s' o='%s'", o.MountType, o.MountDevice, o.MountOpts)
34
+}
35
+
32 36
 // scopedPath verifies that the path where the volume is located
33 37
 // is under Docker's root and the valid local paths.
34 38
 func (r *Root) scopedPath(realPath string) bool {
... ...
@@ -65,5 +71,6 @@ func (v *localVolume) mount() error {
65 65
 	if v.opts.MountDevice == "" {
66 66
 		return fmt.Errorf("missing device in volume options")
67 67
 	}
68
-	return mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, v.opts.MountOpts)
68
+	err := mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, v.opts.MountOpts)
69
+	return errors.Wrapf(err, "error while mounting volume with options: %s", v.opts)
69 70
 }
... ...
@@ -8,6 +8,8 @@ import (
8 8
 	"sync"
9 9
 	"time"
10 10
 
11
+	"github.com/pkg/errors"
12
+
11 13
 	"github.com/Sirupsen/logrus"
12 14
 	"github.com/boltdb/bolt"
13 15
 	"github.com/docker/docker/pkg/locker"
... ...
@@ -70,13 +72,13 @@ func New(rootPath string) (*VolumeStore, error) {
70 70
 		var err error
71 71
 		vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
72 72
 		if err != nil {
73
-			return nil, err
73
+			return nil, errors.Wrap(err, "error while opening volume store metadata database")
74 74
 		}
75 75
 
76 76
 		// initialize volumes bucket
77 77
 		if err := vs.db.Update(func(tx *bolt.Tx) error {
78 78
 			if _, err := tx.CreateBucketIfNotExists([]byte(volumeBucketName)); err != nil {
79
-				return err
79
+				return errors.Wrap(err, "error while setting up volume store metadata database")
80 80
 			}
81 81
 
82 82
 			return nil
... ...
@@ -299,7 +301,7 @@ func (s *VolumeStore) create(name, driverName string, opts, labels map[string]st
299 299
 			err := b.Put([]byte(name), volData)
300 300
 			return err
301 301
 		}); err != nil {
302
-			return nil, err
302
+			return nil, errors.Wrap(err, "error while persisting volume metadata")
303 303
 		}
304 304
 	}
305 305
 
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"github.com/docker/docker/pkg/idtools"
12 12
 	"github.com/docker/docker/pkg/stringid"
13 13
 	"github.com/opencontainers/runc/libcontainer/label"
14
+	"github.com/pkg/errors"
14 15
 )
15 16
 
16 17
 // DefaultDriverName is the driver name used for the driver
... ...
@@ -114,7 +115,8 @@ func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (string, err
114 114
 		if m.ID == "" {
115 115
 			m.ID = stringid.GenerateNonCryptoID()
116 116
 		}
117
-		return m.Volume.Mount(m.ID)
117
+		path, err := m.Volume.Mount(m.ID)
118
+		return path, errors.Wrapf(err, "error while mounting volume '%s'", m.Source)
118 119
 	}
119 120
 	if len(m.Source) == 0 {
120 121
 		return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined")
... ...
@@ -126,14 +128,14 @@ func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (string, err
126 126
 		if err := idtools.MkdirAllNewAs(m.Source, 0755, rootUID, rootGID); err != nil {
127 127
 			if perr, ok := err.(*os.PathError); ok {
128 128
 				if perr.Err != syscall.ENOTDIR {
129
-					return "", err
129
+					return "", errors.Wrapf(err, "error while creating mount source path '%s'", m.Source)
130 130
 				}
131 131
 			}
132 132
 		}
133 133
 	}
134 134
 	if label.RelabelNeeded(m.Mode) {
135 135
 		if err := label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode)); err != nil {
136
-			return "", err
136
+			return "", errors.Wrapf(err, "error setting label on mount source '%s'", m.Source)
137 137
 		}
138 138
 	}
139 139
 	return m.Source, nil