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 <jakecorrenti+github@proton.me>
This commit is contained in:
Jake Correnti
2024-02-08 19:25:10 -05:00
parent 5311233f86
commit 7be6cd4b09
10 changed files with 74 additions and 50 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/containers/common/pkg/strongunits" "github.com/containers/common/pkg/strongunits"
"github.com/containers/podman/v5/cmd/podman/registry" "github.com/containers/podman/v5/cmd/podman/registry"
"github.com/containers/podman/v5/pkg/machine" "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/containers/podman/v5/pkg/machine/vmconfigs"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -28,7 +29,7 @@ var (
var ( var (
setFlags = SetFlags{} setFlags = SetFlags{}
setOpts = machine.SetOptions{} setOpts = define.SetOptions{}
) )
type SetFlags struct { type SetFlags struct {
@ -90,9 +91,6 @@ func init() {
func setMachine(cmd *cobra.Command, args []string) error { func setMachine(cmd *cobra.Command, args []string) error {
var ( var (
err error err error
newCPUs, newMemory *uint64
newDiskSize *strongunits.GiB
newRootful *bool
) )
vmName := defaultMachineName vmName := defaultMachineName
@ -111,15 +109,15 @@ func setMachine(cmd *cobra.Command, args []string) error {
} }
if cmd.Flags().Changed("rootful") { if cmd.Flags().Changed("rootful") {
newRootful = &setFlags.Rootful setOpts.Rootful = &setFlags.Rootful
} }
if cmd.Flags().Changed("cpus") { if cmd.Flags().Changed("cpus") {
mc.Resources.CPUs = setFlags.CPUs mc.Resources.CPUs = setFlags.CPUs
newCPUs = &mc.Resources.CPUs setOpts.CPUs = &mc.Resources.CPUs
} }
if cmd.Flags().Changed("memory") { if cmd.Flags().Changed("memory") {
mc.Resources.Memory = setFlags.Memory mc.Resources.Memory = setFlags.Memory
newMemory = &mc.Resources.Memory setOpts.Memory = &mc.Resources.Memory
} }
if cmd.Flags().Changed("disk-size") { if cmd.Flags().Changed("disk-size") {
if setFlags.DiskSize <= mc.Resources.DiskSize { if setFlags.DiskSize <= mc.Resources.DiskSize {
@ -127,20 +125,19 @@ func setMachine(cmd *cobra.Command, args []string) error {
} }
mc.Resources.DiskSize = setFlags.DiskSize mc.Resources.DiskSize = setFlags.DiskSize
newDiskSizeGB := strongunits.GiB(setFlags.DiskSize) newDiskSizeGB := strongunits.GiB(setFlags.DiskSize)
newDiskSize = &newDiskSizeGB setOpts.DiskSize = &newDiskSizeGB
} }
if cmd.Flags().Changed("user-mode-networking") { if cmd.Flags().Changed("user-mode-networking") {
// TODO This needs help // TODO This needs help
setOpts.UserModeNetworking = &setFlags.UserModeNetworking setOpts.UserModeNetworking = &setFlags.UserModeNetworking
} }
if cmd.Flags().Changed("usb") { if cmd.Flags().Changed("usb") {
// TODO This needs help
setOpts.USBs = &setFlags.USBs setOpts.USBs = &setFlags.USBs
} }
// At this point, we have the known changed information, etc // At this point, we have the known changed information, etc
// Walk through changes to the providers if they need them // 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 return err
} }

View File

@ -79,19 +79,23 @@ func (a AppleHVStubber) RemoveAndCleanMachines(_ *define.MachineDirs) error {
return nil return nil
} }
func (a AppleHVStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, cpus, memory *uint64, newDiskSize *strongunits.GiB, newRootful *bool) error { func (a AppleHVStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, opts define.SetOptions) error {
if newDiskSize != nil { if opts.DiskSize != nil {
if err := resizeDisk(mc, *newDiskSize); err != nil { if err := resizeDisk(mc, *opts.DiskSize); err != nil {
return err return err
} }
} }
if newRootful != nil && mc.HostUser.Rootful != *newRootful { if opts.Rootful != nil && mc.HostUser.Rootful != *opts.Rootful {
if err := mc.SetRootful(*newRootful); err != nil { if err := mc.SetRootful(*opts.Rootful); err != nil {
return err 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 // VFKit does not require saving memory, disk, or cpu
return nil return nil
} }

View File

@ -68,15 +68,6 @@ type ListResponse struct {
UserModeNetworking bool UserModeNetworking bool
} }
type SetOptions struct {
CPUs *uint64
DiskSize *uint64
Memory *uint64
Rootful *bool
UserModeNetworking *bool
USBs *[]string
}
type SSHOptions struct { type SSHOptions struct {
Username string Username string
Args []string Args []string
@ -101,7 +92,7 @@ type VM interface {
Init(opts define.InitOptions) (bool, error) Init(opts define.InitOptions) (bool, error)
Inspect() (*InspectInfo, error) Inspect() (*InspectInfo, error)
Remove(name string, opts RemoveOptions) (string, func() error, 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 SSH(name string, opts SSHOptions) error
Start(name string, opts StartOptions) error Start(name string, opts StartOptions) error
State(bypass bool) (define.Status, error) State(bypass bool) (define.Status, error)

View File

@ -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
}

View File

@ -290,7 +290,7 @@ func stateConversion(s hypervctl.EnabledState) (define.Status, error) {
return define.Unknown, fmt.Errorf("unknown state: %q", s.String()) 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 ( var (
cpuChanged, memoryChanged bool 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") return errors.New("unable to change settings unless vm is stopped")
} }
if newRootful != nil && mc.HostUser.Rootful != *newRootful { if opts.Rootful != nil && mc.HostUser.Rootful != *opts.Rootful {
if err := mc.SetRootful(*newRootful); err != nil { if err := mc.SetRootful(*opts.Rootful); err != nil {
return err return err
} }
} }
if newDiskSize != nil { if opts.DiskSize != nil {
if err := resizeDisk(*newDiskSize, mc.ImagePath); err != nil { if err := resizeDisk(*opts.DiskSize, mc.ImagePath); err != nil {
return err return err
} }
} }
if cpus != nil { if opts.CPUs != nil {
cpuChanged = true cpuChanged = true
} }
if memory != nil { if opts.Memory != nil {
memoryChanged = true memoryChanged = true
} }
if cpuChanged || memoryChanged { if cpuChanged || memoryChanged {
err := vm.UpdateProcessorMemSettings(func(ps *hypervctl.ProcessorSettings) { err := vm.UpdateProcessorMemSettings(func(ps *hypervctl.ProcessorSettings) {
if cpuChanged { if cpuChanged {
ps.VirtualQuantity = *cpus ps.VirtualQuantity = *opts.CPUs
} }
}, func(ms *hypervctl.MemorySettings) { }, func(ms *hypervctl.MemorySettings) {
if memoryChanged { if memoryChanged {
ms.DynamicMemoryEnabled = false ms.DynamicMemoryEnabled = false
ms.VirtualQuantity = *memory ms.VirtualQuantity = *opts.Memory
ms.Limit = *memory ms.Limit = *opts.Memory
ms.Reservation = *memory ms.Reservation = *opts.Memory
} }
}) })
if err != nil { 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 return nil
} }

View File

@ -64,8 +64,7 @@ func (q *QEMUStubber) setQEMUCommandLine(mc *vmconfigs.MachineConfig) error {
q.Command.SetVirtfsMount(mount.Source, mount.Tag, securityModel, mount.ReadOnly) q.Command.SetVirtfsMount(mount.Source, mount.Tag, securityModel, mount.ReadOnly)
} }
// TODO q.Command.SetUSBHostPassthrough(mc.Resources.USBs)
// v.QEMUConfig.Command.SetUSBHostPassthrough(v.USBs)
return nil return nil
} }
@ -243,19 +242,27 @@ func (q *QEMUStubber) resizeDisk(newSize strongunits.GiB, diskPath *define.VMFil
return nil return nil
} }
func (q *QEMUStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, cpus, memory *uint64, newDiskSize *strongunits.GiB, newRootful *bool) error { func (q *QEMUStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, opts define.SetOptions) error {
if newDiskSize != nil { if opts.DiskSize != nil {
if err := q.resizeDisk(*newDiskSize, mc.ImagePath); err != nil { if err := q.resizeDisk(*opts.DiskSize, mc.ImagePath); err != nil {
return err return err
} }
} }
if newRootful != nil && mc.HostUser.Rootful != *newRootful { if opts.Rootful != nil && mc.HostUser.Rootful != *opts.Rootful {
if err := mc.SetRootful(*newRootful); err != nil { if err := mc.SetRootful(*opts.Rootful); err != nil {
return err 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 // Because QEMU does nothing with these hardware attributes, we can simply return
return nil return nil
} }

View File

@ -104,7 +104,7 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) (*vmconfigs.M
return nil, err return nil, err
} }
mc, err := vmconfigs.NewMachineConfig(opts, dirs, sshIdentityPath) mc, err := vmconfigs.NewMachineConfig(opts, dirs, sshIdentityPath, mp.VMType())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -5,7 +5,6 @@ import (
"net/url" "net/url"
"time" "time"
"github.com/containers/common/pkg/strongunits"
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types" gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
"github.com/containers/podman/v5/pkg/machine/define" "github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/ignition" "github.com/containers/podman/v5/pkg/machine/ignition"
@ -114,7 +113,7 @@ type VMProvider interface { //nolint:interfacebloat
MountVolumesToVM(mc *MachineConfig, quiet bool) error MountVolumesToVM(mc *MachineConfig, quiet bool) error
Remove(mc *MachineConfig) ([]string, func() error, error) Remove(mc *MachineConfig) ([]string, func() error, error)
RemoveAndCleanMachines(dirs *define.MachineDirs) 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 StartNetworking(mc *MachineConfig, cmd *gvproxy.GvproxyCommand) error
PostStartNetworking(mc *MachineConfig) error PostStartNetworking(mc *MachineConfig) error
StartVM(mc *MachineConfig) (func() error, func() error, error) StartVM(mc *MachineConfig) (func() error, func() error, error)

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v5/pkg/machine/connection" "github.com/containers/podman/v5/pkg/machine/connection"
"github.com/containers/podman/v5/pkg/machine/define" "github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/lock" "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/containers/podman/v5/utils"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -40,7 +41,7 @@ var (
type RemoteConnectionType string type RemoteConnectionType string
// NewMachineConfig creates the initial machine configuration file from cli options // 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 := new(MachineConfig)
mc.Name = opts.Name mc.Name = opts.Name
mc.dirs = dirs mc.dirs = dirs
@ -58,12 +59,21 @@ func NewMachineConfig(opts define.InitOptions, dirs *define.MachineDirs, sshIden
} }
mc.configPath = cf 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 // System Resources
mrc := ResourceConfig{ mrc := ResourceConfig{
CPUs: opts.CPUS, CPUs: opts.CPUS,
DiskSize: opts.DiskSize, DiskSize: opts.DiskSize,
Memory: opts.Memory, Memory: opts.Memory,
USBs: nil, // Needs to be filled in by providers? USBs: usbs,
} }
mc.Resources = mrc mc.Resources = mrc

View File

@ -1105,7 +1105,7 @@ func setupWslProxyEnv() (hasProxy bool) {
return 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. // 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 // The setting(s) that failed to be applied will have its errors returned in setErrors
var setErrors []error var setErrors []error