| package volumedrivers |
| |
| import ( |
| "errors" |
| "path/filepath" |
| "strings" |
| |
| "github.com/Sirupsen/logrus" |
| "github.com/docker/docker/volume" |
| ) |
| |
| var ( |
| errNoSuchVolume = errors.New("no such volume") |
| ) |
| |
| type volumeDriverAdapter struct { |
| name string |
| baseHostPath string |
| capabilities *volume.Capability |
| proxy *volumeDriverProxy |
| } |
| |
| 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, |
| baseHostPath: a.baseHostPath, |
| }, nil |
| } |
| |
| func (a *volumeDriverAdapter) Remove(v volume.Volume) error { |
| return a.proxy.Remove(v.Name()) |
| } |
| |
| func hostPath(baseHostPath, path string) string { |
| if baseHostPath != "" { |
| path = filepath.Join(baseHostPath, path) |
| } |
| return path |
| } |
| |
| 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, |
| baseHostPath: a.baseHostPath, |
| driverName: a.name, |
| eMount: hostPath(a.baseHostPath, 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, |
| status: v.Status, |
| baseHostPath: a.baseHostPath, |
| }, 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.Warnf("Volume driver %s returned an error while trying to query its capabilities, using default capabilties: %v", a.name, err) |
| 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.Warnf("Volume driver %q returned an invalid scope: %q", a.Name(), cap.Scope) |
| cap.Scope = volume.LocalScope |
| } |
| |
| a.capabilities = &cap |
| return cap |
| } |
| |
| type volumeAdapter struct { |
| proxy *volumeDriverProxy |
| name string |
| baseHostPath string |
| driverName string |
| eMount string // ephemeral host volume path |
| status map[string]interface{} |
| } |
| |
| type proxyVolume struct { |
| Name string |
| Mountpoint string |
| 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 = hostPath(a.baseHostPath, 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 = hostPath(a.baseHostPath, 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) Status() map[string]interface{} { |
| out := make(map[string]interface{}, len(a.status)) |
| for k, v := range a.status { |
| out[k] = v |
| } |
| return out |
| } |