mirror of
https://github.com/containers/podman.git
synced 2025-06-20 17:13:43 +08:00
Merge pull request #14850 from Luap99/e2e-machine
pkg/machine/e2e: do not import from cmd/podman
This commit is contained in:
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/containers/podman/v4/cmd/podman/common"
|
"github.com/containers/podman/v4/cmd/podman/common"
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v4/cmd/podman/validate"
|
"github.com/containers/podman/v4/cmd/podman/validate"
|
||||||
|
"github.com/containers/podman/v4/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -44,23 +45,6 @@ type listFlagType struct {
|
|||||||
quiet bool
|
quiet bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListReporter struct {
|
|
||||||
Name string
|
|
||||||
Default bool
|
|
||||||
Created string
|
|
||||||
Running bool
|
|
||||||
Starting bool
|
|
||||||
LastUp string
|
|
||||||
Stream string
|
|
||||||
VMType string
|
|
||||||
CPUs uint64
|
|
||||||
Memory string
|
|
||||||
DiskSize string
|
|
||||||
Port int
|
|
||||||
RemoteUsername string
|
|
||||||
IdentityPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||||
Command: lsCmd,
|
Command: lsCmd,
|
||||||
@ -70,7 +54,7 @@ func init() {
|
|||||||
flags := lsCmd.Flags()
|
flags := lsCmd.Flags()
|
||||||
formatFlagName := "format"
|
formatFlagName := "format"
|
||||||
flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n", "Format volume output using JSON or a Go template")
|
flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n", "Format volume output using JSON or a Go template")
|
||||||
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&ListReporter{}))
|
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.ListReporter{}))
|
||||||
flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers")
|
flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers")
|
||||||
flags.BoolVarP(&listFlag.quiet, "quiet", "q", false, "Show only machine names")
|
flags.BoolVarP(&listFlag.quiet, "quiet", "q", false, "Show only machine names")
|
||||||
}
|
}
|
||||||
@ -123,8 +107,8 @@ func list(cmd *cobra.Command, args []string) error {
|
|||||||
return outputTemplate(cmd, machineReporter)
|
return outputTemplate(cmd, machineReporter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func outputTemplate(cmd *cobra.Command, responses []*ListReporter) error {
|
func outputTemplate(cmd *cobra.Command, responses []*entities.ListReporter) error {
|
||||||
headers := report.Headers(ListReporter{}, map[string]string{
|
headers := report.Headers(entities.ListReporter{}, map[string]string{
|
||||||
"LastUp": "LAST UP",
|
"LastUp": "LAST UP",
|
||||||
"VmType": "VM TYPE",
|
"VmType": "VM TYPE",
|
||||||
"CPUs": "CPUS",
|
"CPUs": "CPUS",
|
||||||
@ -183,15 +167,15 @@ func streamName(imageStream string) string {
|
|||||||
return imageStream
|
return imageStream
|
||||||
}
|
}
|
||||||
|
|
||||||
func toMachineFormat(vms []*machine.ListResponse) ([]*ListReporter, error) {
|
func toMachineFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, error) {
|
||||||
cfg, err := config.ReadCustomConfig()
|
cfg, err := config.ReadCustomConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
machineResponses := make([]*ListReporter, 0, len(vms))
|
machineResponses := make([]*entities.ListReporter, 0, len(vms))
|
||||||
for _, vm := range vms {
|
for _, vm := range vms {
|
||||||
response := new(ListReporter)
|
response := new(entities.ListReporter)
|
||||||
response.Default = vm.Name == cfg.Engine.ActiveService
|
response.Default = vm.Name == cfg.Engine.ActiveService
|
||||||
response.Name = vm.Name
|
response.Name = vm.Name
|
||||||
response.Running = vm.Running
|
response.Running = vm.Running
|
||||||
@ -211,15 +195,15 @@ func toMachineFormat(vms []*machine.ListResponse) ([]*ListReporter, error) {
|
|||||||
return machineResponses, nil
|
return machineResponses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toHumanFormat(vms []*machine.ListResponse) ([]*ListReporter, error) {
|
func toHumanFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, error) {
|
||||||
cfg, err := config.ReadCustomConfig()
|
cfg, err := config.ReadCustomConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
humanResponses := make([]*ListReporter, 0, len(vms))
|
humanResponses := make([]*entities.ListReporter, 0, len(vms))
|
||||||
for _, vm := range vms {
|
for _, vm := range vms {
|
||||||
response := new(ListReporter)
|
response := new(entities.ListReporter)
|
||||||
if vm.Name == cfg.Engine.ActiveService {
|
if vm.Name == cfg.Engine.ActiveService {
|
||||||
response.Name = vm.Name + "*"
|
response.Name = vm.Name + "*"
|
||||||
response.Default = true
|
response.Default = true
|
||||||
|
18
pkg/domain/entities/machine.go
Normal file
18
pkg/domain/entities/machine.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package entities
|
||||||
|
|
||||||
|
type ListReporter struct {
|
||||||
|
Name string
|
||||||
|
Default bool
|
||||||
|
Created string
|
||||||
|
Running bool
|
||||||
|
Starting bool
|
||||||
|
LastUp string
|
||||||
|
Stream string
|
||||||
|
VMType string
|
||||||
|
CPUs uint64
|
||||||
|
Memory string
|
||||||
|
DiskSize string
|
||||||
|
Port int
|
||||||
|
RemoteUsername string
|
||||||
|
IdentityPath string
|
||||||
|
}
|
@ -2,9 +2,10 @@ package e2e
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/util"
|
"github.com/containers/common/pkg/util"
|
||||||
"github.com/containers/podman/v4/cmd/podman/machine"
|
"github.com/containers/podman/v4/pkg/domain/entities"
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
@ -87,7 +88,7 @@ var _ = Describe("podman machine list", func() {
|
|||||||
startSession, err := mb.setCmd(s).runWithoutWait()
|
startSession, err := mb.setCmd(s).runWithoutWait()
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
l := new(listMachine)
|
l := new(listMachine)
|
||||||
for { // needs to be infinite because we need to check if running when inspect returns to avoid race conditions.
|
for i := 0; i < 30; i++ {
|
||||||
listSession, err := mb.setCmd(l).run()
|
listSession, err := mb.setCmd(l).run()
|
||||||
Expect(listSession).To(Exit(0))
|
Expect(listSession).To(Exit(0))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
@ -96,6 +97,7 @@ var _ = Describe("podman machine list", func() {
|
|||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
}
|
}
|
||||||
Expect(startSession).To(Exit(0))
|
Expect(startSession).To(Exit(0))
|
||||||
listSession, err := mb.setCmd(l).run()
|
listSession, err := mb.setCmd(l).run()
|
||||||
@ -132,7 +134,7 @@ var _ = Describe("podman machine list", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(listSession2).To(Exit(0))
|
Expect(listSession2).To(Exit(0))
|
||||||
|
|
||||||
var listResponse []*machine.ListReporter
|
var listResponse []*entities.ListReporter
|
||||||
err = jsoniter.Unmarshal(listSession.Bytes(), &listResponse)
|
err = jsoniter.Unmarshal(listSession.Bytes(), &listResponse)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ package qemu
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -138,8 +139,10 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
|||||||
cmd = append(cmd, []string{
|
cmd = append(cmd, []string{
|
||||||
"-device", "virtio-serial",
|
"-device", "virtio-serial",
|
||||||
// qemu needs to establish the long name; other connections can use the symlink'd
|
// qemu needs to establish the long name; other connections can use the symlink'd
|
||||||
"-chardev", "socket,path=" + vm.ReadySocket.Path + ",server=on,wait=off,id=" + vm.Name + "_ready",
|
// Note both id and chardev start with an extra "a" because qemu requires that it
|
||||||
"-device", "virtserialport,chardev=" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0",
|
// starts with an letter but users can also use numbers
|
||||||
|
"-chardev", "socket,path=" + vm.ReadySocket.Path + ",server=on,wait=off,id=a" + vm.Name + "_ready",
|
||||||
|
"-device", "virtserialport,chardev=a" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0",
|
||||||
"-pidfile", vm.VMPidFilePath.GetPath()}...)
|
"-pidfile", vm.VMPidFilePath.GetPath()}...)
|
||||||
vm.CmdLine = cmd
|
vm.CmdLine = cmd
|
||||||
return vm, nil
|
return vm, nil
|
||||||
@ -571,15 +574,25 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||||||
files := []*os.File{dnr, dnw, dnw, fd}
|
files := []*os.File{dnr, dnw, dnw, fd}
|
||||||
attr.Files = files
|
attr.Files = files
|
||||||
logrus.Debug(v.CmdLine)
|
logrus.Debug(v.CmdLine)
|
||||||
cmd := v.CmdLine
|
cmdLine := v.CmdLine
|
||||||
|
|
||||||
// Disable graphic window when not in debug mode
|
// Disable graphic window when not in debug mode
|
||||||
// Done in start, so we're not suck with the debug level we used on init
|
// Done in start, so we're not suck with the debug level we used on init
|
||||||
if !logrus.IsLevelEnabled(logrus.DebugLevel) {
|
if !logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||||
cmd = append(cmd, "-display", "none")
|
cmdLine = append(cmdLine, "-display", "none")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = os.StartProcess(v.CmdLine[0], cmd, attr)
|
stderrBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
cmd := &exec.Cmd{
|
||||||
|
Args: cmdLine,
|
||||||
|
Path: cmdLine[0],
|
||||||
|
Stdin: dnr,
|
||||||
|
Stdout: dnw,
|
||||||
|
Stderr: stderrBuf,
|
||||||
|
ExtraFiles: []*os.File{fd},
|
||||||
|
}
|
||||||
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// check if qemu was not found
|
// check if qemu was not found
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
@ -590,15 +603,17 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cmd[0], err = cfg.FindHelperBinary(QemuCommand, true)
|
cmdLine[0], err = cfg.FindHelperBinary(QemuCommand, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = os.StartProcess(cmd[0], cmd, attr)
|
cmd.Path = cmdLine[0]
|
||||||
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to execute %q: %w", cmd, err)
|
return fmt.Errorf("unable to execute %q: %w", cmd, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
defer cmd.Process.Release() //nolint:errcheck
|
||||||
fmt.Println("Waiting for VM ...")
|
fmt.Println("Waiting for VM ...")
|
||||||
socketPath, err := getRuntimeDir()
|
socketPath, err := getRuntimeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -613,6 +628,16 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
// check if qemu is still alive
|
||||||
|
var status syscall.WaitStatus
|
||||||
|
pid, err := syscall.Wait4(cmd.Process.Pid, &status, syscall.WNOHANG, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read qemu process status: %w", err)
|
||||||
|
}
|
||||||
|
if pid > 0 {
|
||||||
|
// child exited
|
||||||
|
return fmt.Errorf("qemu exited unexpectedly with exit code %d, stderr: %s", status.ExitStatus(), stderrBuf.String())
|
||||||
|
}
|
||||||
time.Sleep(wait)
|
time.Sleep(wait)
|
||||||
wait++
|
wait++
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user