144 lines
3.6 KiB
Go
144 lines
3.6 KiB
Go
// +build amd64,linux arm64,linux amd64,darwin arm64,darwin
|
|
|
|
package machine
|
|
|
|
import (
|
|
"os"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/containers/common/pkg/completion"
|
|
"github.com/containers/common/pkg/config"
|
|
"github.com/containers/common/pkg/report"
|
|
"github.com/containers/podman/v3/cmd/podman/registry"
|
|
"github.com/containers/podman/v3/cmd/podman/validate"
|
|
"github.com/containers/podman/v3/pkg/machine"
|
|
"github.com/containers/podman/v3/pkg/machine/qemu"
|
|
"github.com/docker/go-units"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
lsCmd = &cobra.Command{
|
|
Use: "list [options]",
|
|
Aliases: []string{"ls"},
|
|
Short: "List machines",
|
|
Long: "List managed virtual machines.",
|
|
RunE: list,
|
|
Args: validate.NoArgs,
|
|
ValidArgsFunction: completion.AutocompleteNone,
|
|
Example: `podman machine list,
|
|
podman machine ls`,
|
|
}
|
|
listFlag = listFlagType{}
|
|
)
|
|
|
|
type listFlagType struct {
|
|
format string
|
|
noHeading bool
|
|
}
|
|
|
|
type machineReporter struct {
|
|
Name string
|
|
Created string
|
|
LastUp string
|
|
VMType string
|
|
}
|
|
|
|
func init() {
|
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
|
Command: lsCmd,
|
|
Parent: machineCmd,
|
|
})
|
|
|
|
flags := lsCmd.Flags()
|
|
formatFlagName := "format"
|
|
flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\n", "Format volume output using Go template")
|
|
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone)
|
|
flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers")
|
|
}
|
|
|
|
func list(cmd *cobra.Command, args []string) error {
|
|
var opts machine.ListOptions
|
|
// We only have qemu VM's for now
|
|
listResponse, err := qemu.List(opts)
|
|
if err != nil {
|
|
return errors.Wrap(err, "error listing vms")
|
|
}
|
|
|
|
// 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
|
|
})
|
|
machineReporter, err := toHumanFormat(listResponse)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return outputTemplate(cmd, machineReporter)
|
|
}
|
|
|
|
func outputTemplate(cmd *cobra.Command, responses []*machineReporter) error {
|
|
headers := report.Headers(machineReporter{}, map[string]string{
|
|
"LastUp": "LAST UP",
|
|
"VmType": "VM TYPE",
|
|
})
|
|
|
|
row := report.NormalizeFormat(listFlag.format)
|
|
format := report.EnforceRange(row)
|
|
|
|
tmpl, err := report.NewTemplate("list").Parse(format)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
w, err := report.NewWriterDefault(os.Stdout)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer w.Flush()
|
|
|
|
if cmd.Flags().Changed("format") && !report.HasTable(listFlag.format) {
|
|
listFlag.noHeading = true
|
|
}
|
|
|
|
if !listFlag.noHeading {
|
|
if err := tmpl.Execute(w, headers); err != nil {
|
|
return errors.Wrapf(err, "failed to write report column headers")
|
|
}
|
|
}
|
|
return tmpl.Execute(w, responses)
|
|
}
|
|
|
|
func toHumanFormat(vms []*machine.ListResponse) ([]*machineReporter, error) {
|
|
cfg, err := config.ReadCustomConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
humanResponses := make([]*machineReporter, 0, len(vms))
|
|
for _, vm := range vms {
|
|
response := new(machineReporter)
|
|
if vm.Name == cfg.Engine.ActiveService {
|
|
response.Name = vm.Name + "*"
|
|
} else {
|
|
response.Name = vm.Name
|
|
}
|
|
if vm.Running {
|
|
response.LastUp = "Currently running"
|
|
} else {
|
|
response.LastUp = units.HumanDuration(time.Since(vm.LastUp)) + " ago"
|
|
}
|
|
response.Created = units.HumanDuration(time.Since(vm.CreatedAt)) + " ago"
|
|
response.VMType = vm.VMType
|
|
|
|
humanResponses = append(humanResponses, response)
|
|
}
|
|
return humanResponses, nil
|
|
}
|