summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/machine/init.go8
-rw-r--r--docs/source/markdown/podman-machine-init.1.md15
-rw-r--r--pkg/machine/config.go2
-rw-r--r--pkg/machine/qemu/config.go10
-rw-r--r--pkg/machine/qemu/machine.go96
5 files changed, 130 insertions, 1 deletions
diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go
index 14e87c201..ed04239c4 100644
--- a/cmd/podman/machine/init.go
+++ b/cmd/podman/machine/init.go
@@ -88,6 +88,14 @@ func init() {
flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Machine.Image, "Path to qcow image")
_ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)
+ VolumeFlagName := "volume"
+ flags.StringArrayVarP(&initOpts.Volumes, VolumeFlagName, "v", []string{}, "Volumes to mount, source:target")
+ _ = initCmd.RegisterFlagCompletionFunc(VolumeFlagName, completion.AutocompleteDefault)
+
+ VolumeDriverFlagName := "volume-driver"
+ flags.StringVar(&initOpts.VolumeDriver, VolumeDriverFlagName, "", "Optional volume driver")
+ _ = initCmd.RegisterFlagCompletionFunc(VolumeDriverFlagName, completion.AutocompleteDefault)
+
IgnitionPathFlagName := "ignition-path"
flags.StringVar(&initOpts.IgnitionPath, IgnitionPathFlagName, "", "Path to ignition file")
_ = initCmd.RegisterFlagCompletionFunc(IgnitionPathFlagName, completion.AutocompleteDefault)
diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md
index aead6c695..b515e8763 100644
--- a/docs/source/markdown/podman-machine-init.1.md
+++ b/docs/source/markdown/podman-machine-init.1.md
@@ -61,6 +61,20 @@ Set the timezone for the machine and containers. Valid values are `local` or
a `timezone` such as `America/Chicago`. A value of `local`, which is the default,
means to use the timezone of the machine host.
+#### **--volume**, **-v**=*source:target*
+
+Mounts a volume from source to target.
+
+Create a mount. If /host-dir:/machine-dir is specified as the `*source:target*`,
+Podman mounts _host-dir_ in the host to _machine-dir_ in the Podman machine.
+
+The root filesystem is mounted read-only in the default operating system,
+so mounts must be created under the /mnt directory.
+
+#### **--volume-driver**
+
+Driver to use for mounting volumes from the host, such as `virtfs`.
+
#### **--help**
Print usage statement.
@@ -72,6 +86,7 @@ $ podman machine init
$ podman machine init myvm
$ podman machine init --disk-size 50
$ podman machine init --memory=1024 myvm
+$ podman machine init -v /Users:/mnt/Users
```
## SEE ALSO
diff --git a/pkg/machine/config.go b/pkg/machine/config.go
index 4f2947ac0..33a352898 100644
--- a/pkg/machine/config.go
+++ b/pkg/machine/config.go
@@ -18,6 +18,8 @@ type InitOptions struct {
DiskSize uint64
IgnitionPath string
ImagePath string
+ Volumes []string
+ VolumeDriver string
IsDefault bool
Memory uint64
Name string
diff --git a/pkg/machine/qemu/config.go b/pkg/machine/qemu/config.go
index 8404079a2..e76509bb1 100644
--- a/pkg/machine/qemu/config.go
+++ b/pkg/machine/qemu/config.go
@@ -11,6 +11,8 @@ type MachineVM struct {
CPUs uint64
// The command line representation of the qemu command
CmdLine []string
+ // Mounts is the list of remote filesystems to mount
+ Mounts []Mount
// IdentityPath is the fq path to the ssh priv key
IdentityPath string
// IgnitionFilePath is the fq path to the .ign file
@@ -33,6 +35,14 @@ type MachineVM struct {
RemoteUsername string
}
+type Mount struct {
+ Type string
+ Tag string
+ Source string
+ Target string
+ ReadOnly bool
+}
+
type Monitor struct {
// Address portion of the qmp monitor (/tmp/tmp.sock)
Address string
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index a80a11573..f09107c71 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -36,6 +36,11 @@ func GetQemuProvider() machine.Provider {
return qemuProvider
}
+const (
+ VolumeTypeVirtfs = "virtfs"
+ MountType9p = "9p"
+)
+
// NewMachine initializes an instance of a virtual machine based on the qemu
// virtualization.
func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
@@ -167,6 +172,53 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
// Add arch specific options including image location
v.CmdLine = append(v.CmdLine, v.addArchOptions()...)
+ var volumeType string
+ switch opts.VolumeDriver {
+ case "virtfs":
+ volumeType = VolumeTypeVirtfs
+ case "": // default driver
+ volumeType = VolumeTypeVirtfs
+ default:
+ err := fmt.Errorf("unknown volume driver: %s", opts.VolumeDriver)
+ return false, err
+ }
+
+ mounts := []Mount{}
+ for i, volume := range opts.Volumes {
+ tag := fmt.Sprintf("vol%d", i)
+ paths := strings.SplitN(volume, ":", 3)
+ source := paths[0]
+ target := source
+ readonly := false
+ if len(paths) > 1 {
+ target = paths[1]
+ }
+ if len(paths) > 2 {
+ options := paths[2]
+ volopts := strings.Split(options, ",")
+ for _, o := range volopts {
+ switch o {
+ case "rw":
+ readonly = false
+ case "ro":
+ readonly = true
+ default:
+ fmt.Printf("Unknown option: %s\n", o)
+ }
+ }
+ }
+ switch volumeType {
+ case VolumeTypeVirtfs:
+ virtfsOptions := fmt.Sprintf("local,path=%s,mount_tag=%s,security_model=mapped-xattr", source, tag)
+ if readonly {
+ virtfsOptions += ",readonly"
+ }
+ v.CmdLine = append(v.CmdLine, []string{"-virtfs", virtfsOptions}...)
+ mounts = append(mounts, Mount{Type: MountType9p, Tag: tag, Source: source, Target: target, ReadOnly: readonly})
+ }
+ }
+ v.Mounts = mounts
+
// Add location of bootable image
v.CmdLine = append(v.CmdLine, "-drive", "if=virtio,file="+v.ImagePath)
// This kind of stinks but no other way around this r/n
@@ -329,7 +381,39 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
return err
}
_, err = bufio.NewReader(conn).ReadString('\n')
- return err
+ if err != nil {
+ return err
+ }
+
+ if len(v.Mounts) > 0 {
+ for !v.isRunning() || !v.isListening() {
+ time.Sleep(100 * time.Millisecond)
+ }
+ }
+ for _, mount := range v.Mounts {
+ fmt.Printf("Mounting volume... %s:%s\n", mount.Source, mount.Target)
+ // create mountpoint directory if it doesn't exist
+ err = v.SSH(name, machine.SSHOptions{Args: []string{"-q", "--", "sudo", "mkdir", "-p", mount.Target}})
+ if err != nil {
+ return err
+ }
+ switch mount.Type {
+ case MountType9p:
+ mountOptions := []string{"-t", "9p"}
+ mountOptions = append(mountOptions, []string{"-o", "trans=virtio", mount.Tag, mount.Target}...)
+ mountOptions = append(mountOptions, []string{"-o", "version=9p2000.L,msize=131072"}...)
+ if mount.ReadOnly {
+ mountOptions = append(mountOptions, []string{"-o", "ro"}...)
+ }
+ err = v.SSH(name, machine.SSHOptions{Args: append([]string{"-q", "--", "sudo", "mount"}, mountOptions...)})
+ if err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("unknown mount type: %s", mount.Type)
+ }
+ }
+ return nil
}
// Stop uses the qmp monitor to call a system_powerdown
@@ -506,6 +590,16 @@ func (v *MachineVM) isRunning() bool {
return true
}
+func (v *MachineVM) isListening() bool {
+ // Check if we can dial it
+ conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "localhost", v.Port), 10*time.Millisecond)
+ if err != nil {
+ return false
+ }
+ conn.Close()
+ return true
+}
+
// SSH opens an interactive SSH session to the vm specified.
// Added ssh function to VM interface: pkg/machine/config/go : line 58
func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error {