Skip to content

Commit

Permalink
Merge pull request containers#13829 from baude/machineinspect
Browse files Browse the repository at this point in the history
Introduce machine inspect
  • Loading branch information
openshift-merge-robot authored Apr 13, 2022
2 parents f6ce14b + 8710197 commit 78b6dcd
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 44 deletions.
90 changes: 90 additions & 0 deletions cmd/podman/machine/inspect.go
Original file line number Diff line number Diff line change
@@ -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)
}
35 changes: 35 additions & 0 deletions docs/source/markdown/podman-machine-inspect.1.md
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
21 changes: 11 additions & 10 deletions docs/source/markdown/podman-machine.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>
15 changes: 11 additions & 4 deletions pkg/machine/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -113,19 +113,26 @@ 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
}

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?
Expand Down
50 changes: 20 additions & 30 deletions pkg/machine/qemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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}}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -858,45 +858,35 @@ 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)
}
}
return nil
}, 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 {
logrus.Error(err)
}
}()
// 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 {
Expand All @@ -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)
}

Expand Down Expand Up @@ -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
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/machine/wsl/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 78b6dcd

Please sign in to comment.