Skip to content

Commit

Permalink
Merge pull request #11454 from afbjorklund/virtfs-volumes
Browse files Browse the repository at this point in the history
Implement virtfs volumes for podman machine
  • Loading branch information
openshift-merge-robot authored Jan 6, 2022
2 parents 2fd6c2e + 6630e5c commit d627528
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 1 deletion.
8 changes: 8 additions & 0 deletions cmd/podman/machine/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 15 additions & 0 deletions docs/source/markdown/podman-machine-init.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions pkg/machine/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type InitOptions struct {
DiskSize uint64
IgnitionPath string
ImagePath string
Volumes []string
VolumeDriver string
IsDefault bool
Memory uint64
Name string
Expand Down
10 changes: 10 additions & 0 deletions pkg/machine/qemu/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
96 changes: 95 additions & 1 deletion pkg/machine/qemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit d627528

Please sign in to comment.