From aa8b830745858a5c3a59d78cd391045271a6d602 Mon Sep 17 00:00:00 2001 From: Kathryn Baldauf Date: Mon, 12 Oct 2026 16:51:56 -0700 Subject: [PATCH] K8s image load fix fqn tagging (#2384) - The k8s load-image CLI command will issue a ctr image tag command in the guest to make the fully qualified name of an image available when the image has a short name (such as when building and testing locally). The ordering of fully qualified name and source image name was backwards, causing the command to silently fail. Signed-off-by: Kathryn Baldauf --- .../ContainerK8s/Commands/K8sLoadImage.swift | 2 +- .../K8s/TestK8sLoadImageSerial.swift | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Sources/ContainerK8s/Commands/K8sLoadImage.swift b/Sources/ContainerK8s/Commands/K8sLoadImage.swift index 800daac6..a4216acf 100644 --- a/Sources/ContainerK8s/Commands/K8sLoadImage.swift +++ b/Sources/ContainerK8s/Commands/K8sLoadImage.swift @@ -150,7 +150,7 @@ public struct K8sLoadImage: AsyncParsableCommand { log.info("Tagging image for kubelet", metadata: ["short": "\(image)", "fq": "\(fq)", "target": "\(target)"]) let tagConfig = ProcessConfiguration( executable: Self.ctrPath, - arguments: ["--namespace", "k8s.io", "images", "tag", fq, image], + arguments: ["--namespace", "k8s.io", "images", "tag", "--force", image, fq], environment: [], terminal: false ) diff --git a/Tests/IntegrationTests/K8s/TestK8sLoadImageSerial.swift b/Tests/IntegrationTests/K8s/TestK8sLoadImageSerial.swift index 3320e76e..760b1bdd 100644 --- a/Tests/IntegrationTests/K8s/TestK8sLoadImageSerial.swift +++ b/Tests/IntegrationTests/K8s/TestK8sLoadImageSerial.swift @@ -78,4 +78,27 @@ struct TestK8sLoadImageSerial { #expect(try imageExistsInNode(f, node: name, image: "alpine")) } } + + @Test func testLoadShortNameImageIsFullyQualifiedInNode() async throws { + try await ContainerFixture.with { f in + let name = "k8s-\(f.testID)" + let shortName = "short-\(f.testID):latest" + f.addCleanup { + _ = try? f.run(["k8s", "delete", "--name", name]) + _ = try? f.run(["image", "delete", shortName]) + } + + try f.restoreWarmupImage(.kindestNodeV1_35_5) + try f.run(["k8s", "create", "--name", name]).check() + + try f.restoreWarmupImage(.alpine320) + try f.run(["image", "tag", Self.testImage, shortName]).check() + + let loadResult = try f.run(["k8s", "load-image", "--name", name, shortName]) + #expect(loadResult.status == 0) + + // kubelet resolves a short name to docker.io/library/. + #expect(try imageExistsInNode(f, node: name, image: "docker.io/library/\(shortName)")) + } + } }