From 7be6cd4b091b2c3660b2c2321c4a3c53bbdeabf6 Mon Sep 17 00:00:00 2001 From: Jake Correnti Date: Thu, 8 Feb 2024 19:25:10 -0500 Subject: [PATCH] machine: USB passthrough Sets up USB passthrough for machine. Additionally moves `SetOptions` out from `pkg/machine/config.go` to its own file in `pkg/machine/define/setopts.go`. [NO NEW TESTS NEEDED] Signed-off-by: Jake Correnti --- cmd/podman/machine/set.go | 19 ++++++++----------- pkg/machine/applehv/stubber.go | 14 +++++++++----- pkg/machine/config.go | 11 +---------- pkg/machine/define/setopts.go | 12 ++++++++++++ pkg/machine/hyperv/stubber.go | 26 +++++++++++++++----------- pkg/machine/qemu/stubber.go | 21 ++++++++++++++------- pkg/machine/shim/host.go | 2 +- pkg/machine/vmconfigs/config.go | 3 +-- pkg/machine/vmconfigs/machine.go | 14 ++++++++++++-- pkg/machine/wsl/machine.go | 2 +- 10 files changed, 74 insertions(+), 50 deletions(-) create mode 100644 pkg/machine/define/setopts.go diff --git a/cmd/podman/machine/set.go b/cmd/podman/machine/set.go index e678de59e6..1c975622df 100644 --- a/cmd/podman/machine/set.go +++ b/cmd/podman/machine/set.go @@ -9,6 +9,7 @@ import ( "github.com/containers/common/pkg/strongunits" "github.com/containers/podman/v5/cmd/podman/registry" "github.com/containers/podman/v5/pkg/machine" + "github.com/containers/podman/v5/pkg/machine/define" "github.com/containers/podman/v5/pkg/machine/vmconfigs" "github.com/spf13/cobra" ) @@ -28,7 +29,7 @@ var ( var ( setFlags = SetFlags{} - setOpts = machine.SetOptions{} + setOpts = define.SetOptions{} ) type SetFlags struct { @@ -89,10 +90,7 @@ func init() { func setMachine(cmd *cobra.Command, args []string) error { var ( - err error - newCPUs, newMemory *uint64 - newDiskSize *strongunits.GiB - newRootful *bool + err error ) vmName := defaultMachineName @@ -111,15 +109,15 @@ func setMachine(cmd *cobra.Command, args []string) error { } if cmd.Flags().Changed("rootful") { - newRootful = &setFlags.Rootful + setOpts.Rootful = &setFlags.Rootful } if cmd.Flags().Changed("cpus") { mc.Resources.CPUs = setFlags.CPUs - newCPUs = &mc.Resources.CPUs + setOpts.CPUs = &mc.Resources.CPUs } if cmd.Flags().Changed("memory") { mc.Resources.Memory = setFlags.Memory - newMemory = &mc.Resources.Memory + setOpts.Memory = &mc.Resources.Memory } if cmd.Flags().Changed("disk-size") { if setFlags.DiskSize <= mc.Resources.DiskSize { @@ -127,20 +125,19 @@ func setMachine(cmd *cobra.Command, args []string) error { } mc.Resources.DiskSize = setFlags.DiskSize newDiskSizeGB := strongunits.GiB(setFlags.DiskSize) - newDiskSize = &newDiskSizeGB + setOpts.DiskSize = &newDiskSizeGB } if cmd.Flags().Changed("user-mode-networking") { // TODO This needs help setOpts.UserModeNetworking = &setFlags.UserModeNetworking } if cmd.Flags().Changed("usb") { - // TODO This needs help setOpts.USBs = &setFlags.USBs } // At this point, we have the known changed information, etc // Walk through changes to the providers if they need them - if err := provider.SetProviderAttrs(mc, newCPUs, newMemory, newDiskSize, newRootful); err != nil { + if err := provider.SetProviderAttrs(mc, setOpts); err != nil { return err } diff --git a/pkg/machine/applehv/stubber.go b/pkg/machine/applehv/stubber.go index ffd6f06c6a..a8ce1b068c 100644 --- a/pkg/machine/applehv/stubber.go +++ b/pkg/machine/applehv/stubber.go @@ -79,19 +79,23 @@ func (a AppleHVStubber) RemoveAndCleanMachines(_ *define.MachineDirs) error { return nil } -func (a AppleHVStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, cpus, memory *uint64, newDiskSize *strongunits.GiB, newRootful *bool) error { - if newDiskSize != nil { - if err := resizeDisk(mc, *newDiskSize); err != nil { +func (a AppleHVStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, opts define.SetOptions) error { + if opts.DiskSize != nil { + if err := resizeDisk(mc, *opts.DiskSize); err != nil { return err } } - if newRootful != nil && mc.HostUser.Rootful != *newRootful { - if err := mc.SetRootful(*newRootful); err != nil { + if opts.Rootful != nil && mc.HostUser.Rootful != *opts.Rootful { + if err := mc.SetRootful(*opts.Rootful); err != nil { return err } } + if opts.USBs != nil { + return fmt.Errorf("changing USBs not supported for applehv machines") + } + // VFKit does not require saving memory, disk, or cpu return nil } diff --git a/pkg/machine/config.go b/pkg/machine/config.go index 7e75327fd1..7730d5c525 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -68,15 +68,6 @@ type ListResponse struct { UserModeNetworking bool } -type SetOptions struct { - CPUs *uint64 - DiskSize *uint64 - Memory *uint64 - Rootful *bool - UserModeNetworking *bool - USBs *[]string -} - type SSHOptions struct { Username string Args []string @@ -101,7 +92,7 @@ type VM interface { Init(opts define.InitOptions) (bool, error) Inspect() (*InspectInfo, error) Remove(name string, opts RemoveOptions) (string, func() error, error) - Set(name string, opts SetOptions) ([]error, error) + Set(name string, opts define.SetOptions) ([]error, error) SSH(name string, opts SSHOptions) error Start(name string, opts StartOptions) error State(bypass bool) (define.Status, error) diff --git a/pkg/machine/define/setopts.go b/pkg/machine/define/setopts.go new file mode 100644 index 0000000000..4f6ba24489 --- /dev/null +++ b/pkg/machine/define/setopts.go @@ -0,0 +1,12 @@ +package define + +import "github.com/containers/common/pkg/strongunits" + +type SetOptions struct { + CPUs *uint64 + DiskSize *strongunits.GiB + Memory *uint64 + Rootful *bool + UserModeNetworking *bool + USBs *[]string +} diff --git a/pkg/machine/hyperv/stubber.go b/pkg/machine/hyperv/stubber.go index 9acdc4ab81..cfc9b5ac0c 100644 --- a/pkg/machine/hyperv/stubber.go +++ b/pkg/machine/hyperv/stubber.go @@ -290,7 +290,7 @@ func stateConversion(s hypervctl.EnabledState) (define.Status, error) { return define.Unknown, fmt.Errorf("unknown state: %q", s.String()) } -func (h HyperVStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, cpus, memory *uint64, newDiskSize *strongunits.GiB, newRootful *bool) error { +func (h HyperVStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, opts define.SetOptions) error { var ( cpuChanged, memoryChanged bool ) @@ -308,35 +308,35 @@ func (h HyperVStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, cpus, memor return errors.New("unable to change settings unless vm is stopped") } - if newRootful != nil && mc.HostUser.Rootful != *newRootful { - if err := mc.SetRootful(*newRootful); err != nil { + if opts.Rootful != nil && mc.HostUser.Rootful != *opts.Rootful { + if err := mc.SetRootful(*opts.Rootful); err != nil { return err } } - if newDiskSize != nil { - if err := resizeDisk(*newDiskSize, mc.ImagePath); err != nil { + if opts.DiskSize != nil { + if err := resizeDisk(*opts.DiskSize, mc.ImagePath); err != nil { return err } } - if cpus != nil { + if opts.CPUs != nil { cpuChanged = true } - if memory != nil { + if opts.Memory != nil { memoryChanged = true } if cpuChanged || memoryChanged { err := vm.UpdateProcessorMemSettings(func(ps *hypervctl.ProcessorSettings) { if cpuChanged { - ps.VirtualQuantity = *cpus + ps.VirtualQuantity = *opts.CPUs } }, func(ms *hypervctl.MemorySettings) { if memoryChanged { ms.DynamicMemoryEnabled = false - ms.VirtualQuantity = *memory - ms.Limit = *memory - ms.Reservation = *memory + ms.VirtualQuantity = *opts.Memory + ms.Limit = *opts.Memory + ms.Reservation = *opts.Memory } }) if err != nil { @@ -344,6 +344,10 @@ func (h HyperVStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, cpus, memor } } + if opts.USBs != nil { + return fmt.Errorf("changing USBs not supported for hyperv machines") + } + return nil } diff --git a/pkg/machine/qemu/stubber.go b/pkg/machine/qemu/stubber.go index 4f845f4e42..ed5934ed0e 100644 --- a/pkg/machine/qemu/stubber.go +++ b/pkg/machine/qemu/stubber.go @@ -64,8 +64,7 @@ func (q *QEMUStubber) setQEMUCommandLine(mc *vmconfigs.MachineConfig) error { q.Command.SetVirtfsMount(mount.Source, mount.Tag, securityModel, mount.ReadOnly) } - // TODO - // v.QEMUConfig.Command.SetUSBHostPassthrough(v.USBs) + q.Command.SetUSBHostPassthrough(mc.Resources.USBs) return nil } @@ -243,19 +242,27 @@ func (q *QEMUStubber) resizeDisk(newSize strongunits.GiB, diskPath *define.VMFil return nil } -func (q *QEMUStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, cpus, memory *uint64, newDiskSize *strongunits.GiB, newRootful *bool) error { - if newDiskSize != nil { - if err := q.resizeDisk(*newDiskSize, mc.ImagePath); err != nil { +func (q *QEMUStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, opts define.SetOptions) error { + if opts.DiskSize != nil { + if err := q.resizeDisk(*opts.DiskSize, mc.ImagePath); err != nil { return err } } - if newRootful != nil && mc.HostUser.Rootful != *newRootful { - if err := mc.SetRootful(*newRootful); err != nil { + if opts.Rootful != nil && mc.HostUser.Rootful != *opts.Rootful { + if err := mc.SetRootful(*opts.Rootful); err != nil { return err } } + if opts.USBs != nil { + usbs, err := command.ParseUSBs(*opts.USBs) + if err != nil { + return err + } + mc.Resources.USBs = usbs + } + // Because QEMU does nothing with these hardware attributes, we can simply return return nil } diff --git a/pkg/machine/shim/host.go b/pkg/machine/shim/host.go index d3f3059a9c..ece54f4dd5 100644 --- a/pkg/machine/shim/host.go +++ b/pkg/machine/shim/host.go @@ -104,7 +104,7 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) (*vmconfigs.M return nil, err } - mc, err := vmconfigs.NewMachineConfig(opts, dirs, sshIdentityPath) + mc, err := vmconfigs.NewMachineConfig(opts, dirs, sshIdentityPath, mp.VMType()) if err != nil { return nil, err } diff --git a/pkg/machine/vmconfigs/config.go b/pkg/machine/vmconfigs/config.go index 9cd640b636..44179c0fc0 100644 --- a/pkg/machine/vmconfigs/config.go +++ b/pkg/machine/vmconfigs/config.go @@ -5,7 +5,6 @@ import ( "net/url" "time" - "github.com/containers/common/pkg/strongunits" gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/containers/podman/v5/pkg/machine/define" "github.com/containers/podman/v5/pkg/machine/ignition" @@ -114,7 +113,7 @@ type VMProvider interface { //nolint:interfacebloat MountVolumesToVM(mc *MachineConfig, quiet bool) error Remove(mc *MachineConfig) ([]string, func() error, error) RemoveAndCleanMachines(dirs *define.MachineDirs) error - SetProviderAttrs(mc *MachineConfig, cpus, memory *uint64, newDiskSize *strongunits.GiB, newRootful *bool) error + SetProviderAttrs(mc *MachineConfig, opts define.SetOptions) error StartNetworking(mc *MachineConfig, cmd *gvproxy.GvproxyCommand) error PostStartNetworking(mc *MachineConfig) error StartVM(mc *MachineConfig) (func() error, func() error, error) diff --git a/pkg/machine/vmconfigs/machine.go b/pkg/machine/vmconfigs/machine.go index 34bb911f53..1176c92109 100644 --- a/pkg/machine/vmconfigs/machine.go +++ b/pkg/machine/vmconfigs/machine.go @@ -14,6 +14,7 @@ import ( "github.com/containers/podman/v5/pkg/machine/connection" "github.com/containers/podman/v5/pkg/machine/define" "github.com/containers/podman/v5/pkg/machine/lock" + "github.com/containers/podman/v5/pkg/machine/qemu/command" "github.com/containers/podman/v5/utils" "github.com/sirupsen/logrus" ) @@ -40,7 +41,7 @@ var ( type RemoteConnectionType string // NewMachineConfig creates the initial machine configuration file from cli options -func NewMachineConfig(opts define.InitOptions, dirs *define.MachineDirs, sshIdentityPath string) (*MachineConfig, error) { +func NewMachineConfig(opts define.InitOptions, dirs *define.MachineDirs, sshIdentityPath string, vmtype define.VMType) (*MachineConfig, error) { mc := new(MachineConfig) mc.Name = opts.Name mc.dirs = dirs @@ -58,12 +59,21 @@ func NewMachineConfig(opts define.InitOptions, dirs *define.MachineDirs, sshIden } mc.configPath = cf + if vmtype != define.QemuVirt && len(opts.USBs) > 0 { + return nil, fmt.Errorf("USB host passthrough not supported for %s machines", vmtype) + } + + usbs, err := command.ParseUSBs(opts.USBs) + if err != nil { + return nil, err + } + // System Resources mrc := ResourceConfig{ CPUs: opts.CPUS, DiskSize: opts.DiskSize, Memory: opts.Memory, - USBs: nil, // Needs to be filled in by providers? + USBs: usbs, } mc.Resources = mrc diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go index 7b0400ecbb..42a6331bbe 100644 --- a/pkg/machine/wsl/machine.go +++ b/pkg/machine/wsl/machine.go @@ -1105,7 +1105,7 @@ func setupWslProxyEnv() (hasProxy bool) { return } -func (v *MachineVM) Set(_ string, opts machine.SetOptions) ([]error, error) { +func (v *MachineVM) Set(_ string, opts define.SetOptions) ([]error, error) { // If one setting fails to be applied, the others settings will not fail and still be applied. // The setting(s) that failed to be applied will have its errors returned in setErrors var setErrors []error