mirror of
https://github.com/containers/podman.git
synced 2025-06-20 17:13:43 +08:00
Podman 5 machine config file - Step 1
The following PR is the very first step in what will a series of steps to apply a "common" machine configuration file to all providers. Function names, method names, struct names, and field names are all up for debate. The purpose of this PR is to offer a glimpse at the direction we intend to take. This PR also contains temporary structs (i.e. aThing) that are not exported. These are merely placeholders. The configuration work in this PR is also unused of yet. But the code is compiled. Once merged, we can begin the next step of development. [NO NEW TESTS NEEDED] Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v4/pkg/errorhandling"
|
"github.com/containers/podman/v4/pkg/errorhandling"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
"github.com/containers/podman/v4/pkg/machine/provider"
|
"github.com/containers/podman/v4/pkg/machine/provider"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -184,7 +185,7 @@ func composeDockerHost() (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("inspecting machine: %w", err)
|
return "", fmt.Errorf("inspecting machine: %w", err)
|
||||||
}
|
}
|
||||||
if info.State != machine.Running {
|
if info.State != define.Running {
|
||||||
return "", fmt.Errorf("machine %s is not running but in state %s", item.Name, info.State)
|
return "", fmt.Errorf("machine %s is not running but in state %s", item.Name, info.State)
|
||||||
}
|
}
|
||||||
if machineProvider.VMType() == machine.WSLVirt {
|
if machineProvider.VMType() == machine.WSLVirt {
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/containers/podman/v4/pkg/machine/compression"
|
"github.com/containers/podman/v4/pkg/machine/compression"
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
|
||||||
vfConfig "github.com/crc-org/vfkit/pkg/config"
|
vfConfig "github.com/crc-org/vfkit/pkg/config"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@ -76,10 +77,10 @@ func (v AppleHVVirtualization) List(opts machine.ListOptions) ([]*machine.ListRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, mm := range mms {
|
for _, mm := range mms {
|
||||||
vmState, err := mm.Vfkit.state()
|
vmState, err := mm.Vfkit.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, unix.ECONNREFUSED) {
|
if errors.Is(err, unix.ECONNREFUSED) {
|
||||||
vmState = machine.Stopped
|
vmState = define.Stopped
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -89,8 +90,8 @@ func (v AppleHVVirtualization) List(opts machine.ListOptions) ([]*machine.ListRe
|
|||||||
Name: mm.Name,
|
Name: mm.Name,
|
||||||
CreatedAt: mm.Created,
|
CreatedAt: mm.Created,
|
||||||
LastUp: mm.LastUp,
|
LastUp: mm.LastUp,
|
||||||
Running: vmState == machine.Running,
|
Running: vmState == define.Running,
|
||||||
Starting: vmState == machine.Starting,
|
Starting: vmState == define.Starting,
|
||||||
Stream: mm.ImageStream,
|
Stream: mm.ImageStream,
|
||||||
VMType: machine.AppleHvVirt.String(),
|
VMType: machine.AppleHvVirt.String(),
|
||||||
CPUs: mm.CPUs,
|
CPUs: mm.CPUs,
|
||||||
@ -140,7 +141,7 @@ func (v AppleHVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM,
|
|||||||
// Set creation time
|
// Set creation time
|
||||||
m.Created = time.Now()
|
m.Created = time.Now()
|
||||||
|
|
||||||
m.ResourceConfig = machine.ResourceConfig{
|
m.ResourceConfig = vmconfigs.ResourceConfig{
|
||||||
CPUs: opts.CPUS,
|
CPUs: opts.CPUS,
|
||||||
DiskSize: opts.DiskSize,
|
DiskSize: opts.DiskSize,
|
||||||
// Diskpath will be needed
|
// Diskpath will be needed
|
||||||
|
@ -21,7 +21,10 @@ import (
|
|||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
|
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/applehv/vfkit"
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/sockets"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
|
||||||
"github.com/containers/podman/v4/pkg/strongunits"
|
"github.com/containers/podman/v4/pkg/strongunits"
|
||||||
"github.com/containers/podman/v4/pkg/util"
|
"github.com/containers/podman/v4/pkg/util"
|
||||||
"github.com/containers/podman/v4/utils"
|
"github.com/containers/podman/v4/utils"
|
||||||
@ -43,14 +46,6 @@ const (
|
|||||||
apiUpTimeout = 20 * time.Second
|
apiUpTimeout = 20 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// VfkitHelper describes the use of vfkit: cmdline and endpoint
|
|
||||||
type VfkitHelper struct {
|
|
||||||
LogLevel logrus.Level
|
|
||||||
Endpoint string
|
|
||||||
VfkitBinaryPath *define.VMFile
|
|
||||||
VirtualMachine *vfConfig.VirtualMachine
|
|
||||||
}
|
|
||||||
|
|
||||||
// appleHVReadyUnit is a unit file that sets up the virtual serial device
|
// appleHVReadyUnit is a unit file that sets up the virtual serial device
|
||||||
// where when the VM is done configuring, it will send an ack
|
// where when the VM is done configuring, it will send an ack
|
||||||
// so a listening host knows it can begin interacting with it
|
// so a listening host knows it can begin interacting with it
|
||||||
@ -71,19 +66,19 @@ type MacMachine struct {
|
|||||||
// ConfigPath is the fully qualified path to the configuration file
|
// ConfigPath is the fully qualified path to the configuration file
|
||||||
ConfigPath define.VMFile
|
ConfigPath define.VMFile
|
||||||
// HostUser contains info about host user
|
// HostUser contains info about host user
|
||||||
machine.HostUser
|
vmconfigs.HostUser
|
||||||
// ImageConfig describes the bootable image
|
// ImageConfig describes the bootable image
|
||||||
machine.ImageConfig
|
machine.ImageConfig
|
||||||
// Mounts is the list of remote filesystems to mount
|
// Mounts is the list of remote filesystems to mount
|
||||||
Mounts []machine.Mount
|
Mounts []vmconfigs.Mount
|
||||||
// Name of VM
|
// Name of VM
|
||||||
Name string
|
Name string
|
||||||
// ReadySocket tells host when vm is booted
|
// ReadySocket tells host when vm is booted
|
||||||
ReadySocket define.VMFile
|
ReadySocket define.VMFile
|
||||||
// ResourceConfig is physical attrs of the VM
|
// ResourceConfig is physical attrs of the VM
|
||||||
machine.ResourceConfig
|
vmconfigs.ResourceConfig
|
||||||
// SSHConfig for accessing the remote vm
|
// SSHConfig for accessing the remote vm
|
||||||
machine.SSHConfig
|
vmconfigs.SSHConfig
|
||||||
// Starting tells us whether the machine is running or if we have just dialed it to start it
|
// Starting tells us whether the machine is running or if we have just dialed it to start it
|
||||||
Starting bool
|
Starting bool
|
||||||
// Created contains the original created time instead of querying the file mod time
|
// Created contains the original created time instead of querying the file mod time
|
||||||
@ -91,7 +86,7 @@ type MacMachine struct {
|
|||||||
// LastUp contains the last recorded uptime
|
// LastUp contains the last recorded uptime
|
||||||
LastUp time.Time
|
LastUp time.Time
|
||||||
// The VFKit endpoint where we can interact with the VM
|
// The VFKit endpoint where we can interact with the VM
|
||||||
Vfkit VfkitHelper
|
Vfkit vfkit.VfkitHelper
|
||||||
LogPath define.VMFile
|
LogPath define.VMFile
|
||||||
GvProxyPid define.VMFile
|
GvProxyPid define.VMFile
|
||||||
GvProxySock define.VMFile
|
GvProxySock define.VMFile
|
||||||
@ -108,7 +103,7 @@ func (m *MacMachine) setGVProxyInfo(runtimeDir string) error {
|
|||||||
}
|
}
|
||||||
m.GvProxyPid = *gvProxyPid
|
m.GvProxyPid = *gvProxyPid
|
||||||
|
|
||||||
return machine.SetSocket(&m.GvProxySock, filepath.Join(runtimeDir, "gvproxy.sock"), nil)
|
return sockets.SetSocket(&m.GvProxySock, filepath.Join(runtimeDir, "gvproxy.sock"), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setVfkitInfo stores the default devices, sets the vfkit endpoint, and
|
// setVfkitInfo stores the default devices, sets the vfkit endpoint, and
|
||||||
@ -138,7 +133,7 @@ func (m *MacMachine) setVfkitInfo(cfg *config.Config, readySocket define.VMFile)
|
|||||||
// addMountsToVM converts the volumes passed through the CLI to virtio-fs mounts
|
// addMountsToVM converts the volumes passed through the CLI to virtio-fs mounts
|
||||||
// and adds them to the machine
|
// and adds them to the machine
|
||||||
func (m *MacMachine) addMountsToVM(opts machine.InitOptions, virtiofsMnts *[]machine.VirtIoFs) error {
|
func (m *MacMachine) addMountsToVM(opts machine.InitOptions, virtiofsMnts *[]machine.VirtIoFs) error {
|
||||||
var mounts []machine.Mount
|
var mounts []vmconfigs.Mount
|
||||||
for _, volume := range opts.Volumes {
|
for _, volume := range opts.Volumes {
|
||||||
source, target, _, readOnly, err := machine.ParseVolumeFromPath(volume)
|
source, target, _, readOnly, err := machine.ParseVolumeFromPath(volume)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -202,7 +197,7 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := machine.SetSocket(&m.ReadySocket, machine.ReadySocketPath(runtimeDir, m.Name), nil); err != nil {
|
if err := sockets.SetSocket(&m.ReadySocket, sockets.ReadySocketPath(runtimeDir, m.Name), nil); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +300,7 @@ func (m *MacMachine) removeSystemConnections() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MacMachine) Inspect() (*machine.InspectInfo, error) {
|
func (m *MacMachine) Inspect() (*machine.InspectInfo, error) {
|
||||||
vmState, err := m.Vfkit.state()
|
vmState, err := m.Vfkit.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -329,7 +324,7 @@ func (m *MacMachine) Inspect() (*machine.InspectInfo, error) {
|
|||||||
},
|
},
|
||||||
LastUp: m.LastUp,
|
LastUp: m.LastUp,
|
||||||
Name: m.Name,
|
Name: m.Name,
|
||||||
Resources: machine.ResourceConfig{
|
Resources: vmconfigs.ResourceConfig{
|
||||||
CPUs: m.CPUs,
|
CPUs: m.CPUs,
|
||||||
DiskSize: m.DiskSize,
|
DiskSize: m.DiskSize,
|
||||||
Memory: m.Memory,
|
Memory: m.Memory,
|
||||||
@ -367,16 +362,16 @@ func (m *MacMachine) Remove(name string, opts machine.RemoveOptions) (string, fu
|
|||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
vmState, err := m.Vfkit.state()
|
vmState, err := m.Vfkit.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if vmState == machine.Running {
|
if vmState == define.Running {
|
||||||
if !opts.Force {
|
if !opts.Force {
|
||||||
return "", nil, &machine.ErrVMRunningCannotDestroyed{Name: m.Name}
|
return "", nil, &machine.ErrVMRunningCannotDestroyed{Name: m.Name}
|
||||||
}
|
}
|
||||||
if err := m.Vfkit.stop(true, true); err != nil {
|
if err := m.Vfkit.Stop(true, true); err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -430,7 +425,7 @@ func (m *MacMachine) Set(name string, opts machine.SetOptions) ([]error, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if vmState != machine.Stopped {
|
if vmState != define.Stopped {
|
||||||
return nil, machine.ErrWrongState
|
return nil, machine.ErrWrongState
|
||||||
}
|
}
|
||||||
if cpus := opts.CPUs; cpus != nil {
|
if cpus := opts.CPUs; cpus != nil {
|
||||||
@ -473,7 +468,7 @@ func (m *MacMachine) SSH(name string, opts machine.SSHOptions) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if st != machine.Running {
|
if st != define.Running {
|
||||||
return fmt.Errorf("vm %q is not running", m.Name)
|
return fmt.Errorf("vm %q is not running", m.Name)
|
||||||
}
|
}
|
||||||
username := opts.Username
|
username := opts.Username
|
||||||
@ -561,7 +556,7 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if st == machine.Running {
|
if st == define.Running {
|
||||||
return machine.ErrVMAlreadyRunning
|
return machine.ErrVMAlreadyRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,7 +659,7 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error {
|
|||||||
|
|
||||||
logrus.Debug("waiting for ready notification")
|
logrus.Debug("waiting for ready notification")
|
||||||
readyChan := make(chan error)
|
readyChan := make(chan error)
|
||||||
go machine.ListenAndWaitOnSocket(readyChan, readyListen)
|
go sockets.ListenAndWaitOnSocket(readyChan, readyListen)
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -715,8 +710,8 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MacMachine) State(_ bool) (machine.Status, error) {
|
func (m *MacMachine) State(_ bool) (define.Status, error) {
|
||||||
vmStatus, err := m.Vfkit.state()
|
vmStatus, err := m.Vfkit.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -732,7 +727,7 @@ func (m *MacMachine) Stop(name string, opts machine.StopOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if vmState != machine.Running {
|
if vmState != define.Running {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,7 +737,7 @@ func (m *MacMachine) Stop(name string, opts machine.StopOptions) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return m.Vfkit.stop(false, true)
|
return m.Vfkit.Stop(false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getVMConfigPath is a simple wrapper for getting the fully-qualified
|
// getVMConfigPath is a simple wrapper for getting the fully-qualified
|
||||||
@ -845,7 +840,7 @@ func getVMInfos() ([]*machine.ListResponse, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
listEntry.Running = vmState == machine.Running
|
listEntry.Running = vmState == define.Running
|
||||||
listEntry.LastUp = vm.LastUp
|
listEntry.LastUp = vm.LastUp
|
||||||
|
|
||||||
listed = append(listed, listEntry)
|
listed = append(listed, listEntry)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//go:build darwin
|
//go:build darwin
|
||||||
// +build darwin
|
// +build darwin
|
||||||
|
|
||||||
package applehv
|
package vfkit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -12,14 +12,13 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
"github.com/crc-org/vfkit/pkg/rest/define"
|
"github.com/crc-org/vfkit/pkg/config"
|
||||||
|
rest "github.com/crc-org/vfkit/pkg/rest/define"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Endpoint string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
inspect = "/vm/inspect"
|
inspect = "/vm/inspect"
|
||||||
state = "/vm/state"
|
state = "/vm/state"
|
||||||
@ -45,8 +44,8 @@ func (vf *VfkitHelper) post(endpoint string, payload io.Reader) (*http.Response,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getRawState asks vfkit for virtual machine state unmodified (see state())
|
// getRawState asks vfkit for virtual machine state unmodified (see state())
|
||||||
func (vf *VfkitHelper) getRawState() (machine.Status, error) {
|
func (vf *VfkitHelper) getRawState() (define.Status, error) {
|
||||||
var response define.VMState
|
var response rest.VMState
|
||||||
endPoint := vf.Endpoint + state
|
endPoint := vf.Endpoint + state
|
||||||
serverResponse, err := vf.get(endPoint, nil)
|
serverResponse, err := vf.get(endPoint, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -60,25 +59,24 @@ func (vf *VfkitHelper) getRawState() (machine.Status, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return ToMachineStatus(response.State)
|
return ToMachineStatus(response.State)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// state asks vfkit for the virtual machine state. in case the vfkit
|
// state asks vfkit for the virtual machine state. in case the vfkit
|
||||||
// service is not responding, we assume the service is not running
|
// service is not responding, we assume the service is not running
|
||||||
// and return a stopped status
|
// and return a stopped status
|
||||||
func (vf *VfkitHelper) state() (machine.Status, error) {
|
func (vf *VfkitHelper) State() (define.Status, error) {
|
||||||
vmState, err := vf.getRawState()
|
vmState, err := vf.getRawState()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return vmState, err
|
return vmState, err
|
||||||
}
|
}
|
||||||
if errors.Is(err, unix.ECONNREFUSED) {
|
if errors.Is(err, unix.ECONNREFUSED) {
|
||||||
return machine.Stopped, nil
|
return define.Stopped, nil
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vf *VfkitHelper) stateChange(newState define.StateChange) error {
|
func (vf *VfkitHelper) stateChange(newState rest.StateChange) error {
|
||||||
b, err := json.Marshal(define.VMState{State: string(newState)})
|
b, err := json.Marshal(rest.VMState{State: string(newState)})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -87,15 +85,15 @@ func (vf *VfkitHelper) stateChange(newState define.StateChange) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vf *VfkitHelper) stop(force, wait bool) error {
|
func (vf *VfkitHelper) Stop(force, wait bool) error {
|
||||||
waitDuration := time.Millisecond * 10
|
waitDuration := time.Millisecond * 10
|
||||||
// TODO Add ability to wait until stopped
|
// TODO Add ability to wait until stopped
|
||||||
if force {
|
if force {
|
||||||
if err := vf.stateChange(define.HardStop); err != nil {
|
if err := vf.stateChange(rest.HardStop); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := vf.stateChange(define.Stop); err != nil {
|
if err := vf.stateChange(rest.Stop); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,3 +114,11 @@ func (vf *VfkitHelper) stop(force, wait bool) error {
|
|||||||
}
|
}
|
||||||
return waitErr
|
return waitErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VfkitHelper describes the use of vfkit: cmdline and endpoint
|
||||||
|
type VfkitHelper struct {
|
||||||
|
LogLevel logrus.Level
|
||||||
|
Endpoint string
|
||||||
|
VfkitBinaryPath *define.VMFile
|
||||||
|
VirtualMachine *config.VirtualMachine
|
||||||
|
}
|
@ -1,15 +1,17 @@
|
|||||||
//go:build darwin
|
//go:build darwin
|
||||||
// +build darwin
|
// +build darwin
|
||||||
|
|
||||||
package applehv
|
package vfkit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Endpoint string
|
||||||
|
|
||||||
// VZMachineState is what the restful service in vfkit will return
|
// VZMachineState is what the restful service in vfkit will return
|
||||||
type VZMachineState string
|
type VZMachineState string
|
||||||
|
|
||||||
@ -26,14 +28,14 @@ const (
|
|||||||
VZMachineStateStopping VZMachineState = "VirtualMachineStateStopping"
|
VZMachineStateStopping VZMachineState = "VirtualMachineStateStopping"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ToMachineStatus(val string) (machine.Status, error) {
|
func ToMachineStatus(val string) (define.Status, error) {
|
||||||
switch val {
|
switch val {
|
||||||
case string(VZMachineStateRunning), string(VZMachineStatePausing), string(VZMachineStateResuming), string(VZMachineStateStopping), string(VZMachineStatePaused):
|
case string(VZMachineStateRunning), string(VZMachineStatePausing), string(VZMachineStateResuming), string(VZMachineStateStopping), string(VZMachineStatePaused):
|
||||||
return machine.Running, nil
|
return define.Running, nil
|
||||||
case string(VZMachineStateStopped):
|
case string(VZMachineStateStopped):
|
||||||
return machine.Stopped, nil
|
return define.Stopped, nil
|
||||||
case string(VZMachineStateStarting):
|
case string(VZMachineStateStarting):
|
||||||
return machine.Starting, nil
|
return define.Starting, nil
|
||||||
case string(VZMachineStateError):
|
case string(VZMachineStateError):
|
||||||
return "", errors.New("machine is in error state")
|
return "", errors.New("machine is in error state")
|
||||||
}
|
}
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/containers/common/pkg/machine"
|
"github.com/containers/common/pkg/machine"
|
||||||
"github.com/containers/podman/v4/pkg/machine/compression"
|
"github.com/containers/podman/v4/pkg/machine/compression"
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
|
||||||
"github.com/containers/storage/pkg/homedir"
|
"github.com/containers/storage/pkg/homedir"
|
||||||
"github.com/containers/storage/pkg/lockfile"
|
"github.com/containers/storage/pkg/lockfile"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -43,17 +44,7 @@ type InitOptions struct {
|
|||||||
USBs []string
|
USBs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Status = string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Running indicates the qemu vm is running.
|
|
||||||
Running Status = "running"
|
|
||||||
// Stopped indicates the vm has stopped.
|
|
||||||
Stopped Status = "stopped"
|
|
||||||
// Starting indicated the vm is in the process of starting
|
|
||||||
Starting Status = "starting"
|
|
||||||
// Unknown means the state is not known
|
|
||||||
Unknown Status = "unknown"
|
|
||||||
DefaultMachineName string = "podman-machine-default"
|
DefaultMachineName string = "podman-machine-default"
|
||||||
apiUpTimeout = 20 * time.Second
|
apiUpTimeout = 20 * time.Second
|
||||||
)
|
)
|
||||||
@ -139,7 +130,7 @@ type VM interface {
|
|||||||
Set(name string, opts SetOptions) ([]error, error)
|
Set(name string, opts 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) (Status, error)
|
State(bypass bool) (define.Status, error)
|
||||||
Stop(name string, opts StopOptions) error
|
Stop(name string, opts StopOptions) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,9 +164,9 @@ type InspectInfo struct {
|
|||||||
Image ImageConfig
|
Image ImageConfig
|
||||||
LastUp time.Time
|
LastUp time.Time
|
||||||
Name string
|
Name string
|
||||||
Resources ResourceConfig
|
Resources vmconfigs.ResourceConfig
|
||||||
SSHConfig SSHConfig
|
SSHConfig vmconfigs.SSHConfig
|
||||||
State Status
|
State define.Status
|
||||||
UserModeNetworking bool
|
UserModeNetworking bool
|
||||||
Rootful bool
|
Rootful bool
|
||||||
}
|
}
|
||||||
@ -274,33 +265,6 @@ func ConfDirPrefix() (string, error) {
|
|||||||
return confDir, nil
|
return confDir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type USBConfig struct {
|
|
||||||
Bus string
|
|
||||||
DevNumber string
|
|
||||||
Vendor int
|
|
||||||
Product int
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceConfig describes physical attributes of the machine
|
|
||||||
type ResourceConfig struct {
|
|
||||||
// CPUs to be assigned to the VM
|
|
||||||
CPUs uint64
|
|
||||||
// Disk size in gigabytes assigned to the vm
|
|
||||||
DiskSize uint64
|
|
||||||
// Memory in megabytes assigned to the vm
|
|
||||||
Memory uint64
|
|
||||||
// Usbs
|
|
||||||
USBs []USBConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
type Mount struct {
|
|
||||||
ReadOnly bool
|
|
||||||
Source string
|
|
||||||
Tag string
|
|
||||||
Target string
|
|
||||||
Type string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageConfig describes the bootable image for the VM
|
// ImageConfig describes the bootable image for the VM
|
||||||
type ImageConfig struct {
|
type ImageConfig struct {
|
||||||
// IgnitionFile is the path to the filesystem where the
|
// IgnitionFile is the path to the filesystem where the
|
||||||
@ -312,26 +276,6 @@ type ImageConfig struct {
|
|||||||
ImagePath define.VMFile `json:"ImagePath"`
|
ImagePath define.VMFile `json:"ImagePath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HostUser describes the host user
|
|
||||||
type HostUser struct {
|
|
||||||
// Whether this machine should run in a rootful or rootless manner
|
|
||||||
Rootful bool
|
|
||||||
// UID is the numerical id of the user that called machine
|
|
||||||
UID int
|
|
||||||
// Whether one of these fields has changed and actions should be taken
|
|
||||||
Modified bool `json:"HostUserModified"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SSHConfig contains remote access information for SSH
|
|
||||||
type SSHConfig struct {
|
|
||||||
// IdentityPath is the fq path to the ssh priv key
|
|
||||||
IdentityPath string
|
|
||||||
// SSH port for user networking
|
|
||||||
Port int
|
|
||||||
// RemoteUsername of the vm user
|
|
||||||
RemoteUsername string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConnectionConfig contains connections like sockets, etc.
|
// ConnectionConfig contains connections like sockets, etc.
|
||||||
type ConnectionConfig struct {
|
type ConnectionConfig struct {
|
||||||
// PodmanSocket is the exported podman service socket
|
// PodmanSocket is the exported podman service socket
|
||||||
|
3
pkg/machine/define/config.go
Normal file
3
pkg/machine/define/config.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package define
|
||||||
|
|
||||||
|
const UserCertsTargetPath = "/etc/containers/certs.d"
|
15
pkg/machine/define/state.go
Normal file
15
pkg/machine/define/state.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package define
|
||||||
|
|
||||||
|
type Status = string
|
||||||
|
|
||||||
|
// Running indicates the qemu vm is running.
|
||||||
|
const Running Status = "running"
|
||||||
|
|
||||||
|
// Stopped indicates the vm has stopped.
|
||||||
|
const Stopped Status = "stopped"
|
||||||
|
|
||||||
|
// Starting indicated the vm is in the process of starting
|
||||||
|
const Starting Status = "starting"
|
||||||
|
|
||||||
|
// Unknown means the state is not known
|
||||||
|
const Unknown Status = "unknown"
|
@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
"github.com/containers/podman/v4/utils"
|
"github.com/containers/podman/v4/utils"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
@ -108,7 +109,7 @@ var _ = Describe("podman machine init", func() {
|
|||||||
Expect(ec).To(BeZero())
|
Expect(ec).To(BeZero())
|
||||||
Expect(inspectBefore).ToNot(BeEmpty())
|
Expect(inspectBefore).ToNot(BeEmpty())
|
||||||
Expect(inspectAfter).ToNot(BeEmpty())
|
Expect(inspectAfter).ToNot(BeEmpty())
|
||||||
Expect(inspectAfter[0].State).To(Equal(machine.Running))
|
Expect(inspectAfter[0].State).To(Equal(define.Running))
|
||||||
|
|
||||||
if isWSL() { // WSL does not use FCOS
|
if isWSL() { // WSL does not use FCOS
|
||||||
return
|
return
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package e2e_test
|
package e2e_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
. "github.com/onsi/gomega/gexec"
|
. "github.com/onsi/gomega/gexec"
|
||||||
@ -32,7 +32,7 @@ var _ = Describe("podman machine start", func() {
|
|||||||
info, ec, err := mb.toQemuInspectInfo()
|
info, ec, err := mb.toQemuInspectInfo()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(ec).To(BeZero())
|
Expect(ec).To(BeZero())
|
||||||
Expect(info[0].State).To(Equal(machine.Running))
|
Expect(info[0].State).To(Equal(define.Running))
|
||||||
|
|
||||||
stop := new(stopMachine)
|
stop := new(stopMachine)
|
||||||
stopSession, err := mb.setCmd(stop).run()
|
stopSession, err := mb.setCmd(stop).run()
|
||||||
@ -77,7 +77,7 @@ var _ = Describe("podman machine start", func() {
|
|||||||
info, ec, err := mb.toQemuInspectInfo()
|
info, ec, err := mb.toQemuInspectInfo()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(ec).To(BeZero())
|
Expect(ec).To(BeZero())
|
||||||
Expect(info[0].State).To(Equal(machine.Running))
|
Expect(info[0].State).To(Equal(define.Running))
|
||||||
|
|
||||||
startSession, err = mb.setCmd(s).run()
|
startSession, err = mb.setCmd(s).run()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
@ -286,14 +286,14 @@ func handlePrevError(e, prevErr error) error {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func stateConversion(s hypervctl.EnabledState) (machine.Status, error) {
|
func stateConversion(s hypervctl.EnabledState) (define.Status, error) {
|
||||||
switch s {
|
switch s {
|
||||||
case hypervctl.Enabled:
|
case hypervctl.Enabled:
|
||||||
return machine.Running, nil
|
return define.Running, nil
|
||||||
case hypervctl.Disabled:
|
case hypervctl.Disabled:
|
||||||
return machine.Stopped, nil
|
return define.Stopped, nil
|
||||||
case hypervctl.Starting:
|
case hypervctl.Starting:
|
||||||
return machine.Starting, nil
|
return define.Starting, nil
|
||||||
}
|
}
|
||||||
return machine.Unknown, fmt.Errorf("unknown state: %q", s.String())
|
return define.Unknown, fmt.Errorf("unknown state: %q", s.String())
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ import (
|
|||||||
"github.com/containers/libhvee/pkg/hypervctl"
|
"github.com/containers/libhvee/pkg/hypervctl"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/hyperv/vsock"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
|
||||||
"github.com/containers/podman/v4/pkg/strongunits"
|
"github.com/containers/podman/v4/pkg/strongunits"
|
||||||
"github.com/containers/podman/v4/pkg/util"
|
"github.com/containers/podman/v4/pkg/util"
|
||||||
"github.com/containers/podman/v4/utils"
|
"github.com/containers/podman/v4/utils"
|
||||||
@ -99,21 +101,21 @@ type HyperVMachine struct {
|
|||||||
// ConfigPath is the fully qualified path to the configuration file
|
// ConfigPath is the fully qualified path to the configuration file
|
||||||
ConfigPath define.VMFile
|
ConfigPath define.VMFile
|
||||||
// HostUser contains info about host user
|
// HostUser contains info about host user
|
||||||
machine.HostUser
|
vmconfigs.HostUser
|
||||||
// ImageConfig describes the bootable image
|
// ImageConfig describes the bootable image
|
||||||
machine.ImageConfig
|
machine.ImageConfig
|
||||||
// Mounts is the list of remote filesystems to mount
|
// Mounts is the list of remote filesystems to mount
|
||||||
Mounts []machine.Mount
|
Mounts []vmconfigs.Mount
|
||||||
// Name of VM
|
// Name of VM
|
||||||
Name string
|
Name string
|
||||||
// NetworkVSock is for the user networking
|
// NetworkVSock is for the user networking
|
||||||
NetworkHVSock HVSockRegistryEntry
|
NetworkHVSock vsock.HVSockRegistryEntry
|
||||||
// ReadySocket tells host when vm is booted
|
// ReadySocket tells host when vm is booted
|
||||||
ReadyHVSock HVSockRegistryEntry
|
ReadyHVSock vsock.HVSockRegistryEntry
|
||||||
// ResourceConfig is physical attrs of the VM
|
// ResourceConfig is physical attrs of the VM
|
||||||
machine.ResourceConfig
|
vmconfigs.ResourceConfig
|
||||||
// SSHConfig for accessing the remote vm
|
// SSHConfig for accessing the remote vm
|
||||||
machine.SSHConfig
|
vmconfigs.SSHConfig
|
||||||
// Starting tells us whether the machine is running or if we have just dialed it to start it
|
// Starting tells us whether the machine is running or if we have just dialed it to start it
|
||||||
Starting bool
|
Starting bool
|
||||||
// Created contains the original created time instead of querying the file mod time
|
// Created contains the original created time instead of querying the file mod time
|
||||||
@ -132,11 +134,11 @@ type HyperVMachine struct {
|
|||||||
// addNetworkAndReadySocketsToRegistry adds the Network and Ready sockets to the
|
// addNetworkAndReadySocketsToRegistry adds the Network and Ready sockets to the
|
||||||
// Windows registry
|
// Windows registry
|
||||||
func (m *HyperVMachine) addNetworkAndReadySocketsToRegistry() error {
|
func (m *HyperVMachine) addNetworkAndReadySocketsToRegistry() error {
|
||||||
networkHVSock, err := NewHVSockRegistryEntry(m.Name, Network)
|
networkHVSock, err := vsock.NewHVSockRegistryEntry(m.Name, vsock.Network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
eventHVSocket, err := NewHVSockRegistryEntry(m.Name, Events)
|
eventHVSocket, err := vsock.NewHVSockRegistryEntry(m.Name, vsock.Events)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -185,7 +187,7 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
|
|||||||
// around to those, would be another : after that.
|
// around to those, would be another : after that.
|
||||||
// TODO: Need to support options here
|
// TODO: Need to support options here
|
||||||
for _, mount := range opts.Volumes {
|
for _, mount := range opts.Volumes {
|
||||||
newMount := machine.Mount{}
|
newMount := vmconfigs.Mount{}
|
||||||
|
|
||||||
splitMount := strings.Split(mount, ":")
|
splitMount := strings.Split(mount, ":")
|
||||||
if len(splitMount) < 3 {
|
if len(splitMount) < 3 {
|
||||||
@ -242,7 +244,7 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
|
|||||||
callbackFuncs.Add(m.removeSSHKeys)
|
callbackFuncs.Add(m.removeSSHKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.ResourceConfig = machine.ResourceConfig{
|
m.ResourceConfig = vmconfigs.ResourceConfig{
|
||||||
CPUs: opts.CPUS,
|
CPUs: opts.CPUS,
|
||||||
DiskSize: opts.DiskSize,
|
DiskSize: opts.DiskSize,
|
||||||
Memory: opts.Memory,
|
Memory: opts.Memory,
|
||||||
@ -367,7 +369,7 @@ func (m *HyperVMachine) Inspect() (*machine.InspectInfo, error) {
|
|||||||
},
|
},
|
||||||
LastUp: m.LastUp,
|
LastUp: m.LastUp,
|
||||||
Name: m.Name,
|
Name: m.Name,
|
||||||
Resources: machine.ResourceConfig{
|
Resources: vmconfigs.ResourceConfig{
|
||||||
CPUs: uint64(cfg.Hardware.CPUs),
|
CPUs: uint64(cfg.Hardware.CPUs),
|
||||||
DiskSize: 0,
|
DiskSize: 0,
|
||||||
Memory: cfg.Hardware.Memory,
|
Memory: cfg.Hardware.Memory,
|
||||||
@ -543,7 +545,7 @@ func (m *HyperVMachine) SSH(name string, opts machine.SSHOptions) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if state != machine.Running {
|
if state != define.Running {
|
||||||
return fmt.Errorf("vm %q is not running", m.Name)
|
return fmt.Errorf("vm %q is not running", m.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,21 +616,21 @@ func (m *HyperVMachine) Start(name string, opts machine.StartOptions) error {
|
|||||||
return m.writeConfig()
|
return m.writeConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *HyperVMachine) State(_ bool) (machine.Status, error) {
|
func (m *HyperVMachine) State(_ bool) (define.Status, error) {
|
||||||
vmm := hypervctl.NewVirtualMachineManager()
|
vmm := hypervctl.NewVirtualMachineManager()
|
||||||
vm, err := vmm.GetMachine(m.Name)
|
vm, err := vmm.GetMachine(m.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if vm.IsStarting() {
|
if vm.IsStarting() {
|
||||||
return machine.Starting, nil
|
return define.Starting, nil
|
||||||
}
|
}
|
||||||
if vm.State() == hypervctl.Enabled {
|
if vm.State() == hypervctl.Enabled {
|
||||||
return machine.Running, nil
|
return define.Running, nil
|
||||||
}
|
}
|
||||||
// Following QEMU pattern here where only three
|
// Following QEMU pattern here where only three
|
||||||
// states seem valid
|
// states seem valid
|
||||||
return machine.Stopped, nil
|
return define.Stopped, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *HyperVMachine) Stop(name string, opts machine.StopOptions) error {
|
func (m *HyperVMachine) Stop(name string, opts machine.StopOptions) error {
|
||||||
@ -911,19 +913,19 @@ func (m *HyperVMachine) createShares() (_ map[string]uint64, defErr error) {
|
|||||||
toReturn := make(map[string]uint64)
|
toReturn := make(map[string]uint64)
|
||||||
|
|
||||||
for _, mount := range m.Mounts {
|
for _, mount := range m.Mounts {
|
||||||
var vsock *HVSockRegistryEntry
|
var hvSock *vsock.HVSockRegistryEntry
|
||||||
|
|
||||||
vsockNum, ok := m.MountVsocks[mount.Target]
|
vsockNum, ok := m.MountVsocks[mount.Target]
|
||||||
if ok {
|
if ok {
|
||||||
// Ignore errors here, we'll just try and recreate the
|
// Ignore errors here, we'll just try and recreate the
|
||||||
// vsock below.
|
// vsock below.
|
||||||
testVsock, err := LoadHVSockRegistryEntry(vsockNum)
|
testVsock, err := vsock.LoadHVSockRegistryEntry(vsockNum)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
vsock = testVsock
|
hvSock = testVsock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if vsock == nil {
|
if hvSock == nil {
|
||||||
testVsock, err := NewHVSockRegistryEntry(m.Name, Fileserver)
|
testVsock, err := vsock.NewHVSockRegistryEntry(m.Name, vsock.Fileserver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -934,12 +936,12 @@ func (m *HyperVMachine) createShares() (_ map[string]uint64, defErr error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
vsock = testVsock
|
hvSock = testVsock
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("Going to share directory %s via 9p on vsock %d", mount.Source, vsock.Port)
|
logrus.Debugf("Going to share directory %s via 9p on vsock %d", mount.Source, hvSock.Port)
|
||||||
|
|
||||||
toReturn[mount.Target] = vsock.Port
|
toReturn[mount.Target] = hvSock.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
return toReturn, nil
|
return toReturn, nil
|
||||||
@ -955,7 +957,7 @@ func (m *HyperVMachine) removeShares() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vsock, err := LoadHVSockRegistryEntry(vsockNum)
|
vsock, err := vsock.LoadHVSockRegistryEntry(vsockNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Vsock %d for mountpoint %s does not have a valid registry entry, skipping removal", vsockNum, mount.Target)
|
logrus.Debugf("Vsock %d for mountpoint %s does not have a valid registry entry, skipping removal", vsockNum, mount.Target)
|
||||||
continue
|
continue
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package hyperv
|
package vsock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@ -9,8 +9,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/sockets"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
"github.com/Microsoft/go-winio"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
|
||||||
"github.com/containers/podman/v4/utils"
|
"github.com/containers/podman/v4/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/windows/registry"
|
"golang.org/x/sys/windows/registry"
|
||||||
@ -274,7 +275,7 @@ func (hv *HVSockRegistryEntry) Listen() error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
go machine.ListenAndWaitOnSocket(errChan, listener)
|
go sockets.ListenAndWaitOnSocket(errChan, listener)
|
||||||
|
|
||||||
return <-errChan
|
return <-errChan
|
||||||
}
|
}
|
@ -10,10 +10,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/containers/common/libnetwork/etchosts"
|
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -28,7 +25,6 @@ import (
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UserCertsTargetPath = "/etc/containers/certs.d"
|
|
||||||
PodmanDockerTmpConfPath = "/etc/tmpfiles.d/podman-docker.conf"
|
PodmanDockerTmpConfPath = "/etc/tmpfiles.d/podman-docker.conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -615,7 +611,7 @@ func prepareCertFile(path string, name string) (File, error) {
|
|||||||
return File{}, err
|
return File{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
targetPath := filepath.Join(UserCertsTargetPath, name)
|
targetPath := filepath.Join(define.UserCertsTargetPath, name)
|
||||||
|
|
||||||
logrus.Debugf("Copying cert file from '%s' to '%s'.", path, targetPath)
|
logrus.Debugf("Copying cert file from '%s' to '%s'.", path, targetPath)
|
||||||
|
|
||||||
@ -636,22 +632,6 @@ func prepareCertFile(path string, name string) (File, error) {
|
|||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetProxyVariables() map[string]string {
|
|
||||||
proxyOpts := make(map[string]string)
|
|
||||||
for _, variable := range config.ProxyEnv {
|
|
||||||
if value, ok := os.LookupEnv(variable); ok {
|
|
||||||
if value == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
v := strings.ReplaceAll(value, "127.0.0.1", etchosts.HostContainersInternal)
|
|
||||||
v = strings.ReplaceAll(v, "localhost", etchosts.HostContainersInternal)
|
|
||||||
proxyOpts[variable] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return proxyOpts
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLinks(usrName string) []Link {
|
func getLinks(usrName string) []Link {
|
||||||
return []Link{{
|
return []Link{{
|
||||||
Node: Node{
|
Node: Node{
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
package qemu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
|
||||||
)
|
|
||||||
|
|
||||||
// QemuCmd is an alias around a string slice to prevent the need to migrate the
|
|
||||||
// MachineVM struct due to changes
|
|
||||||
type QemuCmd []string
|
|
||||||
|
|
||||||
// NewQemuBuilder creates a new QemuCmd object that we will build on top of,
|
|
||||||
// starting with the qemu binary, architecture specific options, and propagated
|
|
||||||
// proxy and SSL settings
|
|
||||||
func NewQemuBuilder(binary string, options []string) QemuCmd {
|
|
||||||
q := QemuCmd{binary}
|
|
||||||
return append(q, options...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMemory adds the specified amount of memory for the machine
|
|
||||||
func (q *QemuCmd) SetMemory(m uint64) {
|
|
||||||
*q = append(*q, "-m", strconv.FormatUint(m, 10))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCPUs adds the number of CPUs the machine will have
|
|
||||||
func (q *QemuCmd) SetCPUs(c uint64) {
|
|
||||||
*q = append(*q, "-smp", strconv.FormatUint(c, 10))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetIgnitionFile specifies the machine's ignition file
|
|
||||||
func (q *QemuCmd) SetIgnitionFile(file define.VMFile) {
|
|
||||||
*q = append(*q, "-fw_cfg", "name=opt/com.coreos/config,file="+file.GetPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetQmpMonitor specifies the machine's qmp socket
|
|
||||||
func (q *QemuCmd) SetQmpMonitor(monitor Monitor) {
|
|
||||||
*q = append(*q, "-qmp", monitor.Network+":"+monitor.Address.GetPath()+",server=on,wait=off")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNetwork adds a network device to the machine
|
|
||||||
func (q *QemuCmd) SetNetwork() {
|
|
||||||
// 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
|
|
||||||
*q = append(*q, "-netdev", "socket,id=vlan,fd=3", "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNetwork adds a network device to the machine
|
|
||||||
func (q *QemuCmd) SetUSBHostPassthrough(usbs []machine.USBConfig) {
|
|
||||||
if len(usbs) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Add xhci usb emulation first and then each usb device
|
|
||||||
*q = append(*q, "-device", "qemu-xhci")
|
|
||||||
for _, usb := range usbs {
|
|
||||||
var dev string
|
|
||||||
if usb.Bus != "" && usb.DevNumber != "" {
|
|
||||||
dev = fmt.Sprintf("usb-host,hostbus=%s,hostaddr=%s", usb.Bus, usb.DevNumber)
|
|
||||||
} else {
|
|
||||||
dev = fmt.Sprintf("usb-host,vendorid=%d,productid=%d", usb.Vendor, usb.Product)
|
|
||||||
}
|
|
||||||
*q = append(*q, "-device", dev)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSerialPort adds a serial port to the machine for readiness
|
|
||||||
func (q *QemuCmd) SetSerialPort(readySocket, vmPidFile define.VMFile, name string) {
|
|
||||||
*q = append(*q,
|
|
||||||
"-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="+readySocket.GetPath()+",server=on,wait=off,id=a"+name+"_ready",
|
|
||||||
"-device", "virtserialport,chardev=a"+name+"_ready"+",name=org.fedoraproject.port.0",
|
|
||||||
"-pidfile", vmPidFile.GetPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetVirtfsMount adds a virtfs mount to the machine
|
|
||||||
func (q *QemuCmd) SetVirtfsMount(source, tag, securityModel string, readonly bool) {
|
|
||||||
virtfsOptions := fmt.Sprintf("local,path=%s,mount_tag=%s,security_model=%s", source, tag, securityModel)
|
|
||||||
if readonly {
|
|
||||||
virtfsOptions += ",readonly"
|
|
||||||
}
|
|
||||||
*q = append(*q, "-virtfs", virtfsOptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBootableImage specifies the image the machine will use to boot
|
|
||||||
func (q *QemuCmd) SetBootableImage(image string) {
|
|
||||||
*q = append(*q, "-drive", "if=virtio,file="+image)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDisplay specifies whether the machine will have a display
|
|
||||||
func (q *QemuCmd) SetDisplay(display string) {
|
|
||||||
*q = append(*q, "-display", display)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPropagatedHostEnvs adds options that propagate SSL and proxy settings
|
|
||||||
func (q *QemuCmd) SetPropagatedHostEnvs() {
|
|
||||||
*q = propagateHostEnv(*q)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *QemuCmd) Build() []string {
|
|
||||||
return *q
|
|
||||||
}
|
|
236
pkg/machine/qemu/command/command.go
Normal file
236
pkg/machine/qemu/command/command.go
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/common/libnetwork/etchosts"
|
||||||
|
"github.com/containers/common/pkg/config"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
)
|
||||||
|
|
||||||
|
// QemuCmd is an alias around a string slice to prevent the need to migrate the
|
||||||
|
// MachineVM struct due to changes
|
||||||
|
type QemuCmd []string
|
||||||
|
|
||||||
|
// NewQemuBuilder creates a new QemuCmd object that we will build on top of,
|
||||||
|
// starting with the qemu binary, architecture specific options, and propagated
|
||||||
|
// proxy and SSL settings
|
||||||
|
func NewQemuBuilder(binary string, options []string) QemuCmd {
|
||||||
|
q := QemuCmd{binary}
|
||||||
|
return append(q, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMemory adds the specified amount of memory for the machine
|
||||||
|
func (q *QemuCmd) SetMemory(m uint64) {
|
||||||
|
*q = append(*q, "-m", strconv.FormatUint(m, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCPUs adds the number of CPUs the machine will have
|
||||||
|
func (q *QemuCmd) SetCPUs(c uint64) {
|
||||||
|
*q = append(*q, "-smp", strconv.FormatUint(c, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIgnitionFile specifies the machine's ignition file
|
||||||
|
func (q *QemuCmd) SetIgnitionFile(file define.VMFile) {
|
||||||
|
*q = append(*q, "-fw_cfg", "name=opt/com.coreos/config,file="+file.GetPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetQmpMonitor specifies the machine's qmp socket
|
||||||
|
func (q *QemuCmd) SetQmpMonitor(monitor Monitor) {
|
||||||
|
*q = append(*q, "-qmp", monitor.Network+":"+monitor.Address.GetPath()+",server=on,wait=off")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNetwork adds a network device to the machine
|
||||||
|
func (q *QemuCmd) SetNetwork() {
|
||||||
|
// 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
|
||||||
|
*q = append(*q, "-netdev", "socket,id=vlan,fd=3", "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNetwork adds a network device to the machine
|
||||||
|
func (q *QemuCmd) SetUSBHostPassthrough(usbs []USBConfig) {
|
||||||
|
if len(usbs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Add xhci usb emulation first and then each usb device
|
||||||
|
*q = append(*q, "-device", "qemu-xhci")
|
||||||
|
for _, usb := range usbs {
|
||||||
|
var dev string
|
||||||
|
if usb.Bus != "" && usb.DevNumber != "" {
|
||||||
|
dev = fmt.Sprintf("usb-host,hostbus=%s,hostaddr=%s", usb.Bus, usb.DevNumber)
|
||||||
|
} else {
|
||||||
|
dev = fmt.Sprintf("usb-host,vendorid=%d,productid=%d", usb.Vendor, usb.Product)
|
||||||
|
}
|
||||||
|
*q = append(*q, "-device", dev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSerialPort adds a serial port to the machine for readiness
|
||||||
|
func (q *QemuCmd) SetSerialPort(readySocket, vmPidFile define.VMFile, name string) {
|
||||||
|
*q = append(*q,
|
||||||
|
"-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="+readySocket.GetPath()+",server=on,wait=off,id=a"+name+"_ready",
|
||||||
|
"-device", "virtserialport,chardev=a"+name+"_ready"+",name=org.fedoraproject.port.0",
|
||||||
|
"-pidfile", vmPidFile.GetPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVirtfsMount adds a virtfs mount to the machine
|
||||||
|
func (q *QemuCmd) SetVirtfsMount(source, tag, securityModel string, readonly bool) {
|
||||||
|
virtfsOptions := fmt.Sprintf("local,path=%s,mount_tag=%s,security_model=%s", source, tag, securityModel)
|
||||||
|
if readonly {
|
||||||
|
virtfsOptions += ",readonly"
|
||||||
|
}
|
||||||
|
*q = append(*q, "-virtfs", virtfsOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBootableImage specifies the image the machine will use to boot
|
||||||
|
func (q *QemuCmd) SetBootableImage(image string) {
|
||||||
|
*q = append(*q, "-drive", "if=virtio,file="+image)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDisplay specifies whether the machine will have a display
|
||||||
|
func (q *QemuCmd) SetDisplay(display string) {
|
||||||
|
*q = append(*q, "-display", display)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPropagatedHostEnvs adds options that propagate SSL and proxy settings
|
||||||
|
func (q *QemuCmd) SetPropagatedHostEnvs() {
|
||||||
|
*q = propagateHostEnv(*q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *QemuCmd) Build() []string {
|
||||||
|
return *q
|
||||||
|
}
|
||||||
|
|
||||||
|
type USBConfig struct {
|
||||||
|
Bus string
|
||||||
|
DevNumber string
|
||||||
|
Vendor int
|
||||||
|
Product int
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseUSBs(usbs []string) ([]USBConfig, error) {
|
||||||
|
configs := []USBConfig{}
|
||||||
|
for _, str := range usbs {
|
||||||
|
if str == "" {
|
||||||
|
// Ignore --usb="" as it can be used to reset USBConfigs
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
vals := strings.Split(str, ",")
|
||||||
|
if len(vals) != 2 {
|
||||||
|
return configs, fmt.Errorf("usb: fail to parse: missing ',': %s", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
left := strings.Split(vals[0], "=")
|
||||||
|
if len(left) != 2 {
|
||||||
|
return configs, fmt.Errorf("usb: fail to parse: missing '=': %s", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
right := strings.Split(vals[1], "=")
|
||||||
|
if len(right) != 2 {
|
||||||
|
return configs, fmt.Errorf("usb: fail to parse: missing '=': %s", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
option := left[0] + "_" + right[0]
|
||||||
|
|
||||||
|
switch option {
|
||||||
|
case "bus_devnum", "devnum_bus":
|
||||||
|
bus, devnumber := left[1], right[1]
|
||||||
|
if right[0] == "bus" {
|
||||||
|
bus, devnumber = devnumber, bus
|
||||||
|
}
|
||||||
|
|
||||||
|
configs = append(configs, USBConfig{
|
||||||
|
Bus: bus,
|
||||||
|
DevNumber: devnumber,
|
||||||
|
})
|
||||||
|
case "vendor_product", "product_vendor":
|
||||||
|
vendorStr, productStr := left[1], right[1]
|
||||||
|
if right[0] == "vendor" {
|
||||||
|
vendorStr, productStr = productStr, vendorStr
|
||||||
|
}
|
||||||
|
|
||||||
|
vendor, err := strconv.ParseInt(vendorStr, 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
return configs, fmt.Errorf("usb: fail to convert vendor of %s: %s", str, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
product, err := strconv.ParseInt(productStr, 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
return configs, fmt.Errorf("usb: fail to convert product of %s: %s", str, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configs = append(configs, USBConfig{
|
||||||
|
Vendor: int(vendor),
|
||||||
|
Product: int(product),
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
return configs, fmt.Errorf("usb: fail to parse: %s", str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProxyVariables() map[string]string {
|
||||||
|
proxyOpts := make(map[string]string)
|
||||||
|
for _, variable := range config.ProxyEnv {
|
||||||
|
if value, ok := os.LookupEnv(variable); ok {
|
||||||
|
if value == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
v := strings.ReplaceAll(value, "127.0.0.1", etchosts.HostContainersInternal)
|
||||||
|
v = strings.ReplaceAll(v, "localhost", etchosts.HostContainersInternal)
|
||||||
|
proxyOpts[variable] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proxyOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
// propagateHostEnv is here for providing the ability to propagate
|
||||||
|
// proxy and SSL settings (e.g. HTTP_PROXY and others) on a start
|
||||||
|
// and avoid a need of re-creating/re-initiating a VM
|
||||||
|
func propagateHostEnv(cmdLine QemuCmd) QemuCmd {
|
||||||
|
varsToPropagate := make([]string, 0)
|
||||||
|
|
||||||
|
for k, v := range GetProxyVariables() {
|
||||||
|
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
if sslCertFile, ok := os.LookupEnv("SSL_CERT_FILE"); ok {
|
||||||
|
pathInVM := filepath.Join(define.UserCertsTargetPath, filepath.Base(sslCertFile))
|
||||||
|
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", "SSL_CERT_FILE", pathInVM))
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := os.LookupEnv("SSL_CERT_DIR"); ok {
|
||||||
|
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", "SSL_CERT_DIR", define.UserCertsTargetPath))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(varsToPropagate) > 0 {
|
||||||
|
prefix := "name=opt/com.coreos/environment,string="
|
||||||
|
envVarsJoined := strings.Join(varsToPropagate, "|")
|
||||||
|
fwCfgArg := prefix + base64.StdEncoding.EncodeToString([]byte(envVarsJoined))
|
||||||
|
return append(cmdLine, "-fw_cfg", fwCfgArg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmdLine
|
||||||
|
}
|
||||||
|
|
||||||
|
type Monitor struct {
|
||||||
|
// Address portion of the qmp monitor (/tmp/tmp.sock)
|
||||||
|
Address define.VMFile
|
||||||
|
// Network portion of the qmp monitor (unix)
|
||||||
|
Network string
|
||||||
|
// Timeout in seconds for qmp monitor transactions
|
||||||
|
Timeout time.Duration
|
||||||
|
}
|
94
pkg/machine/qemu/command/command_test.go
Normal file
94
pkg/machine/qemu/command/command_test.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containers/common/libnetwork/etchosts"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPropagateHostEnv(t *testing.T) {
|
||||||
|
tests := map[string]struct {
|
||||||
|
value string
|
||||||
|
expect string
|
||||||
|
}{
|
||||||
|
"HTTP_PROXY": {
|
||||||
|
"proxy",
|
||||||
|
"equal",
|
||||||
|
},
|
||||||
|
"ftp_proxy": {
|
||||||
|
"domain.com:8888",
|
||||||
|
"equal",
|
||||||
|
},
|
||||||
|
"FTP_PROXY": {
|
||||||
|
"proxy",
|
||||||
|
"equal",
|
||||||
|
},
|
||||||
|
"NO_PROXY": {
|
||||||
|
"localaddress",
|
||||||
|
"equal",
|
||||||
|
},
|
||||||
|
"HTTPS_PROXY": {
|
||||||
|
"",
|
||||||
|
"unset",
|
||||||
|
},
|
||||||
|
"no_proxy": {
|
||||||
|
"",
|
||||||
|
"unset",
|
||||||
|
},
|
||||||
|
"http_proxy": {
|
||||||
|
"127.0.0.1:8888",
|
||||||
|
fmt.Sprintf("%s:8888", etchosts.HostContainersInternal),
|
||||||
|
},
|
||||||
|
"https_proxy": {
|
||||||
|
"localhost:8888",
|
||||||
|
fmt.Sprintf("%s:8888", etchosts.HostContainersInternal),
|
||||||
|
},
|
||||||
|
"SSL_CERT_FILE": {
|
||||||
|
"/some/f=oo.cert",
|
||||||
|
fmt.Sprintf("%s/f=oo.cert", define.UserCertsTargetPath),
|
||||||
|
},
|
||||||
|
"SSL_CERT_DIR": {
|
||||||
|
"/some/my/certs",
|
||||||
|
define.UserCertsTargetPath,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, item := range tests {
|
||||||
|
t.Setenv(key, item.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdLine := propagateHostEnv(make([]string, 0))
|
||||||
|
|
||||||
|
assert.Len(t, cmdLine, 2)
|
||||||
|
assert.Equal(t, "-fw_cfg", cmdLine[0])
|
||||||
|
tokens := strings.Split(cmdLine[1], ",string=")
|
||||||
|
decodeString, err := base64.StdEncoding.DecodeString(tokens[1])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// envsRawArr looks like: ["BAR=\"bar\"", "FOO=\"foo\""]
|
||||||
|
envsRawArr := strings.Split(string(decodeString), "|")
|
||||||
|
// envs looks like: {"BAR": "bar", "FOO": "foo"}
|
||||||
|
envs := make(map[string]string)
|
||||||
|
for _, env := range envsRawArr {
|
||||||
|
item := strings.SplitN(env, "=", 2)
|
||||||
|
envs[item[0]] = strings.Trim(item[1], "\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, test := range tests {
|
||||||
|
switch test.expect {
|
||||||
|
case "equal":
|
||||||
|
assert.Equal(t, envs[key], test.value)
|
||||||
|
case "unset":
|
||||||
|
if _, ok := envs[key]; ok {
|
||||||
|
t.Errorf("env %s should not be set", key)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert.Equal(t, envs[key], test.expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
//go:build (amd64 && !windows) || (arm64 && !windows)
|
//go:build (amd64 && !windows) || (arm64 && !windows)
|
||||||
// +build amd64,!windows arm64,!windows
|
// +build amd64,!windows arm64,!windows
|
||||||
|
|
||||||
package qemu
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -6,7 +6,6 @@ import (
|
|||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,6 +13,9 @@ import (
|
|||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/containers/podman/v4/pkg/machine/compression"
|
"github.com/containers/podman/v4/pkg/machine/compression"
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/qemu/command"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/sockets"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
|
||||||
"github.com/containers/podman/v4/utils"
|
"github.com/containers/podman/v4/utils"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -59,7 +61,7 @@ func (v *MachineVM) setQMPMonitorSocket() error {
|
|||||||
// setNewMachineCMD configure the CLI command that will be run to create the new
|
// setNewMachineCMD configure the CLI command that will be run to create the new
|
||||||
// machine
|
// machine
|
||||||
func (v *MachineVM) setNewMachineCMD(qemuBinary string, cmdOpts *setNewMachineCMDOpts) {
|
func (v *MachineVM) setNewMachineCMD(qemuBinary string, cmdOpts *setNewMachineCMDOpts) {
|
||||||
v.CmdLine = NewQemuBuilder(qemuBinary, v.addArchOptions(cmdOpts))
|
v.CmdLine = command.NewQemuBuilder(qemuBinary, v.addArchOptions(cmdOpts))
|
||||||
v.CmdLine.SetMemory(v.Memory)
|
v.CmdLine.SetMemory(v.Memory)
|
||||||
v.CmdLine.SetCPUs(v.CPUs)
|
v.CmdLine.SetCPUs(v.CPUs)
|
||||||
v.CmdLine.SetIgnitionFile(v.IgnitionFile)
|
v.CmdLine.SetIgnitionFile(v.IgnitionFile)
|
||||||
@ -69,69 +71,6 @@ func (v *MachineVM) setNewMachineCMD(qemuBinary string, cmdOpts *setNewMachineCM
|
|||||||
v.CmdLine.SetUSBHostPassthrough(v.USBs)
|
v.CmdLine.SetUSBHostPassthrough(v.USBs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseUSBs(usbs []string) ([]machine.USBConfig, error) {
|
|
||||||
configs := []machine.USBConfig{}
|
|
||||||
for _, str := range usbs {
|
|
||||||
if str == "" {
|
|
||||||
// Ignore --usb="" as it can be used to reset USBConfigs
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
vals := strings.Split(str, ",")
|
|
||||||
if len(vals) != 2 {
|
|
||||||
return configs, fmt.Errorf("usb: fail to parse: missing ',': %s", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
left := strings.Split(vals[0], "=")
|
|
||||||
if len(left) != 2 {
|
|
||||||
return configs, fmt.Errorf("usb: fail to parse: missing '=': %s", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
right := strings.Split(vals[1], "=")
|
|
||||||
if len(right) != 2 {
|
|
||||||
return configs, fmt.Errorf("usb: fail to parse: missing '=': %s", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
option := left[0] + "_" + right[0]
|
|
||||||
|
|
||||||
switch option {
|
|
||||||
case "bus_devnum", "devnum_bus":
|
|
||||||
bus, devnumber := left[1], right[1]
|
|
||||||
if right[0] == "bus" {
|
|
||||||
bus, devnumber = devnumber, bus
|
|
||||||
}
|
|
||||||
|
|
||||||
configs = append(configs, machine.USBConfig{
|
|
||||||
Bus: bus,
|
|
||||||
DevNumber: devnumber,
|
|
||||||
})
|
|
||||||
case "vendor_product", "product_vendor":
|
|
||||||
vendorStr, productStr := left[1], right[1]
|
|
||||||
if right[0] == "vendor" {
|
|
||||||
vendorStr, productStr = productStr, vendorStr
|
|
||||||
}
|
|
||||||
|
|
||||||
vendor, err := strconv.ParseInt(vendorStr, 16, 0)
|
|
||||||
if err != nil {
|
|
||||||
return configs, fmt.Errorf("usb: fail to convert vendor of %s: %s", str, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
product, err := strconv.ParseInt(productStr, 16, 0)
|
|
||||||
if err != nil {
|
|
||||||
return configs, fmt.Errorf("usb: fail to convert product of %s: %s", str, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
configs = append(configs, machine.USBConfig{
|
|
||||||
Vendor: int(vendor),
|
|
||||||
Product: int(product),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
return configs, fmt.Errorf("usb: fail to parse: %s", str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return configs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 *QEMUVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
func (p *QEMUVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||||
@ -169,7 +108,7 @@ func (p *QEMUVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, e
|
|||||||
vm.CPUs = opts.CPUS
|
vm.CPUs = opts.CPUS
|
||||||
vm.Memory = opts.Memory
|
vm.Memory = opts.Memory
|
||||||
vm.DiskSize = opts.DiskSize
|
vm.DiskSize = opts.DiskSize
|
||||||
if vm.USBs, err = parseUSBs(opts.USBs); err != nil {
|
if vm.USBs, err = command.ParseUSBs(opts.USBs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +134,7 @@ func (p *QEMUVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, e
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
symlink := vm.Name + "_ready.sock"
|
symlink := vm.Name + "_ready.sock"
|
||||||
if err := machine.SetSocket(&vm.ReadySocket, machine.ReadySocketPath(runtimeDir+"/podman/", vm.Name), &symlink); err != nil {
|
if err := sockets.SetSocket(&vm.ReadySocket, sockets.ReadySocketPath(runtimeDir+"/podman/", vm.Name), &symlink); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +148,7 @@ func (p *QEMUVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, e
|
|||||||
// and returns a vm instance
|
// and returns a vm instance
|
||||||
func (p *QEMUVirtualization) LoadVMByName(name string) (machine.VM, error) {
|
func (p *QEMUVirtualization) LoadVMByName(name string) (machine.VM, error) {
|
||||||
vm := &MachineVM{Name: name}
|
vm := &MachineVM{Name: name}
|
||||||
vm.HostUser = machine.HostUser{UID: -1} // posix reserves -1, so use it to signify undefined
|
vm.HostUser = vmconfigs.HostUser{UID: -1} // posix reserves -1, so use it to signify undefined
|
||||||
if err := vm.update(); err != nil {
|
if err := vm.update(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -274,7 +213,7 @@ func getVMInfos() ([]*machine.ListResponse, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
listEntry.Running = state == machine.Running
|
listEntry.Running = state == define.Running
|
||||||
listEntry.LastUp = vm.LastUp
|
listEntry.LastUp = vm.LastUp
|
||||||
|
|
||||||
listed = append(listed, listEntry)
|
listed = append(listed, listEntry)
|
||||||
|
@ -4,20 +4,20 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine/qemu/command"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUSBParsing(t *testing.T) {
|
func TestUSBParsing(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
result []machine.USBConfig
|
result []command.USBConfig
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Good vendor and product",
|
name: "Good vendor and product",
|
||||||
args: []string{"vendor=13d3,product=5406", "vendor=08ec,product=0016"},
|
args: []string{"vendor=13d3,product=5406", "vendor=08ec,product=0016"},
|
||||||
result: []machine.USBConfig{
|
result: []command.USBConfig{
|
||||||
{
|
{
|
||||||
Vendor: 5075,
|
Vendor: 5075,
|
||||||
Product: 21510,
|
Product: 21510,
|
||||||
@ -32,7 +32,7 @@ func TestUSBParsing(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Good bus and device number",
|
name: "Good bus and device number",
|
||||||
args: []string{"bus=1,devnum=4", "bus=1,devnum=3"},
|
args: []string{"bus=1,devnum=4", "bus=1,devnum=3"},
|
||||||
result: []machine.USBConfig{
|
result: []command.USBConfig{
|
||||||
{
|
{
|
||||||
Bus: "1",
|
Bus: "1",
|
||||||
DevNumber: "4",
|
DevNumber: "4",
|
||||||
@ -47,26 +47,26 @@ func TestUSBParsing(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Bad vendor and product, not hexa",
|
name: "Bad vendor and product, not hexa",
|
||||||
args: []string{"vendor=13dk,product=5406"},
|
args: []string{"vendor=13dk,product=5406"},
|
||||||
result: []machine.USBConfig{},
|
result: []command.USBConfig{},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Bad vendor and product, bad separator",
|
name: "Bad vendor and product, bad separator",
|
||||||
args: []string{"vendor=13d3:product=5406"},
|
args: []string{"vendor=13d3:product=5406"},
|
||||||
result: []machine.USBConfig{},
|
result: []command.USBConfig{},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Bad vendor and product, missing equal",
|
name: "Bad vendor and product, missing equal",
|
||||||
args: []string{"vendor=13d3:product-5406"},
|
args: []string{"vendor=13d3:product-5406"},
|
||||||
result: []machine.USBConfig{},
|
result: []command.USBConfig{},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
got, err := parseUSBs(test.args)
|
got, err := command.ParseUSBs(test.args)
|
||||||
if (err != nil) != test.wantErr {
|
if (err != nil) != test.wantErr {
|
||||||
t.Errorf("parseUUBs error = %v, wantErr %v", err, test.wantErr)
|
t.Errorf("parseUUBs error = %v, wantErr %v", err, test.wantErr)
|
||||||
return
|
return
|
||||||
|
@ -6,7 +6,6 @@ package qemu
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -25,6 +24,9 @@ import (
|
|||||||
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
|
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/qemu/command"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/sockets"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
|
||||||
"github.com/containers/podman/v4/pkg/rootless"
|
"github.com/containers/podman/v4/pkg/rootless"
|
||||||
"github.com/containers/podman/v4/pkg/util"
|
"github.com/containers/podman/v4/pkg/util"
|
||||||
"github.com/containers/storage/pkg/lockfile"
|
"github.com/containers/storage/pkg/lockfile"
|
||||||
@ -66,13 +68,13 @@ type MachineVM struct {
|
|||||||
// ConfigPath is the path to the configuration file
|
// ConfigPath is the path to the configuration file
|
||||||
ConfigPath define.VMFile
|
ConfigPath define.VMFile
|
||||||
// The command line representation of the qemu command
|
// The command line representation of the qemu command
|
||||||
CmdLine QemuCmd
|
CmdLine command.QemuCmd
|
||||||
// HostUser contains info about host user
|
// HostUser contains info about host user
|
||||||
machine.HostUser
|
vmconfigs.HostUser
|
||||||
// ImageConfig describes the bootable image
|
// ImageConfig describes the bootable image
|
||||||
machine.ImageConfig
|
machine.ImageConfig
|
||||||
// Mounts is the list of remote filesystems to mount
|
// Mounts is the list of remote filesystems to mount
|
||||||
Mounts []machine.Mount
|
Mounts []vmconfigs.Mount
|
||||||
// Name of VM
|
// Name of VM
|
||||||
Name string
|
Name string
|
||||||
// PidFilePath is the where the Proxy PID file lives
|
// PidFilePath is the where the Proxy PID file lives
|
||||||
@ -80,13 +82,13 @@ type MachineVM struct {
|
|||||||
// VMPidFilePath is the where the VM PID file lives
|
// VMPidFilePath is the where the VM PID file lives
|
||||||
VMPidFilePath define.VMFile
|
VMPidFilePath define.VMFile
|
||||||
// QMPMonitor is the qemu monitor object for sending commands
|
// QMPMonitor is the qemu monitor object for sending commands
|
||||||
QMPMonitor Monitor
|
QMPMonitor command.Monitor
|
||||||
// ReadySocket tells host when vm is booted
|
// ReadySocket tells host when vm is booted
|
||||||
ReadySocket define.VMFile
|
ReadySocket define.VMFile
|
||||||
// ResourceConfig is physical attrs of the VM
|
// ResourceConfig is physical attrs of the VM
|
||||||
machine.ResourceConfig
|
vmconfigs.ResourceConfig
|
||||||
// SSHConfig for accessing the remote vm
|
// SSHConfig for accessing the remote vm
|
||||||
machine.SSHConfig
|
vmconfigs.SSHConfig
|
||||||
// Starting tells us whether the machine is running or if we have just dialed it to start it
|
// Starting tells us whether the machine is running or if we have just dialed it to start it
|
||||||
Starting bool
|
Starting bool
|
||||||
// Created contains the original created time instead of querying the file mod time
|
// Created contains the original created time instead of querying the file mod time
|
||||||
@ -98,15 +100,6 @@ type MachineVM struct {
|
|||||||
lock *lockfile.LockFile
|
lock *lockfile.LockFile
|
||||||
}
|
}
|
||||||
|
|
||||||
type Monitor struct {
|
|
||||||
// Address portion of the qmp monitor (/tmp/tmp.sock)
|
|
||||||
Address define.VMFile
|
|
||||||
// Network portion of the qmp monitor (unix)
|
|
||||||
Network string
|
|
||||||
// Timeout in seconds for qmp monitor transactions
|
|
||||||
Timeout time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// addMountsToVM converts the volumes passed through the CLI into the specified
|
// addMountsToVM converts the volumes passed through the CLI into the specified
|
||||||
// volume driver and adds them to the machine
|
// volume driver and adds them to the machine
|
||||||
func (v *MachineVM) addMountsToVM(opts machine.InitOptions) error {
|
func (v *MachineVM) addMountsToVM(opts machine.InitOptions) error {
|
||||||
@ -119,7 +112,7 @@ func (v *MachineVM) addMountsToVM(opts machine.InitOptions) error {
|
|||||||
return fmt.Errorf("unknown volume driver: %s", opts.VolumeDriver)
|
return fmt.Errorf("unknown volume driver: %s", opts.VolumeDriver)
|
||||||
}
|
}
|
||||||
|
|
||||||
mounts := []machine.Mount{}
|
mounts := []vmconfigs.Mount{}
|
||||||
for i, volume := range opts.Volumes {
|
for i, volume := range opts.Volumes {
|
||||||
tag := fmt.Sprintf("vol%d", i)
|
tag := fmt.Sprintf("vol%d", i)
|
||||||
paths := pathsFromVolume(volume)
|
paths := pathsFromVolume(volume)
|
||||||
@ -128,7 +121,7 @@ func (v *MachineVM) addMountsToVM(opts machine.InitOptions) error {
|
|||||||
readonly, securityModel := extractMountOptions(paths)
|
readonly, securityModel := extractMountOptions(paths)
|
||||||
if volumeType == VolumeTypeVirtfs {
|
if volumeType == VolumeTypeVirtfs {
|
||||||
v.CmdLine.SetVirtfsMount(source, tag, securityModel, readonly)
|
v.CmdLine.SetVirtfsMount(source, tag, securityModel, readonly)
|
||||||
mounts = append(mounts, machine.Mount{Type: MountType9p, Tag: tag, Source: source, Target: target, ReadOnly: readonly})
|
mounts = append(mounts, vmconfigs.Mount{Type: MountType9p, Tag: tag, Source: source, Target: target, ReadOnly: readonly})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.Mounts = mounts
|
v.Mounts = mounts
|
||||||
@ -274,7 +267,7 @@ func (v *MachineVM) Set(_ string, opts machine.SetOptions) ([]error, error) {
|
|||||||
return setErrors, err
|
return setErrors, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if state == machine.Running {
|
if state == define.Running {
|
||||||
suffix := ""
|
suffix := ""
|
||||||
if v.Name != machine.DefaultMachineName {
|
if v.Name != machine.DefaultMachineName {
|
||||||
suffix = " " + v.Name
|
suffix = " " + v.Name
|
||||||
@ -309,7 +302,7 @@ func (v *MachineVM) Set(_ string, opts machine.SetOptions) ([]error, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.USBs != nil {
|
if opts.USBs != nil {
|
||||||
if usbConfigs, err := parseUSBs(*opts.USBs); err != nil {
|
if usbConfigs, err := command.ParseUSBs(*opts.USBs); err != nil {
|
||||||
setErrors = append(setErrors, fmt.Errorf("failed to set usb: %w", err))
|
setErrors = append(setErrors, fmt.Errorf("failed to set usb: %w", err))
|
||||||
} else {
|
} else {
|
||||||
v.USBs = usbConfigs
|
v.USBs = usbConfigs
|
||||||
@ -381,7 +374,7 @@ func (v *MachineVM) conductVMReadinessCheck(name string, maxBackoffs int, backof
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
if state == machine.Running && v.isListening() {
|
if state == define.Running && v.isListening() {
|
||||||
// Also make sure that SSH is up and running. The
|
// Also make sure that SSH is up and running. The
|
||||||
// ready service's dependencies don't fully make sure
|
// ready service's dependencies don't fully make sure
|
||||||
// that clients can SSH into the machine immediately
|
// that clients can SSH into the machine immediately
|
||||||
@ -469,9 +462,9 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch state {
|
switch state {
|
||||||
case machine.Starting:
|
case define.Starting:
|
||||||
return fmt.Errorf("cannot start VM %q: starting state indicates that a previous start has failed: please stop and restart the VM", v.Name)
|
return fmt.Errorf("cannot start VM %q: starting state indicates that a previous start has failed: please stop and restart the VM", v.Name)
|
||||||
case machine.Running:
|
case define.Running:
|
||||||
return fmt.Errorf("cannot start VM %q: %w", v.Name, machine.ErrVMAlreadyRunning)
|
return fmt.Errorf("cannot start VM %q: %w", v.Name, machine.ErrVMAlreadyRunning)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,7 +530,7 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
qemuSocketConn, err = machine.DialSocketWithBackoffs(maxBackoffs, defaultBackoff, v.QMPMonitor.Address.Path)
|
qemuSocketConn, err = sockets.DialSocketWithBackoffs(maxBackoffs, defaultBackoff, v.QMPMonitor.Address.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -592,7 +585,7 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
|
|||||||
fmt.Println("Waiting for VM ...")
|
fmt.Println("Waiting for VM ...")
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err = machine.DialSocketWithBackoffsAndProcCheck(maxBackoffs, defaultBackoff, v.ReadySocket.GetPath(), checkProcessStatus, "qemu", cmd.Process.Pid, stderrBuf)
|
conn, err = sockets.DialSocketWithBackoffsAndProcCheck(maxBackoffs, defaultBackoff, v.ReadySocket.GetPath(), checkProcessStatus, "qemu", cmd.Process.Pid, stderrBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -656,36 +649,7 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// propagateHostEnv is here for providing the ability to propagate
|
func (v *MachineVM) checkStatus(monitor *qmp.SocketMonitor) (define.Status, error) {
|
||||||
// proxy and SSL settings (e.g. HTTP_PROXY and others) on a start
|
|
||||||
// and avoid a need of re-creating/re-initiating a VM
|
|
||||||
func propagateHostEnv(cmdLine QemuCmd) QemuCmd {
|
|
||||||
varsToPropagate := make([]string, 0)
|
|
||||||
|
|
||||||
for k, v := range machine.GetProxyVariables() {
|
|
||||||
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", k, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
if sslCertFile, ok := os.LookupEnv("SSL_CERT_FILE"); ok {
|
|
||||||
pathInVM := filepath.Join(machine.UserCertsTargetPath, filepath.Base(sslCertFile))
|
|
||||||
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", "SSL_CERT_FILE", pathInVM))
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := os.LookupEnv("SSL_CERT_DIR"); ok {
|
|
||||||
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", "SSL_CERT_DIR", machine.UserCertsTargetPath))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(varsToPropagate) > 0 {
|
|
||||||
prefix := "name=opt/com.coreos/environment,string="
|
|
||||||
envVarsJoined := strings.Join(varsToPropagate, "|")
|
|
||||||
fwCfgArg := prefix + base64.StdEncoding.EncodeToString([]byte(envVarsJoined))
|
|
||||||
return append(cmdLine, "-fw_cfg", fwCfgArg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdLine
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *MachineVM) checkStatus(monitor *qmp.SocketMonitor) (machine.Status, error) {
|
|
||||||
// this is the format returned from the monitor
|
// this is the format returned from the monitor
|
||||||
// {"return": {"status": "running", "singlestep": false, "running": true}}
|
// {"return": {"status": "running", "singlestep": false, "running": true}}
|
||||||
|
|
||||||
@ -712,17 +676,17 @@ func (v *MachineVM) checkStatus(monitor *qmp.SocketMonitor) (machine.Status, err
|
|||||||
b, err := monitor.Run(input)
|
b, err := monitor.Run(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return machine.Stopped, nil
|
return define.Stopped, nil
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(b, &response); err != nil {
|
if err := json.Unmarshal(b, &response); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if response.Response.Status == machine.Running {
|
if response.Response.Status == define.Running {
|
||||||
return machine.Running, nil
|
return define.Running, nil
|
||||||
}
|
}
|
||||||
return machine.Stopped, nil
|
return define.Stopped, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// waitForMachineToStop waits for the machine to stop running
|
// waitForMachineToStop waits for the machine to stop running
|
||||||
@ -734,7 +698,7 @@ func (v *MachineVM) waitForMachineToStop() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if state != machine.Running {
|
if state != define.Running {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(waitInternal)
|
time.Sleep(waitInternal)
|
||||||
@ -929,10 +893,10 @@ func (v *MachineVM) stopLocked() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewQMPMonitor creates the monitor subsection of our vm
|
// NewQMPMonitor creates the monitor subsection of our vm
|
||||||
func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error) {
|
func NewQMPMonitor(network, name string, timeout time.Duration) (command.Monitor, error) {
|
||||||
rtDir, err := getRuntimeDir()
|
rtDir, err := getRuntimeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Monitor{}, err
|
return command.Monitor{}, err
|
||||||
}
|
}
|
||||||
if isRootful() {
|
if isRootful() {
|
||||||
rtDir = "/run"
|
rtDir = "/run"
|
||||||
@ -940,7 +904,7 @@ func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error)
|
|||||||
rtDir = filepath.Join(rtDir, "podman")
|
rtDir = filepath.Join(rtDir, "podman")
|
||||||
if _, err := os.Stat(rtDir); errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(rtDir); errors.Is(err, fs.ErrNotExist) {
|
||||||
if err := os.MkdirAll(rtDir, 0755); err != nil {
|
if err := os.MkdirAll(rtDir, 0755); err != nil {
|
||||||
return Monitor{}, err
|
return command.Monitor{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
@ -948,9 +912,9 @@ func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error)
|
|||||||
}
|
}
|
||||||
address, err := define.NewMachineFile(filepath.Join(rtDir, "qmp_"+name+".sock"), nil)
|
address, err := define.NewMachineFile(filepath.Join(rtDir, "qmp_"+name+".sock"), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Monitor{}, err
|
return command.Monitor{}, err
|
||||||
}
|
}
|
||||||
monitor := Monitor{
|
monitor := command.Monitor{
|
||||||
Network: network,
|
Network: network,
|
||||||
Address: *address,
|
Address: *address,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
@ -1021,7 +985,7 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
if state == machine.Running {
|
if state == define.Running {
|
||||||
if !opts.Force {
|
if !opts.Force {
|
||||||
return "", nil, &machine.ErrVMRunningCannotDestroyed{Name: v.Name}
|
return "", nil, &machine.ErrVMRunningCannotDestroyed{Name: v.Name}
|
||||||
}
|
}
|
||||||
@ -1050,7 +1014,7 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) State(bypass bool) (machine.Status, error) {
|
func (v *MachineVM) State(bypass bool) (define.Status, error) {
|
||||||
// Check if qmp socket path exists
|
// Check if qmp socket path exists
|
||||||
if _, err := os.Stat(v.QMPMonitor.Address.GetPath()); errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(v.QMPMonitor.Address.GetPath()); errors.Is(err, fs.ErrNotExist) {
|
||||||
return "", nil
|
return "", nil
|
||||||
@ -1061,7 +1025,7 @@ func (v *MachineVM) State(bypass bool) (machine.Status, error) {
|
|||||||
}
|
}
|
||||||
// Check if we can dial it
|
// Check if we can dial it
|
||||||
if v.Starting && !bypass {
|
if v.Starting && !bypass {
|
||||||
return machine.Starting, nil
|
return define.Starting, nil
|
||||||
}
|
}
|
||||||
monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout)
|
monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1069,7 +1033,7 @@ func (v *MachineVM) State(bypass bool) (machine.Status, error) {
|
|||||||
// it can appear as though the machine state is not stopped. Check for ECONNREFUSED
|
// it can appear as though the machine state is not stopped. Check for ECONNREFUSED
|
||||||
// almost assures us that the vm is stopped.
|
// almost assures us that the vm is stopped.
|
||||||
if errors.Is(err, syscall.ECONNREFUSED) {
|
if errors.Is(err, syscall.ECONNREFUSED) {
|
||||||
return machine.Stopped, nil
|
return define.Stopped, nil
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -1102,7 +1066,7 @@ func (v *MachineVM) SSH(_ string, opts machine.SSHOptions) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if state != machine.Running {
|
if state != define.Running {
|
||||||
return fmt.Errorf("vm %q is not running", v.Name)
|
return fmt.Errorf("vm %q is not running", v.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,105 +4,18 @@
|
|||||||
package qemu
|
package qemu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containers/common/libnetwork/etchosts"
|
"github.com/containers/podman/v4/pkg/machine/qemu/command"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEditCmd(t *testing.T) {
|
func TestEditCmd(t *testing.T) {
|
||||||
vm := new(MachineVM)
|
vm := new(MachineVM)
|
||||||
vm.CmdLine = QemuCmd{"command", "-flag", "value"}
|
vm.CmdLine = command.QemuCmd{"command", "-flag", "value"}
|
||||||
|
|
||||||
vm.editCmdLine("-flag", "newvalue")
|
vm.editCmdLine("-flag", "newvalue")
|
||||||
vm.editCmdLine("-anotherflag", "anothervalue")
|
vm.editCmdLine("-anotherflag", "anothervalue")
|
||||||
|
|
||||||
require.Equal(t, vm.CmdLine.Build(), []string{"command", "-flag", "newvalue", "-anotherflag", "anothervalue"})
|
require.Equal(t, vm.CmdLine.Build(), []string{"command", "-flag", "newvalue", "-anotherflag", "anothervalue"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPropagateHostEnv(t *testing.T) {
|
|
||||||
tests := map[string]struct {
|
|
||||||
value string
|
|
||||||
expect string
|
|
||||||
}{
|
|
||||||
"HTTP_PROXY": {
|
|
||||||
"proxy",
|
|
||||||
"equal",
|
|
||||||
},
|
|
||||||
"ftp_proxy": {
|
|
||||||
"domain.com:8888",
|
|
||||||
"equal",
|
|
||||||
},
|
|
||||||
"FTP_PROXY": {
|
|
||||||
"proxy",
|
|
||||||
"equal",
|
|
||||||
},
|
|
||||||
"NO_PROXY": {
|
|
||||||
"localaddress",
|
|
||||||
"equal",
|
|
||||||
},
|
|
||||||
"HTTPS_PROXY": {
|
|
||||||
"",
|
|
||||||
"unset",
|
|
||||||
},
|
|
||||||
"no_proxy": {
|
|
||||||
"",
|
|
||||||
"unset",
|
|
||||||
},
|
|
||||||
"http_proxy": {
|
|
||||||
"127.0.0.1:8888",
|
|
||||||
fmt.Sprintf("%s:8888", etchosts.HostContainersInternal),
|
|
||||||
},
|
|
||||||
"https_proxy": {
|
|
||||||
"localhost:8888",
|
|
||||||
fmt.Sprintf("%s:8888", etchosts.HostContainersInternal),
|
|
||||||
},
|
|
||||||
"SSL_CERT_FILE": {
|
|
||||||
"/some/f=oo.cert",
|
|
||||||
fmt.Sprintf("%s/f=oo.cert", machine.UserCertsTargetPath),
|
|
||||||
},
|
|
||||||
"SSL_CERT_DIR": {
|
|
||||||
"/some/my/certs",
|
|
||||||
machine.UserCertsTargetPath,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, item := range tests {
|
|
||||||
t.Setenv(key, item.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdLine := propagateHostEnv(make([]string, 0))
|
|
||||||
|
|
||||||
assert.Len(t, cmdLine, 2)
|
|
||||||
assert.Equal(t, "-fw_cfg", cmdLine[0])
|
|
||||||
tokens := strings.Split(cmdLine[1], ",string=")
|
|
||||||
decodeString, err := base64.StdEncoding.DecodeString(tokens[1])
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// envsRawArr looks like: ["BAR=\"bar\"", "FOO=\"foo\""]
|
|
||||||
envsRawArr := strings.Split(string(decodeString), "|")
|
|
||||||
// envs looks like: {"BAR": "bar", "FOO": "foo"}
|
|
||||||
envs := make(map[string]string)
|
|
||||||
for _, env := range envsRawArr {
|
|
||||||
item := strings.SplitN(env, "=", 2)
|
|
||||||
envs[item[0]] = strings.Trim(item[1], "\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, test := range tests {
|
|
||||||
switch test.expect {
|
|
||||||
case "equal":
|
|
||||||
assert.Equal(t, envs[key], test.value)
|
|
||||||
case "unset":
|
|
||||||
if _, ok := envs[key]; ok {
|
|
||||||
t.Errorf("env %s should not be set", key)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
assert.Equal(t, envs[key], test.expect)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package machine
|
package sockets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
142
pkg/machine/vmconfigs/config.go
Normal file
142
pkg/machine/vmconfigs/config.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package vmconfigs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/qemu/command"
|
||||||
|
"github.com/containers/storage/pkg/lockfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
type aThing struct{}
|
||||||
|
|
||||||
|
type MachineConfig struct {
|
||||||
|
// Common stuff
|
||||||
|
Created time.Time
|
||||||
|
GvProxy gvproxy.GvproxyCommand
|
||||||
|
HostUser HostUser
|
||||||
|
IgnitionFile *aThing // possible interface
|
||||||
|
LastUp time.Time
|
||||||
|
LogPath *define.VMFile `json:",omitempty"` // Revisit this for all providers
|
||||||
|
Mounts []Mount
|
||||||
|
Name string
|
||||||
|
ReadySocket *aThing // possible interface
|
||||||
|
Resources ResourceConfig
|
||||||
|
SSH SSHConfig
|
||||||
|
Starting *bool
|
||||||
|
Version uint
|
||||||
|
|
||||||
|
// Image stuff
|
||||||
|
imageDescription machineImage //nolint:unused
|
||||||
|
|
||||||
|
// Provider stuff
|
||||||
|
AppleHypervisor *AppleHVConfig `json:",omitempty"`
|
||||||
|
QEMUHypervisor *QEMUConfig `json:",omitempty"`
|
||||||
|
HyperVHypervisor *HyperVConfig `json:",omitempty"`
|
||||||
|
WSLHypervisor *WSLConfig `json:",omitempty"`
|
||||||
|
|
||||||
|
lock *lockfile.LockFile //nolint:unused
|
||||||
|
}
|
||||||
|
|
||||||
|
// MachineImage describes a podman machine image
|
||||||
|
type MachineImage struct {
|
||||||
|
OCI *ociMachineImage
|
||||||
|
FCOS *fcosMachineImage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull downloads a machine image
|
||||||
|
func (m *MachineImage) Pull() error {
|
||||||
|
if m.OCI != nil {
|
||||||
|
return m.OCI.download()
|
||||||
|
}
|
||||||
|
if m.FCOS != nil {
|
||||||
|
return m.FCOS.download()
|
||||||
|
}
|
||||||
|
return errors.New("no valid machine image provider detected")
|
||||||
|
}
|
||||||
|
|
||||||
|
type machineImage interface { //nolint:unused
|
||||||
|
download() error
|
||||||
|
path() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ociMachineImage struct {
|
||||||
|
// registry
|
||||||
|
// TODO JSON serial/deserial will write string to disk
|
||||||
|
// but in code it is a types.ImageReference
|
||||||
|
|
||||||
|
// quay.io/podman/podman-machine-image:5.0
|
||||||
|
FQImageReference string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ociMachineImage) path() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ociMachineImage) download() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fcosMachineImage struct {
|
||||||
|
// TODO JSON serial/deserial will write string to disk
|
||||||
|
// but in code is url.URL
|
||||||
|
Location url.URL // file://path/.qcow2 https://path/qcow2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fcosMachineImage) download() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fcosMachineImage) path() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostUser describes the host user
|
||||||
|
type HostUser struct {
|
||||||
|
// Whether this machine should run in a rootful or rootless manner
|
||||||
|
Rootful bool
|
||||||
|
// UID is the numerical id of the user that called machine
|
||||||
|
UID int
|
||||||
|
// Whether one of these fields has changed and actions should be taken
|
||||||
|
Modified bool `json:"HostUserModified"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mount struct {
|
||||||
|
ReadOnly bool
|
||||||
|
Source string
|
||||||
|
Tag string
|
||||||
|
Target string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceConfig describes physical attributes of the machine
|
||||||
|
type ResourceConfig struct {
|
||||||
|
// CPUs to be assigned to the VM
|
||||||
|
CPUs uint64
|
||||||
|
// Disk size in gigabytes assigned to the vm
|
||||||
|
DiskSize uint64
|
||||||
|
// Memory in megabytes assigned to the vm
|
||||||
|
Memory uint64
|
||||||
|
// Usbs
|
||||||
|
USBs []command.USBConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSHConfig contains remote access information for SSH
|
||||||
|
type SSHConfig struct {
|
||||||
|
// IdentityPath is the fq path to the ssh priv key
|
||||||
|
IdentityPath string
|
||||||
|
// SSH port for user networking
|
||||||
|
Port int
|
||||||
|
// RemoteUsername of the vm user
|
||||||
|
RemoteUsername string
|
||||||
|
}
|
||||||
|
|
||||||
|
type VMStats struct {
|
||||||
|
// 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
|
||||||
|
}
|
15
pkg/machine/vmconfigs/config_darwin.go
Normal file
15
pkg/machine/vmconfigs/config_darwin.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package vmconfigs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/applehv/vfkit"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AppleHVConfig struct {
|
||||||
|
// The VFKit endpoint where we can interact with the VM
|
||||||
|
Vfkit vfkit.VfkitHelper
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stubs
|
||||||
|
type HyperVConfig struct{}
|
||||||
|
type WSLConfig struct{}
|
||||||
|
type QEMUConfig struct{}
|
7
pkg/machine/vmconfigs/config_freebsd.go
Normal file
7
pkg/machine/vmconfigs/config_freebsd.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package vmconfigs
|
||||||
|
|
||||||
|
// Stubs
|
||||||
|
type HyperVConfig struct{}
|
||||||
|
type WSLConfig struct {}
|
||||||
|
type QEMUConfig struct {}
|
||||||
|
type AppleHVConfig struct {}
|
14
pkg/machine/vmconfigs/config_linux.go
Normal file
14
pkg/machine/vmconfigs/config_linux.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package vmconfigs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/qemu/command"
|
||||||
|
)
|
||||||
|
|
||||||
|
type QEMUConfig struct {
|
||||||
|
cmd command.QemuCmd //nolint:unused
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stubs
|
||||||
|
type AppleHVConfig struct{}
|
||||||
|
type HyperVConfig struct{}
|
||||||
|
type WSLConfig struct{}
|
21
pkg/machine/vmconfigs/config_windows.go
Normal file
21
pkg/machine/vmconfigs/config_windows.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package vmconfigs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/hyperv/vsock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HyperVConfig struct {
|
||||||
|
// NetworkVSock is for the user networking
|
||||||
|
NetworkHVSock vsock.HVSockRegistryEntry
|
||||||
|
// MountVsocks contains the currently-active vsocks, mapped to the
|
||||||
|
// directory they should be mounted on.
|
||||||
|
MountVsocks map[string]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type WSLConfig struct {
|
||||||
|
wslstuff *aThing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stubs
|
||||||
|
type QEMUConfig struct{}
|
||||||
|
type AppleHVConfig struct{}
|
@ -2,6 +2,8 @@ package machine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Volume interface {
|
type Volume interface {
|
||||||
@ -37,8 +39,8 @@ func (v VirtIoFs) unitName() string {
|
|||||||
return unit
|
return unit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v VirtIoFs) ToMount() Mount {
|
func (v VirtIoFs) ToMount() vmconfigs.Mount {
|
||||||
return Mount{
|
return vmconfigs.Mount{
|
||||||
ReadOnly: v.ReadOnly,
|
ReadOnly: v.ReadOnly,
|
||||||
Source: v.Source,
|
Source: v.Source,
|
||||||
Tag: v.Tag,
|
Tag: v.Tag,
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/containers/podman/v4/pkg/machine/define"
|
"github.com/containers/podman/v4/pkg/machine/define"
|
||||||
|
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
|
||||||
"github.com/containers/podman/v4/pkg/machine/wsl/wutil"
|
"github.com/containers/podman/v4/pkg/machine/wsl/wutil"
|
||||||
"github.com/containers/podman/v4/pkg/util"
|
"github.com/containers/podman/v4/pkg/util"
|
||||||
"github.com/containers/podman/v4/utils"
|
"github.com/containers/podman/v4/utils"
|
||||||
@ -298,7 +299,7 @@ type MachineVM struct {
|
|||||||
// Whether this machine should run in a rootful or rootless manner
|
// Whether this machine should run in a rootful or rootless manner
|
||||||
Rootful bool
|
Rootful bool
|
||||||
// SSH identity, username, etc
|
// SSH identity, username, etc
|
||||||
machine.SSHConfig
|
vmconfigs.SSHConfig
|
||||||
// machine version
|
// machine version
|
||||||
Version int
|
Version int
|
||||||
// Whether to use user-mode networking
|
// Whether to use user-mode networking
|
||||||
@ -1526,12 +1527,12 @@ func unregisterDist(dist string) error {
|
|||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) State(bypass bool) (machine.Status, error) {
|
func (v *MachineVM) State(bypass bool) (define.Status, error) {
|
||||||
if v.isRunning() {
|
if v.isRunning() {
|
||||||
return machine.Running, nil
|
return define.Running, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return machine.Stopped, nil
|
return define.Stopped, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopWinProxy(v *MachineVM) error {
|
func stopWinProxy(v *MachineVM) error {
|
||||||
@ -1808,7 +1809,7 @@ func (v *MachineVM) Inspect() (*machine.InspectInfo, error) {
|
|||||||
machinePipe := toDist(v.Name)
|
machinePipe := toDist(v.Name)
|
||||||
connInfo.PodmanPipe = &define.VMFile{Path: `\\.\pipe\` + machinePipe}
|
connInfo.PodmanPipe = &define.VMFile{Path: `\\.\pipe\` + machinePipe}
|
||||||
|
|
||||||
created, lastUp, _ := v.updateTimeStamps(state == machine.Running)
|
created, lastUp, _ := v.updateTimeStamps(state == define.Running)
|
||||||
return &machine.InspectInfo{
|
return &machine.InspectInfo{
|
||||||
ConfigPath: define.VMFile{Path: v.ConfigPath},
|
ConfigPath: define.VMFile{Path: v.ConfigPath},
|
||||||
ConnectionInfo: *connInfo,
|
ConnectionInfo: *connInfo,
|
||||||
@ -1827,7 +1828,7 @@ func (v *MachineVM) Inspect() (*machine.InspectInfo, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) getResources() (resources machine.ResourceConfig) {
|
func (v *MachineVM) getResources() (resources vmconfigs.ResourceConfig) {
|
||||||
resources.CPUs, _ = getCPUs(v)
|
resources.CPUs, _ = getCPUs(v)
|
||||||
resources.Memory, _ = getMem(v)
|
resources.Memory, _ = getMem(v)
|
||||||
resources.DiskSize = getDiskSize(v)
|
resources.DiskSize = getDiskSize(v)
|
||||||
|
Reference in New Issue
Block a user