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 |