224 lines
5.8 KiB
Go
224 lines
5.8 KiB
Go
//go:build amd64 || arm64
|
|
// +build amd64 arm64
|
|
|
|
package machine
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"sort"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/containers/common/pkg/completion"
|
|
"github.com/containers/common/pkg/config"
|
|
"github.com/containers/common/pkg/report"
|
|
"github.com/containers/podman/v4/cmd/podman/common"
|
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
|
"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/docker/go-units"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
lsCmd = &cobra.Command{
|
|
Use: "list [options]",
|
|
Aliases: []string{"ls"},
|
|
Short: "List machines",
|
|
Long: "List managed virtual machines.",
|
|
PersistentPreRunE: machinePreRunE,
|
|
RunE: list,
|
|
Args: validate.NoArgs,
|
|
ValidArgsFunction: completion.AutocompleteNone,
|
|
Example: `podman machine list,
|
|
podman machine list --format json
|
|
podman machine ls`,
|
|
}
|
|
listFlag = listFlagType{}
|
|
)
|
|
|
|
type listFlagType struct {
|
|
format string
|
|
noHeading bool
|
|
quiet bool
|
|
}
|
|
|
|
func init() {
|
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
|
Command: lsCmd,
|
|
Parent: machineCmd,
|
|
})
|
|
|
|
flags := lsCmd.Flags()
|
|
formatFlagName := "format"
|
|
flags.StringVar(&listFlag.format, formatFlagName, "{{range .}}{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n{{end -}}", "Format volume output using JSON or a Go template")
|
|
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.ListReporter{}))
|
|
flags.BoolVarP(&listFlag.noHeading, "noheading", "n", false, "Do not print headers")
|
|
flags.BoolVarP(&listFlag.quiet, "quiet", "q", false, "Show only machine names")
|
|
}
|
|
|
|
func list(cmd *cobra.Command, args []string) error {
|
|
var (
|
|
opts machine.ListOptions
|
|
listResponse []*machine.ListResponse
|
|
err error
|
|
)
|
|
|
|
listResponse, err = provider.List(opts)
|
|
if err != nil {
|
|
return fmt.Errorf("listing vms: %w", err)
|
|
}
|
|
|
|
// Sort by last run
|
|
sort.Slice(listResponse, func(i, j int) bool {
|
|
return listResponse[i].LastUp.After(listResponse[j].LastUp)
|
|
})
|
|
// Bring currently running machines to top
|
|
sort.Slice(listResponse, func(i, j int) bool {
|
|
return listResponse[i].Running
|
|
})
|
|
|
|
if report.IsJSON(listFlag.format) {
|
|
machineReporter, err := toMachineFormat(listResponse)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
b, err := json.MarshalIndent(machineReporter, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
os.Stdout.Write(b)
|
|
return nil
|
|
}
|
|
|
|
machineReporter, err := toHumanFormat(listResponse)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return outputTemplate(cmd, machineReporter)
|
|
}
|
|
|
|
func outputTemplate(cmd *cobra.Command, responses []*entities.ListReporter) error {
|
|
headers := report.Headers(entities.ListReporter{}, map[string]string{
|
|
"LastUp": "LAST UP",
|
|
"VmType": "VM TYPE",
|
|
"CPUs": "CPUS",
|
|
"Memory": "MEMORY",
|
|
"DiskSize": "DISK SIZE",
|
|
})
|
|
|
|
rpt := report.New(os.Stdout, cmd.Name())
|
|
defer rpt.Flush()
|
|
|
|
var err error
|
|
switch {
|
|
case cmd.Flag("format").Changed:
|
|
rpt, err = rpt.Parse(report.OriginUser, listFlag.format)
|
|
case listFlag.quiet:
|
|
rpt, err = rpt.Parse(report.OriginUser, "{{.Name}}\n")
|
|
default:
|
|
rpt, err = rpt.Parse(report.OriginPodman, listFlag.format)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if rpt.RenderHeaders && !listFlag.noHeading {
|
|
if err := rpt.Execute(headers); err != nil {
|
|
return fmt.Errorf("failed to write report column headers: %w", err)
|
|
}
|
|
}
|
|
return rpt.Execute(responses)
|
|
}
|
|
|
|
func strTime(t time.Time) string {
|
|
iso, err := t.MarshalText()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return string(iso)
|
|
}
|
|
|
|
func strUint(u uint64) string {
|
|
return strconv.FormatUint(u, 10)
|
|
}
|
|
|
|
func streamName(imageStream string) string {
|
|
if imageStream == "" {
|
|
return "default"
|
|
}
|
|
return imageStream
|
|
}
|
|
|
|
func toMachineFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, error) {
|
|
cfg, err := config.ReadCustomConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
machineResponses := make([]*entities.ListReporter, 0, len(vms))
|
|
for _, vm := range vms {
|
|
response := new(entities.ListReporter)
|
|
response.Default = vm.Name == cfg.Engine.ActiveService
|
|
response.Name = vm.Name
|
|
response.Running = vm.Running
|
|
response.LastUp = strTime(vm.LastUp)
|
|
response.Created = strTime(vm.CreatedAt)
|
|
response.Stream = streamName(vm.Stream)
|
|
response.VMType = vm.VMType
|
|
response.CPUs = vm.CPUs
|
|
response.Memory = strUint(vm.Memory)
|
|
response.DiskSize = strUint(vm.DiskSize)
|
|
response.Port = vm.Port
|
|
response.RemoteUsername = vm.RemoteUsername
|
|
response.IdentityPath = vm.IdentityPath
|
|
response.Starting = vm.Starting
|
|
response.UserModeNetworking = vm.UserModeNetworking
|
|
|
|
machineResponses = append(machineResponses, response)
|
|
}
|
|
return machineResponses, nil
|
|
}
|
|
|
|
func toHumanFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, error) {
|
|
cfg, err := config.ReadCustomConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
humanResponses := make([]*entities.ListReporter, 0, len(vms))
|
|
for _, vm := range vms {
|
|
response := new(entities.ListReporter)
|
|
if vm.Name == cfg.Engine.ActiveService {
|
|
response.Name = vm.Name + "*"
|
|
response.Default = true
|
|
} else {
|
|
response.Name = vm.Name
|
|
}
|
|
switch {
|
|
case vm.Starting:
|
|
response.LastUp = "Currently starting"
|
|
response.Starting = true
|
|
case vm.Running:
|
|
response.LastUp = "Currently running"
|
|
response.Running = true
|
|
case vm.LastUp.IsZero():
|
|
response.LastUp = "Never"
|
|
default:
|
|
response.LastUp = units.HumanDuration(time.Since(vm.LastUp)) + " ago"
|
|
}
|
|
response.Created = units.HumanDuration(time.Since(vm.CreatedAt)) + " ago"
|
|
response.VMType = vm.VMType
|
|
response.CPUs = vm.CPUs
|
|
response.Memory = units.BytesSize(float64(vm.Memory))
|
|
response.DiskSize = units.BytesSize(float64(vm.DiskSize))
|
|
|
|
humanResponses = append(humanResponses, response)
|
|
}
|
|
return humanResponses, nil
|
|
}
|