| package drivers // import "github.com/docker/docker/volume/drivers" |
| |
| import ( |
| "errors" |
| "strings" |
| "time" |
| |
| "github.com/docker/docker/volume" |
| "github.com/sirupsen/logrus" |
| ) |
| |
| var ( |
| errNoSuchVolume = errors.New("no such volume") |
| ) |
| |
| type volumeDriverAdapter struct { |
| name string |
| scopePath func(s string) string |
| capabilities *volume.Capability |
| proxy volumeDriver |
| } |
| |
| func (a *volumeDriverAdapter) Name() string { |
| return a.name |
| } |
| |
| func (a *volumeDriverAdapter) Create(name string, opts map[string]string) (volume.Volume, error) { |
| if err := a.proxy.Create(name, opts); err != nil { |
| return nil, err |
| } |
| return &volumeAdapter{ |
| proxy: a.proxy, |
| name: name, |
| driverName: a.name, |
| scopePath: a.scopePath, |
| }, nil |
| } |
| |
| func (a *volumeDriverAdapter) Remove(v volume.Volume) error { |
| return a.proxy.Remove(v.Name()) |
| } |
| |
| func (a *volumeDriverAdapter) List() ([]volume.Volume, error) { |
| ls, err := a.proxy.List() |
| if err != nil { |
| return nil, err |
| } |
| |
| var out []volume.Volume |
| for _, vp := range ls { |
| out = append(out, &volumeAdapter{ |
| proxy: a.proxy, |
| name: vp.Name, |
| scopePath: a.scopePath, |
| driverName: a.name, |
| eMount: a.scopePath(vp.Mountpoint), |
| }) |
| } |
| return out, nil |
| } |
| |
| func (a *volumeDriverAdapter) Get(name string) (volume.Volume, error) { |
| v, err := a.proxy.Get(name) |
| if err != nil { |
| return nil, err |
| } |
| |
| // plugin may have returned no volume and no error |
| if v == nil { |
| return nil, errNoSuchVolume |
| } |
| |
| return &volumeAdapter{ |
| proxy: a.proxy, |
| name: v.Name, |
| driverName: a.Name(), |
| eMount: v.Mountpoint, |
| createdAt: v.CreatedAt, |
| status: v.Status, |
| scopePath: a.scopePath, |
| }, nil |
| } |
| |
| func (a *volumeDriverAdapter) Scope() string { |
| cap := a.getCapabilities() |
| return cap.Scope |
| } |
| |
| func (a *volumeDriverAdapter) getCapabilities() volume.Capability { |
| if a.capabilities != nil { |
| return *a.capabilities |
| } |
| cap, err := a.proxy.Capabilities() |
| if err != nil { |
| // `GetCapabilities` is a not a required endpoint. |
| // On error assume it's a local-only driver |
| logrus.WithError(err).WithField("driver", a.name).Debug("Volume driver returned an error while trying to query its capabilities, using default capabilities") |
| return volume.Capability{Scope: volume.LocalScope} |
| } |
| |
| // don't spam the warn log below just because the plugin didn't provide a scope |
| if len(cap.Scope) == 0 { |
| cap.Scope = volume.LocalScope |
| } |
| |
| cap.Scope = strings.ToLower(cap.Scope) |
| if cap.Scope != volume.LocalScope && cap.Scope != volume.GlobalScope { |
| logrus.WithField("driver", a.Name()).WithField("scope", a.Scope).Warn("Volume driver returned an invalid scope") |
| cap.Scope = volume.LocalScope |
| } |
| |
| a.capabilities = &cap |
| return cap |
| } |
| |
| type volumeAdapter struct { |
| proxy volumeDriver |
| name string |
| scopePath func(string) string |
| driverName string |
| eMount string // ephemeral host volume path |
| createdAt time.Time // time the directory was created |
| status map[string]interface{} |
| } |
| |
| type proxyVolume struct { |
| Name string |
| Mountpoint string |
| CreatedAt time.Time |
| Status map[string]interface{} |
| } |
| |
| func (a *volumeAdapter) Name() string { |
| return a.name |
| } |
| |
| func (a *volumeAdapter) DriverName() string { |
| return a.driverName |
| } |
| |
| func (a *volumeAdapter) Path() string { |
| if len(a.eMount) == 0 { |
| mountpoint, _ := a.proxy.Path(a.name) |
| a.eMount = a.scopePath(mountpoint) |
| } |
| return a.eMount |
| } |
| |
| func (a *volumeAdapter) CachedPath() string { |
| return a.eMount |
| } |
| |
| func (a *volumeAdapter) Mount(id string) (string, error) { |
| mountpoint, err := a.proxy.Mount(a.name, id) |
| a.eMount = a.scopePath(mountpoint) |
| return a.eMount, err |
| } |
| |
| func (a *volumeAdapter) Unmount(id string) error { |
| err := a.proxy.Unmount(a.name, id) |
| if err == nil { |
| a.eMount = "" |
| } |
| return err |
| } |
| |
| func (a *volumeAdapter) CreatedAt() (time.Time, error) { |
| return a.createdAt, nil |
| } |
| func (a *volumeAdapter) Status() map[string]interface{} { |
| out := make(map[string]interface{}, len(a.status)) |
| for k, v := range a.status { |
| out[k] = v |
| } |
| return out |
| } |