From 7bac40ae3e2087cb12ce08c057e95a81482f7752 Mon Sep 17 00:00:00 2001 From: Pasha Sviderski Date: Wed, 17 Jun 2026 15:46:27 +1000 Subject: [PATCH] client: refactor ListImages to return an error per machine --- cmd/uncloud/image/ls.go | 6 ++++++ pkg/api/image.go | 10 ++++++++++ pkg/client/image.go | 16 +++++----------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/cmd/uncloud/image/ls.go b/cmd/uncloud/image/ls.go index a0847bde..7c3edb6e 100644 --- a/cmd/uncloud/image/ls.go +++ b/cmd/uncloud/image/ls.go @@ -102,6 +102,12 @@ func list(ctx context.Context, uncli *cli.CLI, opts listOptions) error { var rows []imageRow for _, machineImages := range clusterImages { + if err := machineImages.Error(); err != nil { + tui.PrintWarning(fmt.Sprintf("failed to list images on machine '%s': %s", + machineImages.Metadata.MachineName, err)) + continue + } + // Get machine name for better readability. machineName := machineImages.Metadata.MachineName diff --git a/pkg/api/image.go b/pkg/api/image.go index e7040a7e..69f7bd63 100644 --- a/pkg/api/image.go +++ b/pkg/api/image.go @@ -1,6 +1,8 @@ package api import ( + "errors" + "github.com/distribution/reference" "github.com/docker/docker/api/types/image" v1 "github.com/opencontainers/image-spec/specs-go/v1" @@ -22,6 +24,14 @@ type MachineImages struct { ContainerdStore bool } +// Error returns a non-nil error if listing images on this machine failed. +func (mi MachineImages) Error() error { + if mi.Metadata != nil && mi.Metadata.Error != "" { + return errors.New(mi.Metadata.Error) + } + return nil +} + // ImageFilter defines criteria to filter images in ListImages. type ImageFilter struct { // Machines filters images to those present on the specified machines (names or IDs). diff --git a/pkg/client/image.go b/pkg/client/image.go index dd93ac63..4395141e 100644 --- a/pkg/client/image.go +++ b/pkg/client/image.go @@ -87,21 +87,12 @@ func (cli *Client) ListImages(ctx context.Context, filter api.ImageFilter) ([]ap continue } - if msg.Metadata.Error != "" { - // Continue processing other messages even if some machines return an error to avoid a partial failure - // of the entire command. - tui.PrintWarning(fmt.Sprintf( - "failed to list images on machine %s: %s", msg.Metadata.MachineName, msg.Metadata.Error, - )) - continue - } - mi := api.MachineImages{ Metadata: msg.Metadata, ContainerdStore: msg.ContainerdStore, } - if len(msg.Images) > 0 { + if msg.Metadata.Error == "" && len(msg.Images) > 0 { if err = json.Unmarshal(msg.Images, &mi.Images); err != nil { return nil, fmt.Errorf("unmarshal images: %w", err) } @@ -223,12 +214,15 @@ func (cli *Client) pushImageToMachine( Machines: []string{machine.Id}, Name: "%invalid-name-to-only-check-store-type%", }) + if err == nil { + err = images[0].Error() + } if err != nil { return fmt.Errorf("check Docker image store type on machine '%s': %w", machine.Name, err) } // Only support Docker with containerd image store enabled to avoid the confusion of pushing images to containerd - // and then not being able to see and use them in Docker. + // and then not being able to use them in Docker. if !images[0].ContainerdStore { pw.Event(progress.NewEvent(pushEventID, progress.Error, "containerd image store required")) return fmt.Errorf("docker on machine '%s' is not using containerd image store, "+