Add tests/setup-tests.py: fetch a real busybox fixture for [net] tests
Idempotent: does nothing if images/busybox.tar already exists (your own unofficial build, or a previous fetch). Otherwise tries skopeo, then podman, then docker, in that order -- skopeo/podman both reliably produce a genuine OCI Image Layout tar; a plain `docker save` only does if the containerd image store happens to be enabled, so the result is verified (oci-layout/index.json actually present at the tar root) regardless of which tool produced it, falling through to the next option otherwise. Clear instructions + nonzero exit if none of the three are available and no fixture already exists. Verified the no-op (already-present) path and the no-tools-available error path directly (temporarily moved the existing images/busybox.tar aside and back) -- this dev machine has none of skopeo/podman/docker installed, so the actual fetch path itself is unverified here; the format-verification step (looks_like_oci_layout()) is what protects against a `docker save` that produced the legacy Docker tar format on some other machine. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
Executable
+108
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fetches a real, runnable busybox OCI Image Layout tar for the
|
||||
[integration][net] test categories (tests/support/fixtures.h's
|
||||
find_busybox_fixture() looks for it at images/busybox.tar, relative to the
|
||||
repo root -- the same directory this project's own manual testing has
|
||||
always used, see CLAUDE.md).
|
||||
|
||||
Idempotent: if images/busybox.tar already exists (your own unofficial
|
||||
build, or a previously-fetched one), does nothing. Otherwise looks for
|
||||
skopeo, then podman, then docker, in that preference order -- skopeo and
|
||||
podman both reliably produce a genuine OCI Image Layout tar (what
|
||||
oci_image.cpp actually parses: oci-layout + index.json + blobs/sha256/*);
|
||||
a plain `docker save` only does if Docker's containerd image store happens
|
||||
to be enabled, so the result is verified either way before being accepted.
|
||||
"""
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
TARGET = REPO_ROOT / "images" / "busybox.tar"
|
||||
IMAGE = "docker.io/library/busybox:latest"
|
||||
|
||||
|
||||
def looks_like_oci_layout(path: Path) -> bool:
|
||||
try:
|
||||
with tarfile.open(path) as tar:
|
||||
names = set(tar.getnames())
|
||||
except tarfile.TarError:
|
||||
return False
|
||||
return "oci-layout" in names and "index.json" in names
|
||||
|
||||
|
||||
def fetch_with_skopeo() -> bool:
|
||||
print("fetching busybox via skopeo...")
|
||||
result = subprocess.run(
|
||||
["skopeo", "copy", f"docker://{IMAGE.removeprefix('docker.io/')}", f"oci-archive:{TARGET}:latest"]
|
||||
)
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
def fetch_with_podman() -> bool:
|
||||
print("fetching busybox via podman...")
|
||||
if subprocess.run(["podman", "pull", IMAGE]).returncode != 0:
|
||||
return False
|
||||
result = subprocess.run(["podman", "save", "--format", "oci-archive", "-o", str(TARGET), IMAGE])
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
def fetch_with_docker() -> bool:
|
||||
print("fetching busybox via docker (only works if the containerd image store is enabled)...")
|
||||
if subprocess.run(["docker", "pull", IMAGE]).returncode != 0:
|
||||
return False
|
||||
result = subprocess.run(["docker", "save", "-o", str(TARGET), IMAGE])
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if TARGET.exists():
|
||||
print(f"already present: {TARGET}")
|
||||
return 0
|
||||
|
||||
TARGET.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
fetchers = [
|
||||
("skopeo", fetch_with_skopeo),
|
||||
("podman", fetch_with_podman),
|
||||
("docker", fetch_with_docker),
|
||||
]
|
||||
for tool, fetch in fetchers:
|
||||
if not shutil.which(tool):
|
||||
continue
|
||||
try:
|
||||
ok = fetch()
|
||||
except OSError as exc:
|
||||
print(f"{tool} failed to run: {exc}", file=sys.stderr)
|
||||
ok = False
|
||||
if not ok:
|
||||
TARGET.unlink(missing_ok=True)
|
||||
print(f"{tool} was found but fetching busybox with it failed; trying the next option", file=sys.stderr)
|
||||
continue
|
||||
if not looks_like_oci_layout(TARGET):
|
||||
TARGET.unlink(missing_ok=True)
|
||||
print(
|
||||
f"{tool} produced {TARGET.name}, but it isn't a genuine OCI Image Layout tar "
|
||||
"(no oci-layout/index.json at its root) -- if that was docker, this usually means "
|
||||
"the containerd image store isn't enabled; trying the next option",
|
||||
file=sys.stderr,
|
||||
)
|
||||
continue
|
||||
print(f"fetched: {TARGET}")
|
||||
return 0
|
||||
|
||||
print(
|
||||
"no usable image tool found (checked skopeo, podman, docker) and "
|
||||
f"{TARGET} doesn't already exist.\n"
|
||||
"Install one of skopeo/podman/docker, or supply your own busybox-like "
|
||||
f"OCI Image Layout tar at {TARGET} directly.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user