Skip to content

Commit a72b5d1

Browse files
committed
Issue #81 - NFS: Support for clusters without the need for docker volume create
1 parent 5533e15 commit a72b5d1

File tree

5 files changed

+101
-44
lines changed

5 files changed

+101
-44
lines changed

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
VERSION = 0.30
1+
VERSION = 0.31
22
GO_FMT = gofmt -s -w -l .
3-
GO_XC = goxc -os="linux" -bc="linux,amd64" -tasks-="rmbin"
3+
GO_XC = goxc -os="linux" -bc="linux,amd64,arm" -tasks-="rmbin"
44

55
GOXC_FILE = .goxc.local.json
66

@@ -20,6 +20,7 @@ goxc:
2020
$(shell echo ' }\n } \n}' >> $(GOXC_FILE))
2121
$(GO_XC)
2222
cp build/$(VERSION)/linux_amd64/docker-volume-netshare build/$(VERSION)/docker-volume-netshare_$(VERSION)_linux_amd64-bin
23+
cp build/$(VERSION)/linux_arm/docker-volume-netshare build/$(VERSION)/docker-volume-netshare_$(VERSION)_linux_arm-bin
2324

2425
deps:
2526
go get

netshare/drivers/driver.go

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,46 +26,56 @@ func (v volumeDriver) Create(r volume.Request) volume.Response {
2626
v.m.Lock()
2727
defer v.m.Unlock()
2828

29-
log.Debugf("Create volume -> name: %s, %v", r.Name, r.Options)
29+
resName, resOpts := resolveName(r.Name)
30+
if resOpts != nil {
31+
// Check to make sure there aren't options, otherwise override
32+
if len(r.Options) == 0 {
33+
r.Options = resOpts
34+
}
35+
}
36+
log.Debugf("Create volume -> name: %s, %v", resName, r.Options)
3037

31-
dest := mountpoint(v.root, r.Name)
38+
dest := mountpoint(v.root, resName)
3239
if err := createDest(dest); err != nil {
3340
return volume.Response{Err: err.Error()}
3441
}
3542

36-
v.mountm.Create(r.Name, dest, r.Options)
37-
//if v.mountm.GetOption(r.Name, ShareOpt) != "" && v.mountm.GetOptionAsBool(r.Name, CreateOpt) {
38-
// log.Debugf("Create volume -> name: %s, creating option found, creating: %s", r.Name, r.Options)
39-
//
40-
//}
43+
v.mountm.Create(resName, dest, r.Options)
4144
return volume.Response{}
4245
}
4346

4447
func (v volumeDriver) Remove(r volume.Request) volume.Response {
45-
log.Debugf("Entering Remove: name: %s, options %v", r.Name, r.Options)
48+
49+
resolvedName, _ := resolveName(r.Name)
50+
51+
log.Debugf("Entering Remove: name: %s, resolved-name: %s, options %v", r.Name, resolvedName, r.Options)
4652
v.m.Lock()
4753
defer v.m.Unlock()
4854

49-
if err := v.mountm.Delete(r.Name); err != nil {
55+
if err := v.mountm.Delete(resolvedName); err != nil {
5056
return volume.Response{Err: err.Error()}
5157
}
5258
return volume.Response{}
5359
}
5460

5561
func (v volumeDriver) Path(r volume.Request) volume.Response {
56-
log.Debugf("Host path for %s is at %s", r.Name, mountpoint(v.root, r.Name))
57-
return volume.Response{Mountpoint: mountpoint(v.root, r.Name)}
62+
resolvedName, _ := resolveName(r.Name)
63+
64+
log.Debugf("Host path for %s (%s) is at %s", r.Name, resolvedName, mountpoint(v.root, resolvedName))
65+
return volume.Response{Mountpoint: mountpoint(v.root, resolvedName)}
5866
}
5967

6068
func (v volumeDriver) Get(r volume.Request) volume.Response {
6169
log.Debugf("Entering Get: %v", r)
6270
v.m.Lock()
6371
defer v.m.Unlock()
64-
hostdir := mountpoint(v.root, r.Name)
72+
resolvedName, _ := resolveName(r.Name)
73+
74+
hostdir := mountpoint(v.root, resolvedName)
6575

66-
if v.mountm.HasMount(r.Name) {
67-
log.Debugf("Get: mount found for %s, host directory: %s", r.Name, hostdir)
68-
return volume.Response{Volume: &volume.Volume{Name: r.Name, Mountpoint: hostdir}}
76+
if v.mountm.HasMount(resolvedName) {
77+
log.Debugf("Get: mount found for %s, host directory: %s", resolvedName, hostdir)
78+
return volume.Response{Volume: &volume.Volume{Name: resolvedName, Mountpoint: hostdir}}
6979
}
7080
return volume.Response{}
7181
}
@@ -78,8 +88,8 @@ func (v volumeDriver) List(r volume.Request) volume.Response {
7888
func (v volumeDriver) Capabilities(r volume.Request) volume.Response {
7989
log.Debugf("Entering Capabilities: %v", r)
8090
return volume.Response{
81-
Capabilities: volume.Capability {
82-
Scope: "global",
91+
Capabilities: volume.Capability{
92+
Scope: "local",
8393
},
8494
}
8595
}

netshare/drivers/mounts.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
)
99

1010
const (
11-
ShareOpt = "share"
11+
ShareOpt = "share"
1212
CreateOpt = "create"
1313
)
1414

@@ -111,6 +111,7 @@ func (m *mountManager) Create(name, hostdir string, opts map[string]string) *mou
111111
}
112112

113113
func (m *mountManager) Delete(name string) error {
114+
log.Debugf("Delete volume: %s, connections: %d", name, m.Count(name))
114115
if m.HasMount(name) {
115116
if m.Count(name) < 1 {
116117
delete(m.mounts, name)

netshare/drivers/nfs.go

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
log "github.com/Sirupsen/logrus"
66
"github.com/docker/go-plugins-helpers/volume"
77
"os"
8-
"strings"
98
"path/filepath"
109
)
1110

@@ -42,13 +41,22 @@ func (n nfsDriver) Mount(r volume.MountRequest) volume.Response {
4241
n.m.Lock()
4342
defer n.m.Unlock()
4443

44+
resolvedName, resOpts := resolveName(r.Name)
4545

46-
hostdir := mountpoint(n.root, r.Name)
47-
source := n.fixSource(r.Name, r.ID)
46+
hostdir := mountpoint(n.root, resolvedName)
47+
source := n.fixSource(resolvedName)
4848

49-
if n.mountm.HasMount(r.Name) && n.mountm.Count(r.Name) > 0 {
49+
// Support adhoc mounts (outside of docker volume create)
50+
// need to adjust source for ShareOpt
51+
if resOpts != nil {
52+
if share, found := resOpts[ShareOpt]; found {
53+
source = n.fixSource(share)
54+
}
55+
}
56+
57+
if n.mountm.HasMount(resolvedName) && n.mountm.Count(resolvedName) > 0 {
5058
log.Infof("Using existing NFS volume mount: %s", hostdir)
51-
n.mountm.Increment(r.Name)
59+
n.mountm.Increment(resolvedName)
5260
if err := run(fmt.Sprintf("mountpoint -q %s", hostdir)); err != nil {
5361
log.Infof("Existing NFS volume not mounted, force remount.")
5462
} else {
@@ -62,15 +70,19 @@ func (n nfsDriver) Mount(r volume.MountRequest) volume.Response {
6270
return volume.Response{Err: err.Error()}
6371
}
6472

65-
if err := n.mountVolume(r.Name, source, hostdir, n.version); err != nil {
73+
if n.mountm.HasMount(resolvedName) == false {
74+
n.mountm.Create(resolvedName, hostdir, resOpts)
75+
}
76+
77+
if err := n.mountVolume(resolvedName, source, hostdir, n.version); err != nil {
6678
return volume.Response{Err: err.Error()}
6779
}
68-
n.mountm.Add(r.Name, hostdir)
80+
n.mountm.Add(resolvedName, hostdir)
6981

70-
if n.mountm.GetOption(r.Name, ShareOpt) != "" && n.mountm.GetOptionAsBool(r.Name, CreateOpt) {
71-
log.Infof("Mount: Share and Create options enabled - using %s as sub-dir mount", r.Name)
72-
datavol := filepath.Join(hostdir, r.Name)
73-
if err := createDest(filepath.Join(hostdir, r.Name)); err != nil {
82+
if n.mountm.GetOption(resolvedName, ShareOpt) != "" && n.mountm.GetOptionAsBool(resolvedName, CreateOpt) {
83+
log.Infof("Mount: Share and Create options enabled - using %s as sub-dir mount", resolvedName)
84+
datavol := filepath.Join(hostdir, resolvedName)
85+
if err := createDest(filepath.Join(hostdir, resolvedName)); err != nil {
7486
return volume.Response{Err: err.Error()}
7587
}
7688
hostdir = datavol
@@ -84,24 +96,28 @@ func (n nfsDriver) Unmount(r volume.UnmountRequest) volume.Response {
8496

8597
n.m.Lock()
8698
defer n.m.Unlock()
87-
hostdir := mountpoint(n.root, r.Name)
8899

89-
if n.mountm.HasMount(r.Name) {
90-
if n.mountm.Count(r.Name) > 1 {
91-
log.Printf("Skipping unmount for %s - in use by other containers", r.Name)
92-
n.mountm.Decrement(r.Name)
100+
resolvedName, _ := resolveName(r.Name)
101+
102+
hostdir := mountpoint(n.root, resolvedName)
103+
104+
if n.mountm.HasMount(resolvedName) {
105+
if n.mountm.Count(resolvedName) > 1 {
106+
log.Printf("Skipping unmount for %s - in use by other containers", resolvedName)
107+
n.mountm.Decrement(resolvedName)
93108
return volume.Response{}
94109
}
95-
n.mountm.Decrement(r.Name)
110+
n.mountm.Decrement(resolvedName)
96111
}
97112

98-
log.Infof("Unmounting volume name %s from %s", r.Name, hostdir)
113+
log.Infof("Unmounting volume name %s from %s", resolvedName, hostdir)
99114

100115
if err := run(fmt.Sprintf("umount %s", hostdir)); err != nil {
116+
log.Errorf("Error unmounting volume from host: %s", err.Error())
101117
return volume.Response{Err: err.Error()}
102118
}
103119

104-
n.mountm.DeleteIfNotManaged(r.Name)
120+
n.mountm.DeleteIfNotManaged(resolvedName)
105121

106122
if err := os.RemoveAll(hostdir); err != nil {
107123
return volume.Response{Err: err.Error()}
@@ -110,13 +126,11 @@ func (n nfsDriver) Unmount(r volume.UnmountRequest) volume.Response {
110126
return volume.Response{}
111127
}
112128

113-
func (n nfsDriver) fixSource(name, id string) string {
129+
func (n nfsDriver) fixSource(name string) string {
114130
if n.mountm.HasOption(name, ShareOpt) {
115-
return n.mountm.GetOption(name, ShareOpt)
131+
return addShareColon(n.mountm.GetOption(name, ShareOpt))
116132
}
117-
source := strings.Split(name, "/")
118-
source[0] = source[0] + ":"
119-
return strings.Join(source, "/")
133+
return addShareColon(name)
120134
}
121135

122136
func (n nfsDriver) mountVolume(name, source, dest string, version int) error {

netshare/drivers/util.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import (
66
"os"
77
"os/exec"
88
"path/filepath"
9+
"strings"
10+
)
11+
12+
const (
13+
ShareSplitIndentifer = "#"
914
)
1015

1116
func createDest(dest string) error {
@@ -25,6 +30,32 @@ func createDest(dest string) error {
2530
return nil
2631
}
2732

33+
// Used to support on the fly volume creation using docker run. If = is in the name we split
34+
// and elem[1] is the volume name
35+
func resolveName(name string) (string, map[string]string) {
36+
if strings.Contains(name, ShareSplitIndentifer) {
37+
sharevol := strings.Split(name, ShareSplitIndentifer)
38+
opts := map[string]string{}
39+
opts[ShareOpt] = sharevol[0]
40+
opts[CreateOpt] = "true"
41+
return sharevol[1], opts
42+
}
43+
return name, nil
44+
}
45+
46+
func shareDefinedWithVolume(name string) bool {
47+
return strings.Contains(name, ShareSplitIndentifer)
48+
}
49+
50+
func addShareColon(share string) string {
51+
if strings.Contains(share, ":") {
52+
return share
53+
}
54+
source := strings.Split(share, "/")
55+
source[0] = source[0] + ":"
56+
return strings.Join(source, "/")
57+
}
58+
2859
func mountpoint(elem ...string) string {
2960
return filepath.Join(elem...)
3061
}

0 commit comments

Comments
 (0)