mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-08-07 09:25:43 +00:00
After creating a podman machine, and before starting it, the LastUp value for podman machine ls should display Never. Previously, the LastUp value was the same as creation time. This also changes the LastUp value for inspect to ZeroTime instead of creation time. Signed-off-by: Ashley Cui <acui@redhat.com>
223 lines
5.8 KiB
Go
223 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
|
|
}
|