From e6a8273004b8b5077a1f67e2fa6e40003f28fb8a Mon Sep 17 00:00:00 2001 From: Hugues Alary Date: Tue, 26 Apr 2016 16:42:55 -0700 Subject: [PATCH] Added the ability to setup multiple NFS Shares By default (changeable with `xhyve-experimental-nfs-share-root`, see below) NFS shares are rooted at /xhyve-nfsshares to avoid the situation where a NFS Share `/usr` would be mounted at `/usr` 2 backward incompatible changes: - renamed `xhyve-experimental-nfs-share` to `xhyve-experimental-nfs-share-enable` - change `xhyve-experimental-nfs-share` from being a boolean to a string slice taking multiple path to be shared via NFS - NFS Shares are now mounted under a default directory /xhyve-nfsshares (the old code was mounting everything under `/` causing, for example, `/usr` to be mounted at `/usr`) Other change: - add `xhyve-experimental-nfs-share-root` to allow specifying where in the guest the NFS Shares will be rooted at Here's an example of how to use: `docker-machine -D create -d xhyve --xhyve-disk-size 40000 --xhyve-memory-size 4000 --xhyve-cpu-count 2 --xhyve-experimental-nfs-share-enable --xhyve-experimental-nfs-share /Users --xhyve-experimental-nfs-share /usr/ --xhyve-experimental-nfs-share-root /nfsharesfromhost test` This command will share the host folders /Users and /usr in the guest at /nfsharesfromhost/Users and /nfsharesfromhost/usr --- README.md | 4 +++- xhyve/xhyve.go | 65 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 4c04e94..b2b5883 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,9 @@ Usage | `--xhyve-boot-initrd` | `XHYVE_BOOT_INITRD` | string | `''` | | `--xhyve-qcow2` | `XHYVE_QCOW2` | bool | `false` | | `--xhyve-virtio-9p` | `XHYVE_VIRTIO_9P` | bool | `false` | -| `--xhyve-experimental-nfs-share` | `XHYVE_EXPERIMENTAL_NFS_SHARE` | bool | `false` | +| `--xhyve-experimental-nfs-share-enable` | `XHYVE_EXPERIMENTAL_NFS_SHARE_ENABLE` | bool | Enable `NFS` folder share (experimental) | `false` | +| `--xhyve-experimental-nfs-share` | `XHYVE_EXPERIMENTAL_NFS_SHARE` | string | Path to a host folder to be shared inside the guest | | +| `--xhyve-experimental-nfs-share-root` | `XHYVE_EXPERIMENTAL_NFS_SHARE_ROOT` | string | root path at which the NFS shares will be mounted| `/xhyve-nfsshares` | #### `--xhyve-boot2docker-url` diff --git a/xhyve/xhyve.go b/xhyve/xhyve.go index ca59ddc..b16cd68 100644 --- a/xhyve/xhyve.go +++ b/xhyve/xhyve.go @@ -16,6 +16,7 @@ import ( "os" "os/exec" "os/user" + "path" "path/filepath" "regexp" "runtime" @@ -53,6 +54,7 @@ const ( defaultPrivateKeyPath = "" defaultUUID = "" defaultNFSShareEnable = false + defaultNFSSharesRoot = "/xhyve-nfsshares" rootVolumeName = "root-volume" defaultDiskNumber = -1 defaultVirtio9p = false @@ -77,6 +79,8 @@ type Driver struct { Qcow2 bool RawDisk bool NFSShareEnable bool + NFSShares []string + NFSSharesRoot string DiskNumber int Virtio9p bool Virtio9pFolder string @@ -116,6 +120,7 @@ func NewDriver(hostName, storePath string) *Driver { PrivateKeyPath: defaultPrivateKeyPath, UUID: defaultUUID, NFSShareEnable: defaultNFSShareEnable, + NFSSharesRoot: defaultNFSSharesRoot, DiskNumber: defaultDiskNumber, Virtio9p: defaultVirtio9p, Qcow2: defaultQcow2, @@ -200,6 +205,16 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag { Name: "xhyve-experimental-nfs-share-enable", Usage: "Setup NFS shared folder (requires root)", }, + mcnflag.StringSliceFlag{ + EnvVar: "XHYVE_EXPERIMENTAL_NFS_SHARE", + Name: "xhyve-experimental-nfs-share", + Usage: "Setup NFS shared folder (requires root)", + }, + mcnflag.StringFlag{ + EnvVar: "XHYVE_EXPERIMENTAL_NFS_SHARE_ROOT", + Name: "xhyve-experimental-nfs-share-root", + Usage: "root directory where the NFS shares will be mounted inside the machine", + }, } } @@ -258,6 +273,8 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.Virtio9p = flags.Bool("xhyve-virtio-9p") d.Virtio9pFolder = "/Users" d.NFSShareEnable = flags.Bool("xhyve-experimental-nfs-share-enable") + d.NFSShares = flags.StringSlice("xhyve-experimental-nfs-share") + d.NFSSharesRoot = flags.String("xhyve-experimental-nfs-share-root") return nil } @@ -577,8 +594,10 @@ func (d *Driver) Remove() error { if d.NFSShareEnable { log.Infof("Remove NFS share folder must be root. Please insert root password.") - if _, err := nfsexports.Remove("", d.nfsExportIdentifier()); err != nil { - log.Errorf("failed removing nfs share: %s", err.Error()) + for _, share := range d.NFSShares { + if _, err := nfsexports.Remove("", d.nfsExportIdentifier(share)); err != nil { + log.Errorf("failed removing nfs share (%s): %s", share, err.Error()) + } } if err := nfsexports.ReloadDaemon(); err != nil { @@ -1000,27 +1019,39 @@ func (d *Driver) setupNFSShare() error { return err } - nfsConfig := fmt.Sprintf("/Users %s -alldirs -mapall=%s", d.IPAddress, user.Username) - - if _, err := nfsexports.Add("", d.nfsExportIdentifier(), nfsConfig); err != nil { + hostIP, err := vmnet.GetNetAddr() + if err != nil { return err } - if err := nfsexports.ReloadDaemon(); err != nil { - return err + bootScriptName := "/var/lib/boot2docker/bootlocal.sh" + bootScript := fmt.Sprintf("#/bin/bash\\n") + + bootScript += "sudo /usr/local/etc/init.d/nfs-client start\\n" + + for _, share := range d.NFSShares { + if !path.IsAbs(share) { + share = d.ResolveStorePath(share) + } + nfsConfig := fmt.Sprintf("%s %s -alldirs -mapall=%s", share, d.IPAddress, user.Username) + + if _, err := nfsexports.Add("", d.nfsExportIdentifier(share), nfsConfig); err != nil { + if strings.Contains(err.Error(), "conflicts with existing export") { + log.Info("Conflicting NFS Share not setup and ignored:", err) + continue + } + return err + } + + root := path.Clean(d.NFSSharesRoot) + bootScript += fmt.Sprintf("sudo mkdir -p %s/%s\\n", root, share) + bootScript += fmt.Sprintf("sudo mount -t nfs -o noacl,async %s:%s %s/%s\\n", hostIP, share, root, share) } - hostIP, err := vmnet.GetNetAddr() - if err != nil { + if err := nfsexports.ReloadDaemon(); err != nil { return err } - bootScriptName := "/var/lib/boot2docker/bootlocal.sh" - bootScript := fmt.Sprintf("#/bin/bash\\n"+ - "sudo mkdir -p /Users\\n"+ - "sudo /usr/local/etc/init.d/nfs-client start\\n"+ - "sudo mount -t nfs -o noacl,async %s:/Users /Users\\n", hostIP) - writeScriptCmd := fmt.Sprintf("echo -e \"%s\" | sudo tee %s && sudo chmod +x %s && %s", bootScript, bootScriptName, bootScriptName, bootScriptName) @@ -1031,8 +1062,8 @@ func (d *Driver) setupNFSShare() error { return nil } -func (d *Driver) nfsExportIdentifier() string { - return fmt.Sprintf("docker-machine-driver-xhyve %s", d.MachineName) +func (d *Driver) nfsExportIdentifier(path string) string { + return fmt.Sprintf("docker-machine-driver-xhyve %s-%s", d.MachineName, path) } func (d *Driver) GetPid() (int, error) {