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>
... | ... |
@@ -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 |