a301dfb44f
slocker-lite validates an OCI Image Layout tar, imports its layers into containers-storage's layer store in order, and mounts the assembled image using fuse-overlayfs, printing the resulting merged path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
90 lines
2.7 KiB
Python
90 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Writes a minimal one-layer OCI Image Layout tar to the path given as argv[1].
|
|
|
|
Used by meson.build to produce a fixture for the `meson test` smoke test.
|
|
"""
|
|
|
|
import gzip
|
|
import hashlib
|
|
import io
|
|
import json
|
|
import sys
|
|
import tarfile
|
|
|
|
|
|
def sha256_hex(data: bytes) -> str:
|
|
return hashlib.sha256(data).hexdigest()
|
|
|
|
|
|
def add_bytes(tar: tarfile.TarFile, name: str, data: bytes) -> None:
|
|
info = tarfile.TarInfo(name=name)
|
|
info.size = len(data)
|
|
tar.addfile(info, io.BytesIO(data))
|
|
|
|
|
|
def main() -> None:
|
|
out_path = sys.argv[1]
|
|
|
|
# Uncompressed layer content: a tiny tar with a single file.
|
|
layer_tar_buf = io.BytesIO()
|
|
with tarfile.open(fileobj=layer_tar_buf, mode="w") as layer_tar:
|
|
add_bytes(layer_tar, "hello.txt", b"hello from slocker-lite fixture\n")
|
|
layer_tar_bytes = layer_tar_buf.getvalue()
|
|
diff_id = sha256_hex(layer_tar_bytes)
|
|
|
|
layer_gz_bytes = gzip.compress(layer_tar_bytes)
|
|
layer_digest = sha256_hex(layer_gz_bytes)
|
|
|
|
config = {
|
|
"architecture": "amd64",
|
|
"os": "linux",
|
|
"config": {},
|
|
"rootfs": {"type": "layers", "diff_ids": [f"sha256:{diff_id}"]},
|
|
}
|
|
config_bytes = json.dumps(config).encode()
|
|
config_digest = sha256_hex(config_bytes)
|
|
|
|
manifest = {
|
|
"schemaVersion": 2,
|
|
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
|
"config": {
|
|
"mediaType": "application/vnd.oci.image.config.v1+json",
|
|
"digest": f"sha256:{config_digest}",
|
|
"size": len(config_bytes),
|
|
},
|
|
"layers": [
|
|
{
|
|
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
|
"digest": f"sha256:{layer_digest}",
|
|
"size": len(layer_gz_bytes),
|
|
}
|
|
],
|
|
}
|
|
manifest_bytes = json.dumps(manifest).encode()
|
|
manifest_digest = sha256_hex(manifest_bytes)
|
|
|
|
index = {
|
|
"schemaVersion": 2,
|
|
"manifests": [
|
|
{
|
|
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
|
"digest": f"sha256:{manifest_digest}",
|
|
"size": len(manifest_bytes),
|
|
}
|
|
],
|
|
}
|
|
index_bytes = json.dumps(index).encode()
|
|
|
|
oci_layout_bytes = json.dumps({"imageLayoutVersion": "1.0.0"}).encode()
|
|
|
|
with tarfile.open(out_path, mode="w") as tar:
|
|
add_bytes(tar, "oci-layout", oci_layout_bytes)
|
|
add_bytes(tar, "index.json", index_bytes)
|
|
add_bytes(tar, f"blobs/sha256/{config_digest}", config_bytes)
|
|
add_bytes(tar, f"blobs/sha256/{manifest_digest}", manifest_bytes)
|
|
add_bytes(tar, f"blobs/sha256/{layer_digest}", layer_gz_bytes)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|