From 65b6f423deecb93f09601aef352356a1d57c7c0f Mon Sep 17 00:00:00 2001 From: Dieter Maier Date: Sun, 30 Apr 2017 01:24:47 +0200 Subject: [PATCH 1/2] Add file_mode, dir_mode + bugfix for lost data on mounts --- main.go | 2 +- netshare/drivers/cifs.go | 84 ++++++++++++++++++++++++++++------------ netshare/netshare.go | 79 ++++++++++++++++++++----------------- 3 files changed, 104 insertions(+), 61 deletions(-) diff --git a/main.go b/main.go index fa8c1df..55ca332 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/ContainX/docker-volume-netshare/netshare" + "github.com/dmaj/docker-volume-netshare/netshare" ) var VERSION string = "" diff --git a/netshare/drivers/cifs.go b/netshare/drivers/cifs.go index 429eabd..189793a 100644 --- a/netshare/drivers/cifs.go +++ b/netshare/drivers/cifs.go @@ -3,46 +3,55 @@ package drivers import ( "bytes" "fmt" + "path/filepath" + "strings" + log "github.com/Sirupsen/logrus" "github.com/dickeyxxx/netrc" "github.com/docker/go-plugins-helpers/volume" - "os" - "path/filepath" - "strings" ) +// Constants defining driver paremeters const ( UsernameOpt = "username" PasswordOpt = "password" DomainOpt = "domain" SecurityOpt = "security" + FileModeOpt = "fileMode" + DirModeOpt = "dirMode" CifsOpts = "cifsopts" ) -type cifsDriver struct { +// CifsDriver driver structure +type CifsDriver struct { volumeDriver creds *CifsCreds netrc *netrc.Netrc cifsopts map[string]string } +// CifsCreds contains Options for cifs-mount type CifsCreds struct { user string pass string domain string security string + fileMode string + dirMode string } func (creds *CifsCreds) String() string { - return fmt.Sprintf("creds: { user=%s,pass=****,domain=%s,security=%s }", creds.user, creds.domain, creds.security) + return fmt.Sprintf("creds: { user=%s,pass=****,domain=%s,security=%s, fileMode=%s, dirMode=%s}", creds.user, creds.domain, creds.security, creds.fileMode, creds.dirMode) } -func NewCifsCredentials(user, pass, domain, security string) *CifsCreds { - return &CifsCreds{user: user, pass: pass, domain: domain, security: security} +// NewCifsCredentials setting the credentials +func NewCifsCredentials(user, pass, domain, security, fileMode, dirMode string) *CifsCreds { + return &CifsCreds{user: user, pass: pass, domain: domain, security: security, fileMode: fileMode, dirMode: dirMode} } -func NewCIFSDriver(root string, creds *CifsCreds, netrc, cifsopts string) cifsDriver { - d := cifsDriver{ +// NewCIFSDriver creating the cifs driver +func NewCIFSDriver(root string, creds *CifsCreds, netrc, cifsopts string) CifsDriver { + d := CifsDriver{ volumeDriver: newVolumeDriver(root), creds: creds, netrc: parseNetRC(netrc), @@ -63,7 +72,8 @@ func parseNetRC(path string) *netrc.Netrc { return nil } -func (c cifsDriver) Mount(r volume.MountRequest) volume.Response { +// Mount do the mounting +func (c CifsDriver) Mount(r volume.MountRequest) volume.Response { c.m.Lock() defer c.m.Unlock() hostdir := mountpoint(c.root, r.Name) @@ -114,7 +124,8 @@ func (c cifsDriver) Mount(r volume.MountRequest) volume.Response { return volume.Response{Mountpoint: hostdir} } -func (c cifsDriver) Unmount(r volume.UnmountRequest) volume.Response { +// Unmount do the unmounting +func (c CifsDriver) Unmount(r volume.UnmountRequest) volume.Response { c.m.Lock() defer c.m.Unlock() hostdir := mountpoint(c.root, r.Name) @@ -137,21 +148,26 @@ func (c cifsDriver) Unmount(r volume.UnmountRequest) volume.Response { c.mountm.DeleteIfNotManaged(r.Name) - if err := os.RemoveAll(hostdir); err != nil { - return volume.Response{Err: err.Error()} - } + // ToDo: + // This is a bad idea. + // When there is a dangling mount you will lose all your data in the mounted folder + // I didn't understand why you delete all the data ...? + + // if err := os.RemoveAll(hostdir); err != nil { + // return volume.Response{Err: err.Error()} + // } return volume.Response{} } -func (c cifsDriver) fixSource(name string) string { +func (c CifsDriver) fixSource(name string) string { if c.mountm.HasOption(name, ShareOpt) { return "//" + c.mountm.GetOption(name, ShareOpt) } return "//" + name } -func (c cifsDriver) parseHost(name string) string { +func (c CifsDriver) parseHost(name string) string { n := name if c.mountm.HasOption(name, ShareOpt) { n = c.mountm.GetOption(name, ShareOpt) @@ -164,20 +180,22 @@ func (c cifsDriver) parseHost(name string) string { return n } -func (s cifsDriver) mountVolume(name, source, dest string, creds *CifsCreds) error { +func (c CifsDriver) mountVolume(name, source, dest string, creds *CifsCreds) error { var opts bytes.Buffer var user = creds.user var pass = creds.pass var domain = creds.domain var security = creds.security + var fileMode = creds.fileMode + var dirMode = creds.dirMode - options := merge(s.mountm.GetOptions(name), s.cifsopts) + options := merge(c.mountm.GetOptions(name), c.cifsopts) if val, ok := options[CifsOpts]; ok { opts.WriteString(val + ",") } - if s.mountm.HasOptions(name) { - mopts := s.mountm.GetOptions(name) + if c.mountm.HasOptions(name) { + mopts := c.mountm.GetOptions(name) if v, found := mopts[UsernameOpt]; found { user = v } @@ -190,6 +208,12 @@ func (s cifsDriver) mountVolume(name, source, dest string, creds *CifsCreds) err if v, found := mopts[SecurityOpt]; found { security = v } + if v, found := mopts[FileModeOpt]; found { + fileMode = v + } + if v, found := mopts[DirModeOpt]; found { + dirMode = v + } } if user != "" { @@ -209,6 +233,14 @@ func (s cifsDriver) mountVolume(name, source, dest string, creds *CifsCreds) err opts.WriteString(fmt.Sprintf("sec=%s,", security)) } + if fileMode != "" { + opts.WriteString(fmt.Sprintf("file_mode=%s,", fileMode)) + } + + if dirMode != "" { + opts.WriteString(fmt.Sprintf("dir_mode=%s,", dirMode)) + } + opts.WriteString("rw ") opts.WriteString(fmt.Sprintf("%s %s", source, dest)) @@ -217,18 +249,20 @@ func (s cifsDriver) mountVolume(name, source, dest string, creds *CifsCreds) err return run(cmd) } -func (s cifsDriver) getCreds(host string) *CifsCreds { - log.Debugf("GetCreds: host=%s, netrc=%v", host, s.netrc) - if s.netrc != nil { - m := s.netrc.Machine(host) +func (c CifsDriver) getCreds(host string) *CifsCreds { + log.Debugf("GetCreds: host=%s, netrc=%v", host, c.netrc) + if c.netrc != nil { + m := c.netrc.Machine(host) if m != nil { return &CifsCreds{ user: m.Get("username"), pass: m.Get("password"), domain: m.Get("domain"), security: m.Get("security"), + fileMode: m.Get("fileMode"), + dirMode: m.Get("dirMode"), } } } - return s.creds + return c.creds } diff --git a/netshare/netshare.go b/netshare/netshare.go index 68b4c32..5297304 100644 --- a/netshare/netshare.go +++ b/netshare/netshare.go @@ -2,46 +2,51 @@ package netshare import ( "fmt" - "github.com/ContainX/docker-volume-netshare/netshare/drivers" - log "github.com/Sirupsen/logrus" - "github.com/docker/go-plugins-helpers/volume" - "github.com/spf13/cobra" "os" "path/filepath" "strconv" + + "github.com/dmaj/docker-volume-netshare/netshare/drivers" + log "github.com/Sirupsen/logrus" + "github.com/docker/go-plugins-helpers/volume" + "github.com/spf13/cobra" ) const ( - UsernameFlag = "username" - PasswordFlag = "password" - DomainFlag = "domain" - SecurityFlag = "security" - VersionFlag = "version" - OptionsFlag = "options" - BasedirFlag = "basedir" - VerboseFlag = "verbose" - AvailZoneFlag = "az" - NoResolveFlag = "noresolve" - NetRCFlag = "netrc" - TCPFlag = "tcp" - PortFlag = "port" - NameServerFlag = "nameserver" - NameFlag = "name" - SecretFlag = "secret" - ContextFlag = "context" - CephMount = "sorcemount" - CephPort = "port" - CephOpts = "options" - ServerMount = "servermount" - EnvSambaUser = "NETSHARE_CIFS_USERNAME" - EnvSambaPass = "NETSHARE_CIFS_PASSWORD" - EnvSambaWG = "NETSHARE_CIFS_DOMAIN" - EnvSambaSec = "NETSHARE_CIFS_SECURITY" - EnvNfsVers = "NETSHARE_NFS_VERSION" - EnvTCP = "NETSHARE_TCP_ENABLED" - EnvTCPAddr = "NETSHARE_TCP_ADDR" - PluginAlias = "netshare" - NetshareHelp = ` + UsernameFlag = "username" + PasswordFlag = "password" + DomainFlag = "domain" + SecurityFlag = "security" + FileModeFlag = "fileMode" + DirModeFlag = "dirMode" + VersionFlag = "version" + OptionsFlag = "options" + BasedirFlag = "basedir" + VerboseFlag = "verbose" + AvailZoneFlag = "az" + NoResolveFlag = "noresolve" + NetRCFlag = "netrc" + TCPFlag = "tcp" + PortFlag = "port" + NameServerFlag = "nameserver" + NameFlag = "name" + SecretFlag = "secret" + ContextFlag = "context" + CephMount = "sorcemount" + CephPort = "port" + CephOpts = "options" + ServerMount = "servermount" + EnvSambaUser = "NETSHARE_CIFS_USERNAME" + EnvSambaPass = "NETSHARE_CIFS_PASSWORD" + EnvSambaWG = "NETSHARE_CIFS_DOMAIN" + EnvSambaSec = "NETSHARE_CIFS_SECURITY" + EnvSambaFileMode = "NETSHARE_CIFS_FILEMODE" + EnvSambaDirMode = "NETSHARE_CIFS_DIRMODE" + EnvNfsVers = "NETSHARE_NFS_VERSION" + EnvTCP = "NETSHARE_TCP_ENABLED" + EnvTCPAddr = "NETSHARE_TCP_ADDR" + PluginAlias = "netshare" + NetshareHelp = ` docker-volume-netshare (NFS V3/4, AWS EFS and CIFS Volume Driver Plugin) Provides docker volume support for NFS v3 and 4, EFS as well as CIFS. This plugin can be run multiple times to @@ -112,6 +117,8 @@ func setupFlags() { cifsCmd.Flags().StringP(PasswordFlag, "p", "", "Password to use for mounts. Can also set environment NETSHARE_CIFS_PASSWORD") cifsCmd.Flags().StringP(DomainFlag, "d", "", "Domain to use for mounts. Can also set environment NETSHARE_CIFS_DOMAIN") cifsCmd.Flags().StringP(SecurityFlag, "s", "", "Security mode to use for mounts (mount.cifs's sec option). Can also set environment NETSHARE_CIFS_SECURITY.") + cifsCmd.Flags().StringP(FileModeFlag, "f", "", "Setting access rights for files (mount.cifs's file_mode option). Can also set environment NETSHARE_CIFS_FILEMODE.") + cifsCmd.Flags().StringP(DirModeFlag, "z", "", "Setting access rights for folders (mount.cifs's dir_mode option). Can also set environment NETSHARE_CIFS_DIRMODE.") cifsCmd.Flags().StringP(NetRCFlag, "", os.Getenv("HOME"), "The default .netrc location. Default is the user.home directory") cifsCmd.Flags().StringP(OptionsFlag, "o", "", "Options passed to Cifs mounts (ex: nounix,uid=433)") @@ -190,10 +197,12 @@ func execCIFS(cmd *cobra.Command, args []string) { pass := typeOrEnv(cmd, PasswordFlag, EnvSambaPass) domain := typeOrEnv(cmd, DomainFlag, EnvSambaWG) security := typeOrEnv(cmd, SecurityFlag, EnvSambaSec) + fileMode := typeOrEnv(cmd, FileModeFlag, EnvSambaFileMode) + dirMode := typeOrEnv(cmd, DirModeFlag, EnvSambaDirMode) netrc, _ := cmd.Flags().GetString(NetRCFlag) options, _ := cmd.Flags().GetString(OptionsFlag) - creds := drivers.NewCifsCredentials(user, pass, domain, security) + creds := drivers.NewCifsCredentials(user, pass, domain, security, fileMode, dirMode) d := drivers.NewCIFSDriver(rootForType(drivers.CIFS), creds, netrc, options) if len(user) > 0 { From e23247c71c9dc8c2c313abba786a79b972d69c95 Mon Sep 17 00:00:00 2001 From: Dieter Maier Date: Sun, 30 Apr 2017 01:32:11 +0200 Subject: [PATCH 2/2] Add infos to README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d6633ef..defb092 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,8 @@ See example: password somepass domain optional security optional + fileMode optional + dirMode optional ``` **2. Run the plugin** @@ -146,7 +148,7 @@ options and other info can be eliminated when running a container. This will create a new volume via the Docker daemon which will call `Create` in netshare passing in the corresponding user, pass and domain info. ``` - $ docker volume create -d cifs --name cifshost/share --opt username=user --opt password=pass --opt domain=domain --opt security=security + $ docker volume create -d cifs --name cifshost/share --opt username=user --opt password=pass --opt domain=domain --opt security=security --opt fileMode=0777 --opt dirMode=0777 ``` **3. Launch a container**