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")
|
flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Machine.Image, "Path to qcow image")
|
||||||
_ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)
|
_ = 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"
|
IgnitionPathFlagName := "ignition-path"
|
||||||
flags.StringVar(&initOpts.IgnitionPath, IgnitionPathFlagName, "", "Path to ignition file")
|
flags.StringVar(&initOpts.IgnitionPath, IgnitionPathFlagName, "", "Path to ignition file")
|
||||||
_ = initCmd.RegisterFlagCompletionFunc(IgnitionPathFlagName, completion.AutocompleteDefault)
|
_ = 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,
|
a `timezone` such as `America/Chicago`. A value of `local`, which is the default,
|
||||||
means to use the timezone of the machine host.
|
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**
|
#### **--help**
|
||||||
|
|
||||||
Print usage statement.
|
Print usage statement.
|
||||||
@ -72,6 +86,7 @@ $ podman machine init
|
|||||||
$ podman machine init myvm
|
$ podman machine init myvm
|
||||||
$ podman machine init --disk-size 50
|
$ podman machine init --disk-size 50
|
||||||
$ podman machine init --memory=1024 myvm
|
$ podman machine init --memory=1024 myvm
|
||||||
|
$ podman machine init -v /Users:/mnt/Users
|
||||||
```
|
```
|
||||||
|
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
|
@ -18,6 +18,8 @@ type InitOptions struct {
|
|||||||
DiskSize uint64
|
DiskSize uint64
|
||||||
IgnitionPath string
|
IgnitionPath string
|
||||||
ImagePath string
|
ImagePath string
|
||||||
|
Volumes []string
|
||||||
|
VolumeDriver string
|
||||||
IsDefault bool
|
IsDefault bool
|
||||||
Memory uint64
|
Memory uint64
|
||||||
Name string
|
Name string
|
||||||
|
@ -11,6 +11,8 @@ type MachineVM struct {
|
|||||||
CPUs uint64
|
CPUs uint64
|
||||||
// The command line representation of the qemu command
|
// The command line representation of the qemu command
|
||||||
CmdLine []string
|
CmdLine []string
|
||||||
|
// Mounts is the list of remote filesystems to mount
|
||||||
|
Mounts []Mount
|
||||||
// IdentityPath is the fq path to the ssh priv key
|
// IdentityPath is the fq path to the ssh priv key
|
||||||
IdentityPath string
|
IdentityPath string
|
||||||
// IgnitionFilePath is the fq path to the .ign file
|
// IgnitionFilePath is the fq path to the .ign file
|
||||||
@ -33,6 +35,14 @@ type MachineVM struct {
|
|||||||
RemoteUsername string
|
RemoteUsername string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Mount struct {
|
||||||
|
Type string
|
||||||
|
Tag string
|
||||||
|
Source string
|
||||||
|
Target string
|
||||||
|
ReadOnly bool
|
||||||
|
}
|
||||||
|
|
||||||
type Monitor struct {
|
type Monitor struct {
|
||||||
// Address portion of the qmp monitor (/tmp/tmp.sock)
|
// Address portion of the qmp monitor (/tmp/tmp.sock)
|
||||||
Address string
|
Address string
|
||||||
|
@ -36,6 +36,11 @@ func GetQemuProvider() machine.Provider {
|
|||||||
return qemuProvider
|
return qemuProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
VolumeTypeVirtfs = "virtfs"
|
||||||
|
MountType9p = "9p"
|
||||||
|
)
|
||||||
|
|
||||||
// NewMachine initializes an instance of a virtual machine based on the qemu
|
// NewMachine initializes an instance of a virtual machine based on the qemu
|
||||||
// virtualization.
|
// virtualization.
|
||||||
func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
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
|
// Add arch specific options including image location
|
||||||
v.CmdLine = append(v.CmdLine, v.addArchOptions()...)
|
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
|
// Add location of bootable image
|
||||||
v.CmdLine = append(v.CmdLine, "-drive", "if=virtio,file="+v.ImagePath)
|
v.CmdLine = append(v.CmdLine, "-drive", "if=virtio,file="+v.ImagePath)
|
||||||
// This kind of stinks but no other way around this r/n
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
_, err = bufio.NewReader(conn).ReadString('\n')
|
_, err = bufio.NewReader(conn).ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
return err
|
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
|
// Stop uses the qmp monitor to call a system_powerdown
|
||||||
@ -506,6 +590,16 @@ func (v *MachineVM) isRunning() bool {
|
|||||||
return true
|
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.
|
// SSH opens an interactive SSH session to the vm specified.
|
||||||
// Added ssh function to VM interface: pkg/machine/config/go : line 58
|
// Added ssh function to VM interface: pkg/machine/config/go : line 58
|
||||||
func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error {
|
func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error {
|
||||||
|
Reference in New Issue
Block a user