Skip to content

fix(image-import): report import failures instead of printing success - #1694

Open
TheSaifZaman wants to merge 2 commits into
k3d-io:mainfrom
TheSaifZaman:fix/1484-image-import-error-propagation
Open

fix(image-import): report import failures instead of printing success#1694
TheSaifZaman wants to merge 2 commits into
k3d-io:mainfrom
TheSaifZaman:fix/1484-image-import-error-propagation

Conversation

@TheSaifZaman

Copy link
Copy Markdown

What

k3d image import prints Successfully imported image(s) and exits 0 even when the import failed on every node. This PR makes the failures surface, and fixes a related bug on the stdin path found while writing the tests.

Fixes #1484

Why

importWithToolsNode logged its errors but always returned nil, so ImageImportIntoClusterMulti fell through to the success message. Two paths were losing errors:

  1. Per-node import — the ctr image import calls ran in a bare sync.WaitGroup goroutine whose error was only passed to l.Log().Errorf. Nothing propagated it.
  2. Tarball copy — a failed CopyToNode logged and continued, so a tarball that never reached the tools node was silently skipped. If it was the only tarball, the import loop then had nothing to do and still reported success.

This matters most in CI/automation, where the reported exit code is the only signal. Two users on the issue describe hitting it intermittently (roughly 1 run in 10) and working around it with --mode=direct.

Changes

Commit 1 — fix(image-import): report failures instead of printing success

  • per-node imports now run in an errgroup.Group instead of a sync.WaitGroup, so a failure is returned
  • failed tarball copies are recorded, while still continuing with the remaining tarballs
  • collected errors are returned only after the tarball removal and tools-node cleanup have run, so a failed import doesn't leak resources
  • per-node errors are still logged individually, so all failures stay visible and not just the first one returned

Commit 2 — fix(image-import): don't report failure when reading from stdin succeeds

The stdin branch wrapped its result unconditionally:

err := loadImageFromStream(ctx, runtime, os.Stdin, cluster, []string{"stdin"})
return fmt.Errorf("failed to load image to cluster from stdin: %v", err)

so k3d image import - returned an error on every run, including successful ones — literally failed to load image to cluster from stdin: %!v(<nil>). It's the mirror image of the bug above and sits three lines away, so I fixed it here; happy to split it into its own PR if you'd rather keep this focused.

Tests

New pkg/client/tools_import_test.go covering all three behaviours, each confirmed to fail against the unfixed code first:

  • Test_importWithToolsNode_returnsErrorWhenImportIntoNodeFails
  • Test_importWithToolsNode_returnsErrorWhenTarballCopyFails
  • Test_ImageImportIntoClusterMulti_succeedsWhenReadingImageFromStdin

They use a fakeToolsRuntime that embeds runtimes.Runtime and overrides only the five methods this path touches, following the existing FakeRuntimeImageGetter pattern in tools_test.go. Any unexpected runtime call panics rather than silently passing.

go test ./... passes; gofmt and go vet are clean on both files. I wasn't able to run golangci-lint locally, so please let CI be the judge there.

Note for reviewers

While writing the stdin test I hit a pre-existing issue that is not addressed here: loadImageFromStream never closes its pipe writers, so a consumer that reads to EOF blocks forever. It doesn't deadlock in production only because the real ExecInNodeWithStdin returns when the exec exits. The fake reads a single chunk to work around it (see the comment there). Worth a separate issue if you agree it's a problem.

`k3d image import` logged per-node import failures and tarball copy
failures, but discarded them: `importWithToolsNode` always returned nil,
so the caller went on to print "Successfully imported image(s)" and exit
with code 0. Automation had no way to detect a failed import.

Two paths were losing errors:

- the per-node `ctr image import` goroutines ran in a bare WaitGroup and
  only logged their error. They now run in an errgroup that returns it.
- a failed `CopyToNode` for an image tarball logged and `continue`d. It
  now records the error and still continues with the remaining tarballs.

Errors are collected and returned only after the tarball and tools node
cleanup has run, so a failed import does not leave resources behind.
Per-node failures are still logged individually so that all of them stay
visible, not just the first one returned.

Fixes k3d-io#1484
The stdin branch of `ImageImportIntoClusterMulti` wrapped the result of
`loadImageFromStream` unconditionally, so `k3d image import -` returned
an error on every invocation, including successful ones:

    failed to load image to cluster from stdin: %!v(<nil>)

Only return an error when one actually occurred, and log the same
success message as the other import paths. The cause is now wrapped with
%w so that callers can unwrap it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] k3d image import: prints out success message even if it fails

1 participant