From 786d235f7f4c8cd033e0238493cc8cd19e3dbbee Mon Sep 17 00:00:00 2001 From: Thales Maciel Date: Sat, 21 Mar 2026 22:21:47 -0300 Subject: [PATCH] Show image names in vm list and raise default memory Make `banger vm list` easier to scan by resolving each VM image ID back to the registered image name when that mapping is available, while still falling back to a short ID for unknown images. Raise the shared default VM memory from 1024 MiB to 2048 MiB so new VMs, CLI help, and daemon-side defaults all align on a 2 GiB baseline. Add CLI coverage for the image-name rendering path and validate the change with go test ./..., make build, `banger vm list`, and `banger vm create --help`. --- internal/cli/banger.go | 61 +++++++++++++++++++++++++++++----------- internal/cli/cli_test.go | 53 ++++++++++++++++++++++++++++++++++ internal/model/types.go | 2 +- 3 files changed, 98 insertions(+), 18 deletions(-) diff --git a/internal/cli/banger.go b/internal/cli/banger.go index 39601ac..0743c97 100644 --- a/internal/cli/banger.go +++ b/internal/cli/banger.go @@ -477,24 +477,11 @@ func newVMListCommand() *cobra.Command { if err != nil { return err } - w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 8, 2, ' ', 0) - fmt.Fprintln(w, "ID\tNAME\tSTATE\tIMAGE\tIP\tVCPU\tMEM\tDISK\tCREATED") - for _, vm := range result.VMs { - fmt.Fprintf( - w, - "%s\t%s\t%s\t%s\t%s\t%d\t%d MiB\t%s\t%s\n", - shortID(vm.ID), - vm.Name, - vm.State, - shortID(vm.ImageID), - vm.Runtime.GuestIP, - vm.Spec.VCPUCount, - vm.Spec.MemoryMiB, - model.FormatSizeBytes(vm.Spec.WorkDiskSizeBytes), - relativeTime(vm.CreatedAt), - ) + images, err := rpc.Call[api.ImageListResult](cmd.Context(), layout.SocketPath, "image.list", api.Empty{}) + if err != nil { + return err } - return w.Flush() + return printVMListTable(cmd.OutOrStdout(), result.VMs, imageNameIndex(images.Images)) }, } } @@ -1308,11 +1295,51 @@ func printVMSummary(out anyWriter, vm model.VMRecord) error { return err } +func printVMListTable(out anyWriter, vms []model.VMRecord, imageNames map[string]string) error { + w := tabwriter.NewWriter(out, 0, 8, 2, ' ', 0) + if _, err := fmt.Fprintln(w, "ID\tNAME\tSTATE\tIMAGE\tIP\tVCPU\tMEM\tDISK\tCREATED"); err != nil { + return err + } + for _, vm := range vms { + if _, err := fmt.Fprintf( + w, + "%s\t%s\t%s\t%s\t%s\t%d\t%d MiB\t%s\t%s\n", + shortID(vm.ID), + vm.Name, + vm.State, + vmImageLabel(vm.ImageID, imageNames), + vm.Runtime.GuestIP, + vm.Spec.VCPUCount, + vm.Spec.MemoryMiB, + model.FormatSizeBytes(vm.Spec.WorkDiskSizeBytes), + relativeTime(vm.CreatedAt), + ); err != nil { + return err + } + } + return w.Flush() +} + func printImageSummary(out anyWriter, image model.Image) error { _, err := fmt.Fprintf(out, "%s\t%s\t%t\t%s\n", shortID(image.ID), image.Name, image.Managed, image.RootfsPath) return err } +func imageNameIndex(images []model.Image) map[string]string { + index := make(map[string]string, len(images)) + for _, image := range images { + index[image.ID] = image.Name + } + return index +} + +func vmImageLabel(imageID string, imageNames map[string]string) string { + if name := strings.TrimSpace(imageNames[imageID]); name != "" { + return name + } + return shortID(imageID) +} + func printImageListTable(out anyWriter, images []model.Image) error { w := tabwriter.NewWriter(out, 0, 8, 2, ' ', 0) if _, err := fmt.Fprintln(w, "ID\tNAME\tMANAGED\tROOTFS SIZE\tCREATED"); err != nil { diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go index a515757..3ec9968 100644 --- a/internal/cli/cli_test.go +++ b/internal/cli/cli_test.go @@ -519,6 +519,59 @@ func TestPrintImageListTableShowsRootfsSizes(t *testing.T) { } } +func TestPrintVMListTableShowsImageNames(t *testing.T) { + var out bytes.Buffer + err := printVMListTable(&out, []model.VMRecord{ + { + ID: "0123456789abcdef", + Name: "alp-fast", + ImageID: "image-alpine-123456", + State: model.VMStateRunning, + CreatedAt: time.Now().Add(-1 * time.Hour), + Spec: model.VMSpec{ + VCPUCount: 2, + MemoryMiB: model.DefaultMemoryMiB, + WorkDiskSizeBytes: model.DefaultWorkDiskSize, + }, + Runtime: model.VMRuntime{GuestIP: "172.16.0.4"}, + }, + { + ID: "fedcba9876543210", + Name: "mystery", + ImageID: "abcdef1234567890", + State: model.VMStateStopped, + CreatedAt: time.Now().Add(-2 * time.Hour), + Spec: model.VMSpec{ + VCPUCount: 1, + MemoryMiB: 512, + WorkDiskSizeBytes: 4 * 1024 * 1024 * 1024, + }, + }, + }, map[string]string{ + "image-alpine-123456": "alpine", + }) + if err != nil { + t.Fatalf("printVMListTable() error = %v", err) + } + + output := out.String() + if !strings.Contains(output, "IMAGE") || !strings.Contains(output, "MEM") { + t.Fatalf("output = %q, want vm list headers", output) + } + if !strings.Contains(output, "alp-fast") || !strings.Contains(output, "alpine") { + t.Fatalf("output = %q, want resolved image name", output) + } + if strings.Contains(output, "image-alpine-123456") { + t.Fatalf("output = %q, should not include full image id when name is known", output) + } + if !strings.Contains(output, shortID("abcdef1234567890")) { + t.Fatalf("output = %q, want short image id fallback", output) + } + if !strings.Contains(output, fmt.Sprintf("%d MiB", model.DefaultMemoryMiB)) { + t.Fatalf("output = %q, want updated default memory display", output) + } +} + func TestPrintVMPortsTableSortsAndRendersURLEndpoints(t *testing.T) { result := api.VMPortsResult{ Name: "alpha", diff --git a/internal/model/types.go b/internal/model/types.go index f986505..0cfb904 100644 --- a/internal/model/types.go +++ b/internal/model/types.go @@ -17,7 +17,7 @@ const ( DefaultDNS = "1.1.1.1" DefaultSystemOverlaySize = 8 * 1024 * 1024 * 1024 DefaultWorkDiskSize = 8 * 1024 * 1024 * 1024 - DefaultMemoryMiB = 1024 + DefaultMemoryMiB = 2048 DefaultVCPUCount = 2 DefaultStatsPollInterval = 10 * time.Second DefaultStaleSweepInterval = 1 * time.Minute