Skip to content

Commit

Permalink
Added the ability to setup multiple NFS Shares
Browse files Browse the repository at this point in the history
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
  • Loading branch information
huguesalary committed Jul 24, 2017
1 parent 4449140 commit 3d840ec
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 24 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
72 changes: 49 additions & 23 deletions xhyve/xhyve.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"os"
"os/exec"
"os/user"
"path"
"path/filepath"
"regexp"
"runtime"
Expand Down Expand Up @@ -53,6 +54,7 @@ const (
defaultPrivateKeyPath = ""
defaultUUID = ""
defaultNFSShareEnable = false
defaultNFSSharesRoot = "/xhyve-nfsshares"
rootVolumeName = "root-volume"
defaultDiskNumber = -1
defaultVirtio9p = false
Expand All @@ -77,6 +79,8 @@ type Driver struct {
Qcow2 bool
RawDisk bool
NFSShareEnable bool
NFSShares []string
NFSSharesRoot string
Virtio9p bool
Virtio9pFolder string
NFSShare bool
Expand Down Expand Up @@ -115,6 +119,7 @@ func NewDriver(hostName, storePath string) *Driver {
PrivateKeyPath: defaultPrivateKeyPath,
UUID: defaultUUID,
NFSShareEnable: defaultNFSShareEnable,
NFSSharesRoot: defaultNFSSharesRoot,
DiskNumber: defaultDiskNumber,
Virtio9p: defaultVirtio9p,
Qcow2: defaultQcow2,
Expand Down Expand Up @@ -162,11 +167,6 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
Usage: "Size of disk for host in MB",
Value: defaultDiskSize,
},
mcnflag.BoolFlag{
EnvVar: "XHYVE_EXPERIMENTAL_NFS_SHARE",
Name: "xhyve-experimental-nfs-share",
Usage: "Setup NFS shared folder (requires root)",
},
mcnflag.IntFlag{
EnvVar: "XHYVE_MEMORY_SIZE",
Name: "xhyve-memory-size",
Expand Down Expand Up @@ -199,6 +199,17 @@ 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",
Value: defaultNFSSharesRoot,
},
}
}

Expand Down Expand Up @@ -245,7 +256,6 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
}
d.DiskSize = int64(flags.Int("xhyve-disk-size"))
d.Memory = flags.Int("xhyve-memory-size")
d.NFSShare = flags.Bool("xhyve-experimental-nfs-share")
d.Qcow2 = flags.Bool("xhyve-qcow2")
d.RawDisk = flags.Bool("xhyve-rawdisk")
d.SSHPort = 22
Expand All @@ -257,6 +267,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
}
Expand Down Expand Up @@ -576,8 +588,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 {
Expand Down Expand Up @@ -999,27 +1013,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)

Expand All @@ -1030,8 +1056,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) {
Expand Down

0 comments on commit 3d840ec

Please sign in to comment.