mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Merge pull request #11454 from afbjorklund/virtfs-volumes
Implement virtfs volumes for podman machine
This commit is contained in:
@ -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)
|
||||
|
@ -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
|
||||
|
@ -18,6 +18,8 @@ type InitOptions struct {
|
||||
DiskSize uint64
|
||||
IgnitionPath string
|
||||
ImagePath string
|
||||
Volumes []string
|
||||
VolumeDriver string
|
||||
IsDefault bool
|
||||
Memory uint64
|
||||
Name string
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
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 {
|
||||
|
Reference in New Issue
Block a user