summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrent Baude <bbaude@redhat.com>2022-04-01 15:31:13 -0500
committerBrent Baude <bbaude@redhat.com>2022-04-12 15:51:39 -0500
commit8710197e8592e9726d98d11d017d1c79ab07415b (patch)
treed3e1788912e4b1ac7d58e72d1a56cf0cbaf6a143
parentdb7cd88c6781c3d42376f02b5b1547c466c45d3e (diff)
downloadpodman-8710197e8592e9726d98d11d017d1c79ab07415b.tar.gz
podman-8710197e8592e9726d98d11d017d1c79ab07415b.tar.bz2
podman-8710197e8592e9726d98d11d017d1c79ab07415b.zip
Introduce machine inspect
Allow users to inspect their podman virtual machines. This will be helpful for debug and development alike, because more details about the machine can be collected. Signed-off-by: Brent Baude <bbaude@redhat.com> [NO NEW TESTS NEEDED] Signed-off-by: Brent Baude <bbaude@redhat.com>
-rw-r--r--cmd/podman/machine/inspect.go90
-rw-r--r--docs/source/markdown/podman-machine-inspect.1.md35
-rw-r--r--docs/source/markdown/podman-machine.1.md21
-rw-r--r--pkg/machine/config.go15
-rw-r--r--pkg/machine/qemu/machine.go50
-rw-r--r--pkg/machine/wsl/machine.go7
6 files changed, 174 insertions, 44 deletions
diff --git a/cmd/podman/machine/inspect.go b/cmd/podman/machine/inspect.go
new file mode 100644
index 000000000..d43cabf6b
--- /dev/null
+++ b/cmd/podman/machine/inspect.go
@@ -0,0 +1,90 @@
+//go:build amd64 || arm64
+// +build amd64 arm64
+
+package machine
+
+import (
+ "encoding/json"
+ "os"
+
+ "github.com/containers/podman/v4/cmd/podman/common"
+ "github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/cmd/podman/utils"
+ "github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/machine"
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+)
+
+var (
+ inspectCmd = &cobra.Command{
+ Use: "inspect [options] [MACHINE...]",
+ Short: "Inspect an existing machine",
+ Long: "Provide details on a managed virtual machine",
+ RunE: inspect,
+ Example: `podman machine inspect myvm`,
+ ValidArgsFunction: autocompleteMachine,
+ }
+ inspectFlag = inspectFlagType{}
+)
+
+type inspectFlagType struct {
+ format string
+}
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: inspectCmd,
+ Parent: machineCmd,
+ })
+
+ flags := inspectCmd.Flags()
+ formatFlagName := "format"
+ flags.StringVar(&inspectFlag.format, formatFlagName, "", "Format volume output using JSON or a Go template")
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(machine.InspectInfo{}))
+}
+
+func inspect(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ if len(args) < 1 {
+ args = append(args, defaultMachineName)
+ }
+ vms := make([]machine.InspectInfo, 0, len(args))
+ provider := getSystemDefaultProvider()
+ for _, vmName := range args {
+ vm, err := provider.LoadVMByName(vmName)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ state, err := vm.State()
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ ii := machine.InspectInfo{
+ State: state,
+ VM: vm,
+ }
+ vms = append(vms, ii)
+ }
+ if len(inspectFlag.format) > 0 {
+ // need jhonce to work his template magic
+ return define.ErrNotImplemented
+ }
+ if err := printJSON(vms); err != nil {
+ logrus.Error(err)
+ }
+ return errs.PrintErrors()
+}
+
+func printJSON(data []machine.InspectInfo) error {
+ enc := json.NewEncoder(os.Stdout)
+ // by default, json marshallers will force utf=8 from
+ // a string. this breaks healthchecks that use <,>, &&.
+ enc.SetEscapeHTML(false)
+ enc.SetIndent("", " ")
+ return enc.Encode(data)
+}
diff --git a/docs/source/markdown/podman-machine-inspect.1.md b/docs/source/markdown/podman-machine-inspect.1.md
new file mode 100644
index 000000000..38eb66b0d
--- /dev/null
+++ b/docs/source/markdown/podman-machine-inspect.1.md
@@ -0,0 +1,35 @@
+% podman-machine-inspect(1)
+
+## NAME
+podman\-machine\-inspect - Inspect one or more virtual machines
+
+## SYNOPSIS
+**podman machine inspect** [*options] *name* ...
+
+## DESCRIPTION
+
+Inspect one or more virtual machines
+
+Obtain greater detail about Podman virtual machines. More than one virtual machine can be
+inspected at once.
+
+## OPTIONS
+#### **--format**
+
+Print results with a Go template.
+
+#### **--help**
+
+Print usage statement.
+
+## EXAMPLES
+
+```
+$ podman machine inspect podman-machine-default
+```
+
+## SEE ALSO
+**[podman(1)](podman.1.md)**, **[podman-machine(1)](podman-machine.1.md)**
+
+## HISTORY
+April 2022, Originally compiled by Brent Baude <bbaude@redhat.com>
diff --git a/docs/source/markdown/podman-machine.1.md b/docs/source/markdown/podman-machine.1.md
index 3bdfd0be9..e9f6c7d20 100644
--- a/docs/source/markdown/podman-machine.1.md
+++ b/docs/source/markdown/podman-machine.1.md
@@ -11,18 +11,19 @@ podman\-machine - Manage Podman's virtual machine
## SUBCOMMANDS
-| Command | Man Page | Description |
-| ------- | ------------------------------------------------------- | --------------------------------- |
-| init | [podman-machine-init(1)](podman-machine-init.1.md) | Initialize a new virtual machine |
-| list | [podman-machine-list(1)](podman-machine-list.1.md) | List virtual machines |
-| rm | [podman-machine-rm(1)](podman-machine-rm.1.md) | Remove a virtual machine |
-| set | [podman-machine-set(1)](podman-machine-set.1.md) | Sets a virtual machine setting |
-| ssh | [podman-machine-ssh(1)](podman-machine-ssh.1.md) | SSH into a virtual machine |
-| start | [podman-machine-start(1)](podman-machine-start.1.md) | Start a virtual machine |
-| stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop a virtual machine |
+| Command | Man Page | Description |
+|---------|------------------------------------------------------|-----------------------------------|
+| init | [podman-machine-init(1)](podman-machine-init.1.md) | Initialize a new virtual machine |
+| inspect | [podman-machine-inspect(1)](podman-machine-inspect.1.md) | Inspect one or more virtual machines |
+| list | [podman-machine-list(1)](podman-machine-list.1.md) | List virtual machines |
+| rm | [podman-machine-rm(1)](podman-machine-rm.1.md) | Remove a virtual machine |
+| set | [podman-machine-set(1)](podman-machine-set.1.md) | Sets a virtual machine setting |
+| ssh | [podman-machine-ssh(1)](podman-machine-ssh.1.md) | SSH into a virtual machine |
+| start | [podman-machine-start(1)](podman-machine-start.1.md) | Start a virtual machine |
+| stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop a virtual machine |
## SEE ALSO
-**[podman(1)](podman.1.md)**, **[podman-machine-init(1)](podman-machine-init.1.md)**, **[podman-machine-list(1)](podman-machine-list.1.md)**, **[podman-machine-rm(1)](podman-machine-rm.1.md)**, **[podman-machine-ssh(1)](podman-machine-ssh.1.md)**, **[podman-machine-start(1)](podman-machine-start.1.md)**, **[podman-machine-stop(1)](podman-machine-stop.1.md)**
+**[podman(1)](podman.1.md)**, **[podman-machine-init(1)](podman-machine-init.1.md)**, **[podman-machine-list(1)](podman-machine-list.1.md)**, **[podman-machine-rm(1)](podman-machine-rm.1.md)**, **[podman-machine-ssh(1)](podman-machine-ssh.1.md)**, **[podman-machine-start(1)](podman-machine-start.1.md)**, **[podman-machine-stop(1)](podman-machine-stop.1.md)**, **[podman-machine-inspect(1)](podman-machine-inspect.1.md)**
## HISTORY
March 2021, Originally compiled by Ashley Cui <acui@redhat.com>
diff --git a/pkg/machine/config.go b/pkg/machine/config.go
index 7e1561506..6c2fab0e5 100644
--- a/pkg/machine/config.go
+++ b/pkg/machine/config.go
@@ -33,14 +33,14 @@ type InitOptions struct {
UID string
}
-type QemuMachineStatus = string
+type Status = string
const (
// Running indicates the qemu vm is running.
- Running QemuMachineStatus = "running"
+ Running Status = "running"
// Stopped indicates the vm has stopped.
- Stopped QemuMachineStatus = "stopped"
- DefaultMachineName string = "podman-machine-default"
+ Stopped Status = "stopped"
+ DefaultMachineName string = "podman-machine-default"
)
type Provider interface {
@@ -113,12 +113,15 @@ type RemoveOptions struct {
SaveIgnition bool
}
+type InspectOptions struct{}
+
type VM interface {
Init(opts InitOptions) (bool, error)
Remove(name string, opts RemoveOptions) (string, func() error, error)
Set(name string, opts SetOptions) error
SSH(name string, opts SSHOptions) error
Start(name string, opts StartOptions) error
+ State() (Status, error)
Stop(name string, opts StopOptions) error
}
@@ -126,6 +129,10 @@ type DistributionDownload interface {
HasUsableCache() (bool, error)
Get() *Download
}
+type InspectInfo struct {
+ State Status
+ VM
+}
func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url.URL {
//TODO Should this function have input verification?
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index 321c1b99c..a3dedeedb 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -439,12 +439,12 @@ func (v *MachineVM) Set(_ string, opts machine.SetOptions) error {
return nil
}
- running, err := v.isRunning()
+ state, err := v.State()
if err != nil {
return err
}
- if running {
+ if state == machine.Running {
suffix := ""
if v.Name != machine.DefaultMachineName {
suffix = " " + v.Name
@@ -581,14 +581,14 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
}
if len(v.Mounts) > 0 {
- running, err := v.isRunning()
+ state, err := v.State()
if err != nil {
return err
}
listening := v.isListening()
- for !running || !listening {
+ for state != machine.Running || !listening {
time.Sleep(100 * time.Millisecond)
- running, err = v.isRunning()
+ state, err = v.State()
if err != nil {
return err
}
@@ -634,7 +634,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
return nil
}
-func (v *MachineVM) checkStatus(monitor *qmp.SocketMonitor) (machine.QemuMachineStatus, error) {
+func (v *MachineVM) checkStatus(monitor *qmp.SocketMonitor) (machine.Status, error) {
// this is the format returned from the monitor
// {"return": {"status": "running", "singlestep": false, "running": true}}
@@ -748,11 +748,11 @@ func (v *MachineVM) Stop(_ string, _ machine.StopOptions) error {
disconnected = true
waitInternal := 250 * time.Millisecond
for i := 0; i < 5; i++ {
- running, err := v.isRunning()
+ state, err := v.State()
if err != nil {
return err
}
- if !running {
+ if state != machine.Running {
break
}
time.Sleep(waitInternal)
@@ -800,11 +800,11 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
)
// cannot remove a running vm unless --force is used
- running, err := v.isRunning()
+ state, err := v.State()
if err != nil {
return "", nil, err
}
- if running && !opts.Force {
+ if state == machine.Running && !opts.Force {
return "", nil, errors.Errorf("running vm %q cannot be destroyed", v.Name)
}
@@ -858,10 +858,7 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
confirmationMessage += "\n"
return confirmationMessage, func() error {
for _, f := range files {
- if err := os.Remove(f); err != nil {
- if errors.Is(err, os.ErrNotExist) {
- continue
- }
+ if err := os.Remove(f); err != nil && !errors.Is(err, os.ErrNotExist) {
logrus.Error(err)
}
}
@@ -869,19 +866,19 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
}, nil
}
-func (v *MachineVM) isRunning() (bool, error) {
+func (v *MachineVM) State() (machine.Status, error) {
// Check if qmp socket path exists
if _, err := os.Stat(v.QMPMonitor.Address.GetPath()); os.IsNotExist(err) {
- return false, nil
+ return "", nil
}
// Check if we can dial it
monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout)
if err != nil {
// FIXME: this error should probably be returned
- return false, nil // nolint: nilerr
+ return "", err
}
if err := monitor.Connect(); err != nil {
- return false, err
+ return "", err
}
defer func() {
if err := monitor.Disconnect(); err != nil {
@@ -889,14 +886,7 @@ func (v *MachineVM) isRunning() (bool, error) {
}
}()
// If there is a monitor, lets see if we can query state
- state, err := v.checkStatus(monitor)
- if err != nil {
- return false, err
- }
- if state == machine.Running {
- return true, nil
- }
- return false, nil
+ return v.checkStatus(monitor)
}
func (v *MachineVM) isListening() bool {
@@ -912,11 +902,11 @@ func (v *MachineVM) isListening() bool {
// SSH opens an interactive SSH session to the vm specified.
// Added ssh function to VM interface: pkg/machine/config/go : line 58
func (v *MachineVM) SSH(_ string, opts machine.SSHOptions) error {
- running, err := v.isRunning()
+ state, err := v.State()
if err != nil {
return err
}
- if !running {
+ if state != machine.Running {
return errors.Errorf("vm %q is not running.", v.Name)
}
@@ -1037,11 +1027,11 @@ func getVMInfos() ([]*machine.ListResponse, error) {
return err
}
listEntry.LastUp = fi.ModTime()
- running, err := vm.isRunning()
+ state, err := vm.State()
if err != nil {
return err
}
- if running {
+ if state == machine.Running {
listEntry.Running = true
}
diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go
index fdda45ca6..1da042f6a 100644
--- a/pkg/machine/wsl/machine.go
+++ b/pkg/machine/wsl/machine.go
@@ -18,6 +18,7 @@ import (
"strings"
"time"
+ "github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/homedir"
@@ -1013,6 +1014,12 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
return nil
}
+// TODO: We need to rename isRunning to State(); I do not have a
+// windows system to test this on.
+func (v *MachineVM) State() (machine.Status, error) {
+ return "", define.ErrNotImplemented
+}
+
func stopWinProxy(v *MachineVM) error {
pid, tid, tidFile, err := readWinProxyTid(v)
if err != nil {