Re-organize hypervisor implementations
Ensures that for each hypervisor implementation, their `config.go` file deals with implementing the `VirtProvider` interface while the `machine.go` file is for implementing the `VM` interface. Moves the `Virtualization` type into a common file and created wrappers for the individual hypervisors. Allows for shared functions that are exactly the same while providing the flexibility to create hypervisor-specific implementations of the functions. [NO NEW TESTS NEEDED] Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
This commit is contained in:
parent
49e0bde2bf
commit
516034215f
|
|
@ -29,7 +29,7 @@ func GetSystemProvider() (machine.VirtProvider, error) {
|
|||
logrus.Debugf("Using Podman machine with `%s` virtualization provider", resolvedVMType.String())
|
||||
switch resolvedVMType {
|
||||
case machine.QemuVirt:
|
||||
return qemu.GetVirtualizationProvider(), nil
|
||||
return qemu.VirtualizationProvider(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported virtualization provider: `%s`", resolvedVMType.String())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ func GetSystemProvider() (machine.VirtProvider, error) {
|
|||
logrus.Debugf("Using Podman machine with `%s` virtualization provider", resolvedVMType.String())
|
||||
switch resolvedVMType {
|
||||
case machine.QemuVirt:
|
||||
return qemu.GetVirtualizationProvider(), nil
|
||||
return qemu.VirtualizationProvider(), nil
|
||||
case machine.AppleHvVirt:
|
||||
return applehv.GetVirtualizationProvider(), nil
|
||||
return applehv.VirtualizationProvider(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported virtualization provider: `%s`", resolvedVMType.String())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ func GetSystemProvider() (machine.VirtProvider, error) {
|
|||
logrus.Debugf("Using Podman machine with `%s` virtualization provider", resolvedVMType.String())
|
||||
switch resolvedVMType {
|
||||
case machine.WSLVirt:
|
||||
return wsl.GetWSLProvider(), nil
|
||||
return wsl.VirtualizationProvider(), nil
|
||||
case machine.HyperVVirt:
|
||||
return hyperv.GetVirtualizationProvider(), nil
|
||||
return hyperv.VirtualizationProvider(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported virtualization provider: `%s`", resolvedVMType.String())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,8 @@ const (
|
|||
defaultVFKitEndpoint = "http://localhost:8081"
|
||||
)
|
||||
|
||||
type Virtualization struct {
|
||||
artifact machine.Artifact
|
||||
compression machine.ImageCompression
|
||||
format machine.ImageFormat
|
||||
type AppleHVVirtualization struct {
|
||||
machine.Virtualization
|
||||
}
|
||||
|
||||
type MMHardwareConfig struct {
|
||||
|
|
@ -30,11 +28,13 @@ type MMHardwareConfig struct {
|
|||
Memory int32
|
||||
}
|
||||
|
||||
func (v Virtualization) Artifact() machine.Artifact {
|
||||
return machine.Metal
|
||||
func VirtualizationProvider() machine.VirtProvider {
|
||||
return &AppleHVVirtualization{
|
||||
machine.NewVirtualization(machine.Metal, machine.Xz, machine.Raw),
|
||||
}
|
||||
}
|
||||
|
||||
func (v Virtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
||||
func (v AppleHVVirtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
||||
fsVms, err := getVMInfos()
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
|
|
@ -48,15 +48,7 @@ func (v Virtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
|||
return false, "", nil
|
||||
}
|
||||
|
||||
func (v Virtualization) Compression() machine.ImageCompression {
|
||||
return v.compression
|
||||
}
|
||||
|
||||
func (v Virtualization) Format() machine.ImageFormat {
|
||||
return v.format
|
||||
}
|
||||
|
||||
func (v Virtualization) IsValidVMName(name string) (bool, error) {
|
||||
func (v AppleHVVirtualization) IsValidVMName(name string) (bool, error) {
|
||||
mm := MacMachine{Name: name}
|
||||
configDir, err := machine.GetConfDir(machine.AppleHvVirt)
|
||||
if err != nil {
|
||||
|
|
@ -68,7 +60,7 @@ func (v Virtualization) IsValidVMName(name string) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (v Virtualization) List(opts machine.ListOptions) ([]*machine.ListResponse, error) {
|
||||
func (v AppleHVVirtualization) List(opts machine.ListOptions) ([]*machine.ListResponse, error) {
|
||||
var (
|
||||
response []*machine.ListResponse
|
||||
)
|
||||
|
|
@ -108,12 +100,12 @@ func (v Virtualization) List(opts machine.ListOptions) ([]*machine.ListResponse,
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (v Virtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||
func (v AppleHVVirtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||
m := MacMachine{Name: name}
|
||||
return m.loadFromFile()
|
||||
}
|
||||
|
||||
func (v Virtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||
func (v AppleHVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||
m := MacMachine{Name: opts.Name}
|
||||
|
||||
configDir, err := machine.GetConfDir(machine.AppleHvVirt)
|
||||
|
|
@ -149,16 +141,16 @@ func (v Virtualization) NewMachine(opts machine.InitOptions) (machine.VM, error)
|
|||
return m.loadFromFile()
|
||||
}
|
||||
|
||||
func (v Virtualization) RemoveAndCleanMachines() error {
|
||||
func (v AppleHVVirtualization) RemoveAndCleanMachines() error {
|
||||
// This can be implemented when host networking is completed.
|
||||
return machine.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (v Virtualization) VMType() machine.VMType {
|
||||
func (v AppleHVVirtualization) VMType() machine.VMType {
|
||||
return vmtype
|
||||
}
|
||||
|
||||
func (v Virtualization) loadFromLocalJson() ([]*MacMachine, error) {
|
||||
func (v AppleHVVirtualization) loadFromLocalJson() ([]*MacMachine, error) {
|
||||
var (
|
||||
jsonFiles []string
|
||||
mms []*MacMachine
|
||||
|
|
|
|||
|
|
@ -27,14 +27,6 @@ var (
|
|||
vmtype = machine.AppleHvVirt
|
||||
)
|
||||
|
||||
func GetVirtualizationProvider() machine.VirtProvider {
|
||||
return &Virtualization{
|
||||
artifact: machine.None,
|
||||
compression: machine.Xz,
|
||||
format: machine.Raw,
|
||||
}
|
||||
}
|
||||
|
||||
// VfkitHelper describes the use of vfkit: cmdline and endpoint
|
||||
type VfkitHelper struct {
|
||||
Bootloader string
|
||||
|
|
|
|||
|
|
@ -48,19 +48,6 @@ const (
|
|||
DefaultMachineName string = "podman-machine-default"
|
||||
)
|
||||
|
||||
type VirtProvider interface {
|
||||
Artifact() Artifact
|
||||
CheckExclusiveActiveVM() (bool, string, error)
|
||||
Compression() ImageCompression
|
||||
Format() ImageFormat
|
||||
IsValidVMName(name string) (bool, error)
|
||||
List(opts ListOptions) ([]*ListResponse, error)
|
||||
LoadVMByName(name string) (VM, error)
|
||||
NewMachine(opts InitOptions) (VM, error)
|
||||
RemoveAndCleanMachines() error
|
||||
VMType() VMType
|
||||
}
|
||||
|
||||
type RemoteConnectionType string
|
||||
|
||||
var (
|
||||
|
|
@ -428,3 +415,42 @@ func ParseVMType(input string, emptyFallback VMType) (VMType, error) {
|
|||
return QemuVirt, fmt.Errorf("unknown VMType `%s`", input)
|
||||
}
|
||||
}
|
||||
|
||||
type VirtProvider interface {
|
||||
Artifact() Artifact
|
||||
CheckExclusiveActiveVM() (bool, string, error)
|
||||
Compression() ImageCompression
|
||||
Format() ImageFormat
|
||||
IsValidVMName(name string) (bool, error)
|
||||
List(opts ListOptions) ([]*ListResponse, error)
|
||||
LoadVMByName(name string) (VM, error)
|
||||
NewMachine(opts InitOptions) (VM, error)
|
||||
RemoveAndCleanMachines() error
|
||||
VMType() VMType
|
||||
}
|
||||
|
||||
type Virtualization struct {
|
||||
artifact Artifact
|
||||
compression ImageCompression
|
||||
format ImageFormat
|
||||
}
|
||||
|
||||
func (p *Virtualization) Artifact() Artifact {
|
||||
return p.artifact
|
||||
}
|
||||
|
||||
func (p *Virtualization) Compression() ImageCompression {
|
||||
return p.compression
|
||||
}
|
||||
|
||||
func (p *Virtualization) Format() ImageFormat {
|
||||
return p.format
|
||||
}
|
||||
|
||||
func NewVirtualization(artifact Artifact, compression ImageCompression, format ImageFormat) Virtualization {
|
||||
return Virtualization{
|
||||
artifact,
|
||||
compression,
|
||||
format,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ func TestMachine(t *testing.T) {
|
|||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
qemuVP := qemu.GetVirtualizationProvider()
|
||||
qemuVP := qemu.VirtualizationProvider()
|
||||
fcd, err := machine.GetFCOSDownload(qemuVP, defaultStream)
|
||||
if err != nil {
|
||||
Fail("unable to get virtual machine image")
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Virtualization struct {
|
||||
artifact machine.Artifact
|
||||
compression machine.ImageCompression
|
||||
format machine.ImageFormat
|
||||
type HyperVVirtualization struct {
|
||||
machine.Virtualization
|
||||
}
|
||||
|
||||
func (v Virtualization) Artifact() machine.Artifact {
|
||||
return machine.None
|
||||
func VirtualizationProvider() machine.VirtProvider {
|
||||
return &HyperVVirtualization{
|
||||
machine.NewVirtualization(machine.HyperV, machine.Zip, machine.Vhdx),
|
||||
}
|
||||
}
|
||||
|
||||
func (v Virtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
||||
func (v HyperVVirtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
||||
vmm := hypervctl.NewVirtualMachineManager()
|
||||
// Use of GetAll is OK here because we do not want to use the same name
|
||||
// as something already *actually* configured in hyperv
|
||||
|
|
@ -43,15 +43,7 @@ func (v Virtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
|||
return false, "", nil
|
||||
}
|
||||
|
||||
func (v Virtualization) Compression() machine.ImageCompression {
|
||||
return v.compression
|
||||
}
|
||||
|
||||
func (v Virtualization) Format() machine.ImageFormat {
|
||||
return v.format
|
||||
}
|
||||
|
||||
func (v Virtualization) IsValidVMName(name string) (bool, error) {
|
||||
func (v HyperVVirtualization) IsValidVMName(name string) (bool, error) {
|
||||
// We check both the local filesystem and hyperv for the valid name
|
||||
mm := HyperVMachine{Name: name}
|
||||
configDir, err := machine.GetConfDir(v.VMType())
|
||||
|
|
@ -69,7 +61,7 @@ func (v Virtualization) IsValidVMName(name string) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (v Virtualization) List(opts machine.ListOptions) ([]*machine.ListResponse, error) {
|
||||
func (v HyperVVirtualization) List(opts machine.ListOptions) ([]*machine.ListResponse, error) {
|
||||
mms, err := v.loadFromLocalJson()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -103,12 +95,12 @@ func (v Virtualization) List(opts machine.ListOptions) ([]*machine.ListResponse,
|
|||
return response, err
|
||||
}
|
||||
|
||||
func (v Virtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||
func (v HyperVVirtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||
m := &HyperVMachine{Name: name}
|
||||
return m.loadFromFile()
|
||||
}
|
||||
|
||||
func (v Virtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||
func (v HyperVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||
m := HyperVMachine{Name: opts.Name}
|
||||
if len(opts.ImagePath) < 1 {
|
||||
return nil, errors.New("must define --image-path for hyperv support")
|
||||
|
|
@ -180,7 +172,7 @@ func (v Virtualization) NewMachine(opts machine.InitOptions) (machine.VM, error)
|
|||
return v.LoadVMByName(opts.Name)
|
||||
}
|
||||
|
||||
func (v Virtualization) RemoveAndCleanMachines() error {
|
||||
func (v HyperVVirtualization) RemoveAndCleanMachines() error {
|
||||
// Error handling used here is following what qemu did
|
||||
var (
|
||||
prevErr error
|
||||
|
|
@ -238,11 +230,11 @@ func (v Virtualization) RemoveAndCleanMachines() error {
|
|||
return prevErr
|
||||
}
|
||||
|
||||
func (v Virtualization) VMType() machine.VMType {
|
||||
func (v HyperVVirtualization) VMType() machine.VMType {
|
||||
return vmtype
|
||||
}
|
||||
|
||||
func (v Virtualization) loadFromLocalJson() ([]*HyperVMachine, error) {
|
||||
func (v HyperVVirtualization) loadFromLocalJson() ([]*HyperVMachine, error) {
|
||||
var (
|
||||
jsonFiles []string
|
||||
mms []*HyperVMachine
|
||||
|
|
|
|||
|
|
@ -30,14 +30,6 @@ var (
|
|||
vmtype = machine.HyperVVirt
|
||||
)
|
||||
|
||||
func GetVirtualizationProvider() machine.VirtProvider {
|
||||
return &Virtualization{
|
||||
artifact: machine.HyperV,
|
||||
compression: machine.Zip,
|
||||
format: machine.Vhdx,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// Some of this will need to change when we are closer to having
|
||||
// working code.
|
||||
|
|
|
|||
|
|
@ -1,15 +1,312 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v4/pkg/machine"
|
||||
"github.com/containers/podman/v4/utils"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Virtualization struct {
|
||||
artifact machine.Artifact
|
||||
compression machine.ImageCompression
|
||||
format machine.ImageFormat
|
||||
type QEMUVirtualization struct {
|
||||
machine.Virtualization
|
||||
}
|
||||
|
||||
// NewMachine initializes an instance of a virtual machine based on the qemu
|
||||
// virtualization.
|
||||
func (p *QEMUVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||
vmConfigDir, err := machine.GetConfDir(vmtype)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm := new(MachineVM)
|
||||
if len(opts.Name) > 0 {
|
||||
vm.Name = opts.Name
|
||||
}
|
||||
ignitionFile, err := machine.NewMachineFile(filepath.Join(vmConfigDir, vm.Name+".ign"), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.IgnitionFile = *ignitionFile
|
||||
imagePath, err := machine.NewMachineFile(opts.ImagePath, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.ImagePath = *imagePath
|
||||
vm.RemoteUsername = opts.Username
|
||||
|
||||
// Add a random port for ssh
|
||||
port, err := utils.GetRandomPort()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.Port = port
|
||||
|
||||
vm.CPUs = opts.CPUS
|
||||
vm.Memory = opts.Memory
|
||||
vm.DiskSize = opts.DiskSize
|
||||
|
||||
vm.Created = time.Now()
|
||||
|
||||
// Find the qemu executable
|
||||
cfg, err := config.Default()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
execPath, err := cfg.FindHelperBinary(QemuCommand, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := vm.setPIDSocket(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd := []string{execPath}
|
||||
// Add memory
|
||||
cmd = append(cmd, []string{"-m", strconv.Itoa(int(vm.Memory))}...)
|
||||
// Add cpus
|
||||
cmd = append(cmd, []string{"-smp", strconv.Itoa(int(vm.CPUs))}...)
|
||||
// Add ignition file
|
||||
cmd = append(cmd, []string{"-fw_cfg", "name=opt/com.coreos/config,file=" + vm.IgnitionFile.GetPath()}...)
|
||||
// Add qmp socket
|
||||
monitor, err := NewQMPMonitor("unix", vm.Name, defaultQMPTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.QMPMonitor = monitor
|
||||
cmd = append(cmd, []string{"-qmp", monitor.Network + ":" + monitor.Address.GetPath() + ",server=on,wait=off"}...)
|
||||
|
||||
// Add network
|
||||
// Right now the mac address is hardcoded so that the host networking gives it a specific IP address. This is
|
||||
// why we can only run one vm at a time right now
|
||||
cmd = append(cmd, []string{"-netdev", "socket,id=vlan,fd=3", "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee"}...)
|
||||
if err := vm.setReadySocket(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add serial port for readiness
|
||||
cmd = append(cmd, []string{
|
||||
"-device", "virtio-serial",
|
||||
// qemu needs to establish the long name; other connections can use the symlink'd
|
||||
// Note both id and chardev start with an extra "a" because qemu requires that it
|
||||
// starts with a letter but users can also use numbers
|
||||
"-chardev", "socket,path=" + vm.ReadySocket.Path + ",server=on,wait=off,id=a" + vm.Name + "_ready",
|
||||
"-device", "virtserialport,chardev=a" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0",
|
||||
"-pidfile", vm.VMPidFilePath.GetPath()}...)
|
||||
vm.CmdLine = cmd
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
// LoadVMByName reads a json file that describes a known qemu vm
|
||||
// and returns a vm instance
|
||||
func (p *QEMUVirtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||
vm := &MachineVM{Name: name}
|
||||
vm.HostUser = machine.HostUser{UID: -1} // posix reserves -1, so use it to signify undefined
|
||||
if err := vm.update(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
// List lists all vm's that use qemu virtualization
|
||||
func (p *QEMUVirtualization) List(_ machine.ListOptions) ([]*machine.ListResponse, error) {
|
||||
return getVMInfos()
|
||||
}
|
||||
|
||||
func getVMInfos() ([]*machine.ListResponse, error) {
|
||||
vmConfigDir, err := machine.GetConfDir(vmtype)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var listed []*machine.ListResponse
|
||||
|
||||
if err = filepath.WalkDir(vmConfigDir, func(path string, d fs.DirEntry, err error) error {
|
||||
vm := new(MachineVM)
|
||||
if strings.HasSuffix(d.Name(), ".json") {
|
||||
fullPath := filepath.Join(vmConfigDir, d.Name())
|
||||
b, err := os.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(b, vm)
|
||||
if err != nil {
|
||||
// Checking if the file did not unmarshal because it is using
|
||||
// the deprecated config file format.
|
||||
migrateErr := migrateVM(fullPath, b, vm)
|
||||
if migrateErr != nil {
|
||||
return migrateErr
|
||||
}
|
||||
}
|
||||
listEntry := new(machine.ListResponse)
|
||||
|
||||
listEntry.Name = vm.Name
|
||||
listEntry.Stream = vm.ImageStream
|
||||
listEntry.VMType = "qemu"
|
||||
listEntry.CPUs = vm.CPUs
|
||||
listEntry.Memory = vm.Memory * units.MiB
|
||||
listEntry.DiskSize = vm.DiskSize * units.GiB
|
||||
listEntry.Port = vm.Port
|
||||
listEntry.RemoteUsername = vm.RemoteUsername
|
||||
listEntry.IdentityPath = vm.IdentityPath
|
||||
listEntry.CreatedAt = vm.Created
|
||||
listEntry.Starting = vm.Starting
|
||||
listEntry.UserModeNetworking = true // always true
|
||||
|
||||
if listEntry.CreatedAt.IsZero() {
|
||||
listEntry.CreatedAt = time.Now()
|
||||
vm.Created = time.Now()
|
||||
if err := vm.writeConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
state, err := vm.State(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listEntry.Running = state == machine.Running
|
||||
|
||||
if !vm.LastUp.IsZero() { // this means we have already written a time to the config
|
||||
listEntry.LastUp = vm.LastUp
|
||||
} else { // else we just created the machine AKA last up = created time
|
||||
listEntry.LastUp = vm.Created
|
||||
vm.LastUp = listEntry.LastUp
|
||||
if err := vm.writeConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
listed = append(listed, listEntry)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listed, err
|
||||
}
|
||||
|
||||
func (p *QEMUVirtualization) IsValidVMName(name string) (bool, error) {
|
||||
infos, err := getVMInfos()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, vm := range infos {
|
||||
if vm.Name == name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// CheckExclusiveActiveVM checks if there is a VM already running
|
||||
// that does not allow other VMs to be running
|
||||
func (p *QEMUVirtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
||||
vms, err := getVMInfos()
|
||||
if err != nil {
|
||||
return false, "", fmt.Errorf("checking VM active: %w", err)
|
||||
}
|
||||
for _, vm := range vms {
|
||||
if vm.Running || vm.Starting {
|
||||
return true, vm.Name, nil
|
||||
}
|
||||
}
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
// RemoveAndCleanMachines removes all machine and cleans up any other files associated with podman machine
|
||||
func (p *QEMUVirtualization) RemoveAndCleanMachines() error {
|
||||
var (
|
||||
vm machine.VM
|
||||
listResponse []*machine.ListResponse
|
||||
opts machine.ListOptions
|
||||
destroyOptions machine.RemoveOptions
|
||||
)
|
||||
destroyOptions.Force = true
|
||||
var prevErr error
|
||||
|
||||
listResponse, err := p.List(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, mach := range listResponse {
|
||||
vm, err = p.LoadVMByName(mach.Name)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
_, remove, err := vm.Remove(mach.Name, destroyOptions)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
if err := remove(); err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean leftover files in data dir
|
||||
dataDir, err := machine.DataDirPrefix()
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
err := machine.GuardedRemoveAll(dataDir)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
|
||||
// Clean leftover files in conf dir
|
||||
confDir, err := machine.ConfDirPrefix()
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
err := machine.GuardedRemoveAll(confDir)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
return prevErr
|
||||
}
|
||||
|
||||
func (p *QEMUVirtualization) VMType() machine.VMType {
|
||||
return vmtype
|
||||
}
|
||||
|
||||
func VirtualizationProvider() machine.VirtProvider {
|
||||
return &QEMUVirtualization{
|
||||
machine.NewVirtualization(machine.Qemu, machine.Xz, machine.Qcow),
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: MachineVMV1 is being deprecated in favor a more flexible and informative
|
||||
|
|
@ -47,39 +344,6 @@ type MachineVMV1 struct {
|
|||
UID int
|
||||
}
|
||||
|
||||
type MachineVM struct {
|
||||
// ConfigPath is the path to the configuration file
|
||||
ConfigPath machine.VMFile
|
||||
// The command line representation of the qemu command
|
||||
CmdLine []string
|
||||
// HostUser contains info about host user
|
||||
machine.HostUser
|
||||
// ImageConfig describes the bootable image
|
||||
machine.ImageConfig
|
||||
// Mounts is the list of remote filesystems to mount
|
||||
Mounts []machine.Mount
|
||||
// Name of VM
|
||||
Name string
|
||||
// PidFilePath is the where the Proxy PID file lives
|
||||
PidFilePath machine.VMFile
|
||||
// VMPidFilePath is the where the VM PID file lives
|
||||
VMPidFilePath machine.VMFile
|
||||
// QMPMonitor is the qemu monitor object for sending commands
|
||||
QMPMonitor Monitor
|
||||
// ReadySocket tells host when vm is booted
|
||||
ReadySocket machine.VMFile
|
||||
// ResourceConfig is physical attrs of the VM
|
||||
machine.ResourceConfig
|
||||
// SSHConfig for accessing the remote vm
|
||||
machine.SSHConfig
|
||||
// Starting tells us whether the machine is running or if we have just dialed it to start it
|
||||
Starting bool
|
||||
// Created contains the original created time instead of querying the file mod time
|
||||
Created time.Time
|
||||
// LastUp contains the last recorded uptime
|
||||
LastUp time.Time
|
||||
}
|
||||
|
||||
type Monitorv1 struct {
|
||||
// Address portion of the qmp monitor (/tmp/tmp.sock)
|
||||
Address string
|
||||
|
|
@ -89,15 +353,6 @@ type Monitorv1 struct {
|
|||
Timeout time.Duration
|
||||
}
|
||||
|
||||
type Monitor struct {
|
||||
// Address portion of the qmp monitor (/tmp/tmp.sock)
|
||||
Address machine.VMFile
|
||||
// Network portion of the qmp monitor (unix)
|
||||
Network string
|
||||
// Timeout in seconds for qmp monitor transactions
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
var (
|
||||
// defaultQMPTimeout is the timeout duration for the
|
||||
// qmp monitor interactions.
|
||||
|
|
|
|||
|
|
@ -28,10 +28,8 @@ import (
|
|||
"github.com/containers/podman/v4/pkg/machine"
|
||||
"github.com/containers/podman/v4/pkg/rootless"
|
||||
"github.com/containers/podman/v4/pkg/util"
|
||||
"github.com/containers/podman/v4/utils"
|
||||
"github.com/containers/storage/pkg/ioutils"
|
||||
"github.com/digitalocean/go-qemu/qmp"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
|
@ -41,14 +39,6 @@ var (
|
|||
vmtype = machine.QemuVirt
|
||||
)
|
||||
|
||||
func GetVirtualizationProvider() machine.VirtProvider {
|
||||
return &Virtualization{
|
||||
artifact: machine.Qemu,
|
||||
compression: machine.Xz,
|
||||
format: machine.Qcow,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
VolumeTypeVirtfs = "virtfs"
|
||||
MountType9p = "9p"
|
||||
|
|
@ -57,88 +47,46 @@ const (
|
|||
apiUpTimeout = 20 * time.Second
|
||||
)
|
||||
|
||||
// NewMachine initializes an instance of a virtual machine based on the qemu
|
||||
// virtualization.
|
||||
func (p *Virtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||
vmConfigDir, err := machine.GetConfDir(vmtype)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm := new(MachineVM)
|
||||
if len(opts.Name) > 0 {
|
||||
vm.Name = opts.Name
|
||||
}
|
||||
ignitionFile, err := machine.NewMachineFile(filepath.Join(vmConfigDir, vm.Name+".ign"), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.IgnitionFile = *ignitionFile
|
||||
imagePath, err := machine.NewMachineFile(opts.ImagePath, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.ImagePath = *imagePath
|
||||
vm.RemoteUsername = opts.Username
|
||||
type MachineVM struct {
|
||||
// ConfigPath is the path to the configuration file
|
||||
ConfigPath machine.VMFile
|
||||
// The command line representation of the qemu command
|
||||
CmdLine []string
|
||||
// HostUser contains info about host user
|
||||
machine.HostUser
|
||||
// ImageConfig describes the bootable image
|
||||
machine.ImageConfig
|
||||
// Mounts is the list of remote filesystems to mount
|
||||
Mounts []machine.Mount
|
||||
// Name of VM
|
||||
Name string
|
||||
// PidFilePath is the where the Proxy PID file lives
|
||||
PidFilePath machine.VMFile
|
||||
// VMPidFilePath is the where the VM PID file lives
|
||||
VMPidFilePath machine.VMFile
|
||||
// QMPMonitor is the qemu monitor object for sending commands
|
||||
QMPMonitor Monitor
|
||||
// ReadySocket tells host when vm is booted
|
||||
ReadySocket machine.VMFile
|
||||
// ResourceConfig is physical attrs of the VM
|
||||
machine.ResourceConfig
|
||||
// SSHConfig for accessing the remote vm
|
||||
machine.SSHConfig
|
||||
// Starting tells us whether the machine is running or if we have just dialed it to start it
|
||||
Starting bool
|
||||
// Created contains the original created time instead of querying the file mod time
|
||||
Created time.Time
|
||||
// LastUp contains the last recorded uptime
|
||||
LastUp time.Time
|
||||
}
|
||||
|
||||
// Add a random port for ssh
|
||||
port, err := utils.GetRandomPort()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.Port = port
|
||||
|
||||
vm.CPUs = opts.CPUS
|
||||
vm.Memory = opts.Memory
|
||||
vm.DiskSize = opts.DiskSize
|
||||
|
||||
vm.Created = time.Now()
|
||||
|
||||
// Find the qemu executable
|
||||
cfg, err := config.Default()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
execPath, err := cfg.FindHelperBinary(QemuCommand, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := vm.setPIDSocket(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd := []string{execPath}
|
||||
// Add memory
|
||||
cmd = append(cmd, []string{"-m", strconv.Itoa(int(vm.Memory))}...)
|
||||
// Add cpus
|
||||
cmd = append(cmd, []string{"-smp", strconv.Itoa(int(vm.CPUs))}...)
|
||||
// Add ignition file
|
||||
cmd = append(cmd, []string{"-fw_cfg", "name=opt/com.coreos/config,file=" + vm.IgnitionFile.GetPath()}...)
|
||||
// Add qmp socket
|
||||
monitor, err := NewQMPMonitor("unix", vm.Name, defaultQMPTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.QMPMonitor = monitor
|
||||
cmd = append(cmd, []string{"-qmp", monitor.Network + ":" + monitor.Address.GetPath() + ",server=on,wait=off"}...)
|
||||
|
||||
// Add network
|
||||
// Right now the mac address is hardcoded so that the host networking gives it a specific IP address. This is
|
||||
// why we can only run one vm at a time right now
|
||||
cmd = append(cmd, []string{"-netdev", "socket,id=vlan,fd=3", "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee"}...)
|
||||
if err := vm.setReadySocket(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add serial port for readiness
|
||||
cmd = append(cmd, []string{
|
||||
"-device", "virtio-serial",
|
||||
// qemu needs to establish the long name; other connections can use the symlink'd
|
||||
// Note both id and chardev start with an extra "a" because qemu requires that it
|
||||
// starts with a letter but users can also use numbers
|
||||
"-chardev", "socket,path=" + vm.ReadySocket.Path + ",server=on,wait=off,id=a" + vm.Name + "_ready",
|
||||
"-device", "virtserialport,chardev=a" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0",
|
||||
"-pidfile", vm.VMPidFilePath.GetPath()}...)
|
||||
vm.CmdLine = cmd
|
||||
return vm, nil
|
||||
type Monitor struct {
|
||||
// Address portion of the qmp monitor (/tmp/tmp.sock)
|
||||
Address machine.VMFile
|
||||
// Network portion of the qmp monitor (unix)
|
||||
Network string
|
||||
// Timeout in seconds for qmp monitor transactions
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// migrateVM takes the old configuration structure and migrates it
|
||||
|
|
@ -224,18 +172,6 @@ func migrateVM(configPath string, config []byte, vm *MachineVM) error {
|
|||
return os.Remove(configPath + ".orig")
|
||||
}
|
||||
|
||||
// LoadVMByName reads a json file that describes a known qemu vm
|
||||
// and returns a vm instance
|
||||
func (p *Virtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||
vm := &MachineVM{Name: name}
|
||||
vm.HostUser = machine.HostUser{UID: -1} // posix reserves -1, so use it to signify undefined
|
||||
if err := vm.update(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
// Init writes the json configuration file to the filesystem for
|
||||
// other verbs (start, stop)
|
||||
func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
|
||||
|
|
@ -250,7 +186,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
|
|||
case machine.Testing.String(), machine.Next.String(), machine.Stable.String(), "":
|
||||
// Get image as usual
|
||||
v.ImageStream = opts.ImagePath
|
||||
vp := GetVirtualizationProvider()
|
||||
vp := VirtualizationProvider()
|
||||
dd, err := machine.NewFcosDownloader(vmtype, v.Name, machine.FCOSStreamFromString(opts.ImagePath), vp)
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -1118,124 +1054,6 @@ func getDiskSize(path string) (uint64, error) {
|
|||
return tmpInfo.VirtualSize, nil
|
||||
}
|
||||
|
||||
// List lists all vm's that use qemu virtualization
|
||||
func (p *Virtualization) List(_ machine.ListOptions) ([]*machine.ListResponse, error) {
|
||||
return getVMInfos()
|
||||
}
|
||||
|
||||
func getVMInfos() ([]*machine.ListResponse, error) {
|
||||
vmConfigDir, err := machine.GetConfDir(vmtype)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var listed []*machine.ListResponse
|
||||
|
||||
if err = filepath.WalkDir(vmConfigDir, func(path string, d fs.DirEntry, err error) error {
|
||||
vm := new(MachineVM)
|
||||
if strings.HasSuffix(d.Name(), ".json") {
|
||||
fullPath := filepath.Join(vmConfigDir, d.Name())
|
||||
b, err := os.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(b, vm)
|
||||
if err != nil {
|
||||
// Checking if the file did not unmarshal because it is using
|
||||
// the deprecated config file format.
|
||||
migrateErr := migrateVM(fullPath, b, vm)
|
||||
if migrateErr != nil {
|
||||
return migrateErr
|
||||
}
|
||||
}
|
||||
listEntry := new(machine.ListResponse)
|
||||
|
||||
listEntry.Name = vm.Name
|
||||
listEntry.Stream = vm.ImageStream
|
||||
listEntry.VMType = "qemu"
|
||||
listEntry.CPUs = vm.CPUs
|
||||
listEntry.Memory = vm.Memory * units.MiB
|
||||
listEntry.DiskSize = vm.DiskSize * units.GiB
|
||||
listEntry.Port = vm.Port
|
||||
listEntry.RemoteUsername = vm.RemoteUsername
|
||||
listEntry.IdentityPath = vm.IdentityPath
|
||||
listEntry.CreatedAt = vm.Created
|
||||
listEntry.Starting = vm.Starting
|
||||
listEntry.UserModeNetworking = true // always true
|
||||
|
||||
if listEntry.CreatedAt.IsZero() {
|
||||
listEntry.CreatedAt = time.Now()
|
||||
vm.Created = time.Now()
|
||||
if err := vm.writeConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
state, err := vm.State(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listEntry.Running = state == machine.Running
|
||||
|
||||
if !vm.LastUp.IsZero() { // this means we have already written a time to the config
|
||||
listEntry.LastUp = vm.LastUp
|
||||
} else { // else we just created the machine AKA last up = created time
|
||||
listEntry.LastUp = vm.Created
|
||||
vm.LastUp = listEntry.LastUp
|
||||
if err := vm.writeConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
listed = append(listed, listEntry)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listed, err
|
||||
}
|
||||
|
||||
func (p *Virtualization) IsValidVMName(name string) (bool, error) {
|
||||
infos, err := getVMInfos()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, vm := range infos {
|
||||
if vm.Name == name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// CheckExclusiveActiveVM checks if there is a VM already running
|
||||
// that does not allow other VMs to be running
|
||||
func (p *Virtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
||||
vms, err := getVMInfos()
|
||||
if err != nil {
|
||||
return false, "", fmt.Errorf("checking VM active: %w", err)
|
||||
}
|
||||
for _, vm := range vms {
|
||||
if vm.Running || vm.Starting {
|
||||
return true, vm.Name, nil
|
||||
}
|
||||
}
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
func (p *Virtualization) Artifact() machine.Artifact {
|
||||
return p.artifact
|
||||
}
|
||||
|
||||
func (p *Virtualization) Compression() machine.ImageCompression {
|
||||
return p.compression
|
||||
}
|
||||
|
||||
func (p *Virtualization) Format() machine.ImageFormat {
|
||||
return p.format
|
||||
}
|
||||
|
||||
// startHostNetworking runs a binary on the host system that allows users
|
||||
// to set up port forwarding to the podman virtual machine
|
||||
func (v *MachineVM) startHostNetworking() (string, machine.APIForwardingState, error) {
|
||||
|
|
@ -1695,86 +1513,6 @@ func (v *MachineVM) editCmdLine(flag string, value string) {
|
|||
}
|
||||
}
|
||||
|
||||
// RemoveAndCleanMachines removes all machine and cleans up any other files associated with podman machine
|
||||
func (p *Virtualization) RemoveAndCleanMachines() error {
|
||||
var (
|
||||
vm machine.VM
|
||||
listResponse []*machine.ListResponse
|
||||
opts machine.ListOptions
|
||||
destroyOptions machine.RemoveOptions
|
||||
)
|
||||
destroyOptions.Force = true
|
||||
var prevErr error
|
||||
|
||||
listResponse, err := p.List(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, mach := range listResponse {
|
||||
vm, err = p.LoadVMByName(mach.Name)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
_, remove, err := vm.Remove(mach.Name, destroyOptions)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
if err := remove(); err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean leftover files in data dir
|
||||
dataDir, err := machine.DataDirPrefix()
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
err := machine.GuardedRemoveAll(dataDir)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
|
||||
// Clean leftover files in conf dir
|
||||
confDir, err := machine.ConfDirPrefix()
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
err := machine.GuardedRemoveAll(confDir)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
return prevErr
|
||||
}
|
||||
|
||||
func (p *Virtualization) VMType() machine.VMType {
|
||||
return vmtype
|
||||
}
|
||||
|
||||
func isRootful() bool {
|
||||
// Rootless is not relevant on Windows. In the future rootless.IsRootless
|
||||
// could be switched to return true on Windows, and other codepaths migrated
|
||||
|
|
|
|||
|
|
@ -0,0 +1,213 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package wsl
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/podman/v4/pkg/machine"
|
||||
"github.com/containers/podman/v4/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type WSLVirtualization struct {
|
||||
machine.Virtualization
|
||||
}
|
||||
|
||||
func VirtualizationProvider() machine.VirtProvider {
|
||||
return &WSLVirtualization{
|
||||
machine.NewVirtualization(machine.None, machine.Xz, machine.Tar),
|
||||
}
|
||||
}
|
||||
|
||||
// NewMachine initializes an instance of a wsl machine
|
||||
func (p *WSLVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||
vm := new(MachineVM)
|
||||
if len(opts.Name) > 0 {
|
||||
vm.Name = opts.Name
|
||||
}
|
||||
configPath, err := getConfigPath(opts.Name)
|
||||
if err != nil {
|
||||
return vm, err
|
||||
}
|
||||
|
||||
vm.ConfigPath = configPath
|
||||
vm.ImagePath = opts.ImagePath
|
||||
vm.RemoteUsername = opts.Username
|
||||
vm.Created = time.Now()
|
||||
vm.LastUp = vm.Created
|
||||
|
||||
// Default is false
|
||||
if opts.UserModeNetworking != nil {
|
||||
vm.UserModeNetworking = *opts.UserModeNetworking
|
||||
}
|
||||
|
||||
// Add a random port for ssh
|
||||
port, err := utils.GetRandomPort()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.Port = port
|
||||
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
// LoadByName reads a json file that describes a known qemu vm
|
||||
// and returns a vm instance
|
||||
func (p *WSLVirtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||
configPath, err := getConfigPath(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vm, err := readAndMigrate(configPath, name)
|
||||
return vm, err
|
||||
}
|
||||
|
||||
// List lists all vm's that use qemu virtualization
|
||||
func (p *WSLVirtualization) List(_ machine.ListOptions) ([]*machine.ListResponse, error) {
|
||||
return GetVMInfos()
|
||||
}
|
||||
|
||||
func GetVMInfos() ([]*machine.ListResponse, error) {
|
||||
vmConfigDir, err := machine.GetConfDir(vmtype)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var listed []*machine.ListResponse
|
||||
|
||||
if err = filepath.WalkDir(vmConfigDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if strings.HasSuffix(d.Name(), ".json") {
|
||||
path := filepath.Join(vmConfigDir, d.Name())
|
||||
vm, err := readAndMigrate(path, strings.TrimSuffix(d.Name(), ".json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listEntry := new(machine.ListResponse)
|
||||
|
||||
listEntry.Name = vm.Name
|
||||
listEntry.Stream = vm.ImageStream
|
||||
listEntry.VMType = "wsl"
|
||||
listEntry.CPUs, _ = getCPUs(vm)
|
||||
listEntry.Memory, _ = getMem(vm)
|
||||
listEntry.DiskSize = getDiskSize(vm)
|
||||
listEntry.RemoteUsername = vm.RemoteUsername
|
||||
listEntry.Port = vm.Port
|
||||
listEntry.IdentityPath = vm.IdentityPath
|
||||
listEntry.Starting = false
|
||||
listEntry.UserModeNetworking = vm.UserModeNetworking
|
||||
|
||||
running := vm.isRunning()
|
||||
listEntry.CreatedAt, listEntry.LastUp, _ = vm.updateTimeStamps(running)
|
||||
listEntry.Running = running
|
||||
|
||||
listed = append(listed, listEntry)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listed, err
|
||||
}
|
||||
|
||||
func (p *WSLVirtualization) IsValidVMName(name string) (bool, error) {
|
||||
infos, err := GetVMInfos()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, vm := range infos {
|
||||
if vm.Name == name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (p *WSLVirtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
// RemoveAndCleanMachines removes all machine and cleans up any other files associated with podman machine
|
||||
func (p *WSLVirtualization) RemoveAndCleanMachines() error {
|
||||
var (
|
||||
vm machine.VM
|
||||
listResponse []*machine.ListResponse
|
||||
opts machine.ListOptions
|
||||
destroyOptions machine.RemoveOptions
|
||||
)
|
||||
destroyOptions.Force = true
|
||||
var prevErr error
|
||||
|
||||
listResponse, err := p.List(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, mach := range listResponse {
|
||||
vm, err = p.LoadVMByName(mach.Name)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
_, remove, err := vm.Remove(mach.Name, destroyOptions)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
if err := remove(); err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean leftover files in data dir
|
||||
dataDir, err := machine.DataDirPrefix()
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
err := machine.GuardedRemoveAll(dataDir)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
|
||||
// Clean leftover files in conf dir
|
||||
confDir, err := machine.ConfDirPrefix()
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
err := machine.GuardedRemoveAll(confDir)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
return prevErr
|
||||
}
|
||||
|
||||
func (p *WSLVirtualization) VMType() machine.VMType {
|
||||
return vmtype
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -22,7 +21,6 @@ import (
|
|||
"github.com/containers/podman/v4/pkg/machine"
|
||||
"github.com/containers/podman/v4/pkg/machine/wsl/wutil"
|
||||
"github.com/containers/podman/v4/pkg/util"
|
||||
"github.com/containers/podman/v4/utils"
|
||||
"github.com/containers/storage/pkg/homedir"
|
||||
"github.com/containers/storage/pkg/ioutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
|
@ -219,24 +217,6 @@ const (
|
|||
rootlessSock = "/run/user/1000/podman/podman.sock"
|
||||
)
|
||||
|
||||
type Virtualization struct {
|
||||
artifact machine.Artifact
|
||||
compression machine.ImageCompression
|
||||
format machine.ImageFormat
|
||||
}
|
||||
|
||||
func (p *Virtualization) Artifact() machine.Artifact {
|
||||
return p.artifact
|
||||
}
|
||||
|
||||
func (p *Virtualization) Compression() machine.ImageCompression {
|
||||
return p.compression
|
||||
}
|
||||
|
||||
func (p *Virtualization) Format() machine.ImageFormat {
|
||||
return p.format
|
||||
}
|
||||
|
||||
type MachineVM struct {
|
||||
// ConfigPath is the path to the configuration file
|
||||
ConfigPath string
|
||||
|
|
@ -268,46 +248,6 @@ func (e *ExitCodeError) Error() string {
|
|||
return fmt.Sprintf("Process failed with exit code: %d", e.code)
|
||||
}
|
||||
|
||||
func GetWSLProvider() machine.VirtProvider {
|
||||
return &Virtualization{
|
||||
artifact: machine.None,
|
||||
compression: machine.Xz,
|
||||
format: machine.Tar,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMachine initializes an instance of a wsl machine
|
||||
func (p *Virtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||
vm := new(MachineVM)
|
||||
if len(opts.Name) > 0 {
|
||||
vm.Name = opts.Name
|
||||
}
|
||||
configPath, err := getConfigPath(opts.Name)
|
||||
if err != nil {
|
||||
return vm, err
|
||||
}
|
||||
|
||||
vm.ConfigPath = configPath
|
||||
vm.ImagePath = opts.ImagePath
|
||||
vm.RemoteUsername = opts.Username
|
||||
vm.Created = time.Now()
|
||||
vm.LastUp = vm.Created
|
||||
|
||||
// Default is false
|
||||
if opts.UserModeNetworking != nil {
|
||||
vm.UserModeNetworking = *opts.UserModeNetworking
|
||||
}
|
||||
|
||||
// Add a random port for ssh
|
||||
port, err := utils.GetRandomPort()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.Port = port
|
||||
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
func getConfigPath(name string) (string, error) {
|
||||
return getConfigPathExt(name, "json")
|
||||
}
|
||||
|
|
@ -321,18 +261,6 @@ func getConfigPathExt(name string, extension string) (string, error) {
|
|||
return filepath.Join(vmConfigDir, fmt.Sprintf("%s.%s", name, extension)), nil
|
||||
}
|
||||
|
||||
// LoadByName reads a json file that describes a known qemu vm
|
||||
// and returns a vm instance
|
||||
func (p *Virtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||
configPath, err := getConfigPath(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vm, err := readAndMigrate(configPath, name)
|
||||
return vm, err
|
||||
}
|
||||
|
||||
// readAndMigrate returns the content of the VM's
|
||||
// configuration file in json
|
||||
func readAndMigrate(configPath string, name string) (*MachineVM, error) {
|
||||
|
|
@ -1512,53 +1440,6 @@ func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error {
|
|||
return cmd.Run()
|
||||
}
|
||||
|
||||
// List lists all vm's that use qemu virtualization
|
||||
func (p *Virtualization) List(_ machine.ListOptions) ([]*machine.ListResponse, error) {
|
||||
return GetVMInfos()
|
||||
}
|
||||
|
||||
func GetVMInfos() ([]*machine.ListResponse, error) {
|
||||
vmConfigDir, err := machine.GetConfDir(vmtype)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var listed []*machine.ListResponse
|
||||
|
||||
if err = filepath.WalkDir(vmConfigDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if strings.HasSuffix(d.Name(), ".json") {
|
||||
path := filepath.Join(vmConfigDir, d.Name())
|
||||
vm, err := readAndMigrate(path, strings.TrimSuffix(d.Name(), ".json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listEntry := new(machine.ListResponse)
|
||||
|
||||
listEntry.Name = vm.Name
|
||||
listEntry.Stream = vm.ImageStream
|
||||
listEntry.VMType = "wsl"
|
||||
listEntry.CPUs, _ = getCPUs(vm)
|
||||
listEntry.Memory, _ = getMem(vm)
|
||||
listEntry.DiskSize = getDiskSize(vm)
|
||||
listEntry.RemoteUsername = vm.RemoteUsername
|
||||
listEntry.Port = vm.Port
|
||||
listEntry.IdentityPath = vm.IdentityPath
|
||||
listEntry.Starting = false
|
||||
listEntry.UserModeNetworking = vm.UserModeNetworking
|
||||
|
||||
running := vm.isRunning()
|
||||
listEntry.CreatedAt, listEntry.LastUp, _ = vm.updateTimeStamps(running)
|
||||
listEntry.Running = running
|
||||
|
||||
listed = append(listed, listEntry)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listed, err
|
||||
}
|
||||
|
||||
func (vm *MachineVM) updateTimeStamps(updateLast bool) (time.Time, time.Time, error) {
|
||||
var err error
|
||||
if updateLast {
|
||||
|
|
@ -1643,23 +1524,6 @@ func getMem(vm *MachineVM) (uint64, error) {
|
|||
return total - available, err
|
||||
}
|
||||
|
||||
func (p *Virtualization) IsValidVMName(name string) (bool, error) {
|
||||
infos, err := GetVMInfos()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, vm := range infos {
|
||||
if vm.Name == name {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (p *Virtualization) CheckExclusiveActiveVM() (bool, string, error) {
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
func (v *MachineVM) setRootful(rootful bool) error {
|
||||
changeCon, err := machine.AnyConnectionDefault(v.Name, v.Name+"-root")
|
||||
if err != nil {
|
||||
|
|
@ -1716,83 +1580,3 @@ func (v *MachineVM) getResources() (resources machine.ResourceConfig) {
|
|||
resources.DiskSize = getDiskSize(v)
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveAndCleanMachines removes all machine and cleans up any other files associated with podman machine
|
||||
func (p *Virtualization) RemoveAndCleanMachines() error {
|
||||
var (
|
||||
vm machine.VM
|
||||
listResponse []*machine.ListResponse
|
||||
opts machine.ListOptions
|
||||
destroyOptions machine.RemoveOptions
|
||||
)
|
||||
destroyOptions.Force = true
|
||||
var prevErr error
|
||||
|
||||
listResponse, err := p.List(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, mach := range listResponse {
|
||||
vm, err = p.LoadVMByName(mach.Name)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
_, remove, err := vm.Remove(mach.Name, destroyOptions)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
if err := remove(); err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean leftover files in data dir
|
||||
dataDir, err := machine.DataDirPrefix()
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
err := machine.GuardedRemoveAll(dataDir)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
|
||||
// Clean leftover files in conf dir
|
||||
confDir, err := machine.ConfDirPrefix()
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
} else {
|
||||
err := machine.GuardedRemoveAll(confDir)
|
||||
if err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
prevErr = err
|
||||
}
|
||||
}
|
||||
return prevErr
|
||||
}
|
||||
|
||||
func (p *Virtualization) VMType() machine.VMType {
|
||||
return vmtype
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue