diff --git a/cmd/podman/volume_create.go b/cmd/podman/volume_create.go index 84f6bba941..7342d9110a 100644 --- a/cmd/podman/volume_create.go +++ b/cmd/podman/volume_create.go @@ -25,8 +25,8 @@ var ( return volumeCreateCmd(&volumeCreateCommand) }, Example: `podman volume create myvol - podman volume create - podman volume create --label foo=bar myvol`, + podman volume create --label foo=bar + podman volume create --opt type=nfs --opt o=addr=192.168.0.2,rw --opt device=:/nfsshare mynfsvol`, } ) diff --git a/docs/podman-volume-create.1.md b/docs/podman-volume-create.1.md index 795d7b4494..5cf0472076 100644 --- a/docs/podman-volume-create.1.md +++ b/docs/podman-volume-create.1.md @@ -29,7 +29,13 @@ Set metadata for a volume (e.g., --label mykey=value). **-o**, **--opt**=[] -Set driver specific options. +Set driver specific options. To setup NFS volume you need to specify: + + type: `-o type=nfs` To indicate the nfs mount. + + o: `-o o=addr=nfsserver.example.com,rw` Options including the address of the nfs server. + + device: `-o device=/nfsshare`, the remote nfs share. ## EXAMPLES @@ -39,6 +45,8 @@ $ podman volume create myvol $ podman volume create $ podman volume create --label foo=bar myvol + +# podman volume create --opt type=nfs --opt o=addr=192.168.0.2,rw --opt device=/nfsshare mynfsvol ``` ## SEE ALSO diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index c7758055fe..d90a3493a0 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -191,6 +191,13 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options .. return nil, errors.Wrapf(err, "error creating named volume %q", vol.Name) } + options := newVol.Options() + if len(options) > 0 { + if err := newVol.Mount(); err != nil { + return nil, err + } + } + if err := ctr.copyWithTarFromImage(vol.Dest, newVol.MountPoint()); err != nil && !os.IsNotExist(err) { return nil, errors.Wrapf(err, "Failed to copy content into new volume mount %q", vol.Name) } diff --git a/libpod/volume.go b/libpod/volume.go index 0b37d44efe..b179db75dd 100644 --- a/libpod/volume.go +++ b/libpod/volume.go @@ -1,5 +1,13 @@ package libpod +import ( + "net" + "strings" + + "github.com/containers/storage/pkg/mount" + "github.com/pkg/errors" +) + // Volume is the type used to create named volumes // TODO: all volumes should be created using this and the Volume API type Volume struct { @@ -70,3 +78,57 @@ func (v *Volume) Scope() string { func (v *Volume) IsCtrSpecific() bool { return v.config.IsCtrSpecific } + +// Mount the volume +func (v *Volume) Mount() error { + if v.MountPoint() == "" { + return errors.Errorf("missing device in volume options") + } + mounted, err := mount.Mounted(v.MountPoint()) + if err != nil { + return errors.Wrapf(err, "failed to determine if %v is mounted", v.Name()) + } + if mounted { + return nil + } + options := v.Options() + if len(options) == 0 { + return errors.Errorf("volume %v is not mountable, no options available", v.Name()) + } + mountOpts := options["o"] + device := options["device"] + if options["type"] == "nfs" { + if addrValue := getAddress(mountOpts); addrValue != "" && net.ParseIP(addrValue).To4() == nil { + ipAddr, err := net.ResolveIPAddr("ip", addrValue) + if err != nil { + return errors.Wrapf(err, "error resolving passed in nfs address") + } + mountOpts = strings.Replace(mountOpts, "addr="+addrValue, "addr="+ipAddr.String(), 1) + } + if device[0] != ':' { + device = ":" + device + } + } + err = mount.Mount(device, v.MountPoint(), options["type"], mountOpts) + return errors.Wrap(err, "failed to mount local volume") +} + +// Unmount the volume from the system +func (v *Volume) Unmount() error { + if v.MountPoint() == "" { + return errors.Errorf("missing device in volume options") + } + return mount.Unmount(v.MountPoint()) +} + +// getAddress finds out address/hostname from options +func getAddress(opts string) string { + optsList := strings.Split(opts, ",") + for i := 0; i < len(optsList); i++ { + if strings.HasPrefix(optsList[i], "addr=") { + addr := strings.SplitN(optsList[i], "=", 2)[1] + return addr + } + } + return "" +} diff --git a/libpod/volume_internal.go b/libpod/volume_internal.go index 35f0ca19d6..96f8e471b0 100644 --- a/libpod/volume_internal.go +++ b/libpod/volume_internal.go @@ -18,5 +18,6 @@ func newVolume(runtime *Runtime) (*Volume, error) { // teardownStorage deletes the volume from volumePath func (v *Volume) teardownStorage() error { + v.Unmount() return os.RemoveAll(filepath.Join(v.runtime.config.VolumePath, v.Name())) }