From 035e0daebeb53880ea2a6bd0f0e31785f3ec9e55 Mon Sep 17 00:00:00 2001 From: Bruce Ashfield Date: Thu, 19 Feb 2026 01:53:36 +0000 Subject: vxn: add Docker/Podman integration and CLI frontends Add vdkr/vpdmn as Dom0 target packages with Xen auto-detection, native Docker/Podman config sub-packages, and OCI runtime fixes for Docker compatibility (JSON logging, root.path, kill --all, monitor PID lifecycle). Signed-off-by: Bruce Ashfield --- .../container-oci-registry-config.bb | 145 ++++++++++++--------- .../container-registry/docker-registry-config.bb | 24 +++- 2 files changed, 108 insertions(+), 61 deletions(-) (limited to 'recipes-containers/container-registry') diff --git a/recipes-containers/container-registry/container-oci-registry-config.bb b/recipes-containers/container-registry/container-oci-registry-config.bb index 294defc3..5161f0a3 100644 --- a/recipes-containers/container-registry/container-oci-registry-config.bb +++ b/recipes-containers/container-registry/container-oci-registry-config.bb @@ -64,12 +64,19 @@ CONTAINER_REGISTRY_SEARCH_FIRST ?= "1" # NOT stored in bitbake - should point to external file CONTAINER_REGISTRY_AUTHFILE ?= "" +# OCI runtime configuration for Podman +# Runtime name (e.g. "vxn") — creates a containers.conf.d drop-in +PODMAN_OCI_RUNTIME ?= "" +# Path to OCI runtime binary (e.g. "/usr/bin/vxn-oci-runtime") +PODMAN_OCI_RUNTIME_PATH ?= "" + # Skip recipe entirely if not configured # User must explicitly set CONTAINER_REGISTRY_URL to enable python() { registry = d.getVar('CONTAINER_REGISTRY_URL') - if not registry: - raise bb.parse.SkipRecipe("CONTAINER_REGISTRY_URL not set - recipe is opt-in only") + oci_runtime = (d.getVar('PODMAN_OCI_RUNTIME') or "").strip() + if not registry and not oci_runtime: + raise bb.parse.SkipRecipe("No registry or OCI runtime configured - recipe is opt-in only") # Check for conflicting settings secure = d.getVar('CONTAINER_REGISTRY_SECURE') == '1' @@ -94,63 +101,85 @@ python do_install() { search_first = d.getVar('CONTAINER_REGISTRY_SEARCH_FIRST') == "1" ca_cert = d.getVar('CONTAINER_REGISTRY_CA_CERT') authfile = d.getVar('CONTAINER_REGISTRY_AUTHFILE') or '' - - # Extract registry host (strip any path) - registry_host = registry.split('/')[0] if '/' in registry else registry + oci_runtime = (d.getVar('PODMAN_OCI_RUNTIME') or "").strip() + oci_runtime_path = (d.getVar('PODMAN_OCI_RUNTIME_PATH') or "").strip() dest = d.getVar('D') - confdir = os.path.join(dest, d.getVar('sysconfdir').lstrip('/'), - 'containers', 'registries.conf.d') - os.makedirs(confdir, exist_ok=True) - # Install CA cert in secure mode - if secure: - if os.path.exists(ca_cert): - cert_dir = os.path.join(dest, 'etc/containers/certs.d', registry_host) - os.makedirs(cert_dir, exist_ok=True) - shutil.copy(ca_cert, os.path.join(cert_dir, 'ca.crt')) - bb.note(f"Installed CA certificate for registry: {registry_host}") - else: - bb.warn(f"Secure mode enabled but CA certificate not found at {ca_cert}") - bb.warn("Run 'container-registry.sh start' to generate PKI, then rebuild this package") - - # In secure mode, insecure should be false - if secure: - insecure = False - - # Generate drop-in config - # Filename starts with 50- so it's processed after base config but - # can be overridden by higher-numbered files - config_path = os.path.join(confdir, '50-custom-registry.conf') - - with open(config_path, 'w') as f: - f.write(f"# Custom container registry: {registry}\n") - f.write(f"# Generated by container-oci-registry-config recipe\n") - f.write(f"# This is ADDITIVE - base registries.conf is unchanged\n") - f.write(f"# Public registries (docker.io, quay.io) remain accessible\n") - f.write(f"#\n") + # --- Registry configuration --- + if registry: + # Extract registry host (strip any path) + registry_host = registry.split('/')[0] if '/' in registry else registry + + confdir = os.path.join(dest, d.getVar('sysconfdir').lstrip('/'), + 'containers', 'registries.conf.d') + os.makedirs(confdir, exist_ok=True) + + # Install CA cert in secure mode if secure: - f.write(f"# Mode: secure (TLS with CA certificate verification)\n") - f.write(f"# CA cert: /etc/containers/certs.d/{registry_host}/ca.crt\n") - else: - f.write(f"# Mode: insecure (HTTP or untrusted TLS)\n") - f.write(f"#\n") - f.write(f"# To remove: uninstall container-oci-registry-config package\n") - f.write(f"# or delete this file\n\n") - - if search_first: - # Add to unqualified-search-registries - # This means short names like "myapp:latest" will search here first - f.write(f"# Search this registry for unqualified image names\n") - f.write(f'unqualified-search-registries = ["{registry}"]\n\n') - - # Always create registry entry to set insecure flag explicitly - f.write(f'[[registry]]\n') - f.write(f'location = "{registry_host}"\n') - if insecure: - f.write(f'insecure = true\n') - else: - f.write(f'insecure = false\n') + if os.path.exists(ca_cert): + cert_dir = os.path.join(dest, 'etc/containers/certs.d', registry_host) + os.makedirs(cert_dir, exist_ok=True) + shutil.copy(ca_cert, os.path.join(cert_dir, 'ca.crt')) + bb.note("Installed CA certificate for registry: %s" % registry_host) + else: + bb.warn("Secure mode enabled but CA certificate not found at %s" % ca_cert) + bb.warn("Run 'container-registry.sh start' to generate PKI, then rebuild this package") + + # In secure mode, insecure should be false + if secure: + insecure = False + + # Generate drop-in config + config_path = os.path.join(confdir, '50-custom-registry.conf') + + with open(config_path, 'w') as f: + f.write("# Custom container registry: %s\n" % registry) + f.write("# Generated by container-oci-registry-config recipe\n") + f.write("# This is ADDITIVE - base registries.conf is unchanged\n") + f.write("# Public registries (docker.io, quay.io) remain accessible\n") + f.write("#\n") + if secure: + f.write("# Mode: secure (TLS with CA certificate verification)\n") + f.write("# CA cert: /etc/containers/certs.d/%s/ca.crt\n" % registry_host) + else: + f.write("# Mode: insecure (HTTP or untrusted TLS)\n") + f.write("#\n") + f.write("# To remove: uninstall container-oci-registry-config package\n") + f.write("# or delete this file\n\n") + + if search_first: + f.write("# Search this registry for unqualified image names\n") + f.write('unqualified-search-registries = ["%s"]\n\n' % registry) + + f.write('[[registry]]\n') + f.write('location = "%s"\n' % registry_host) + if insecure: + f.write('insecure = true\n') + else: + f.write('insecure = false\n') + + mode = "secure" if secure else ("insecure" if insecure else "default") + bb.note("Created registry config for %s (mode=%s)" % (registry, mode)) + + # --- OCI runtime configuration --- + if oci_runtime: + dropin_dir = os.path.join(dest, d.getVar('sysconfdir').lstrip('/'), + 'containers', 'containers.conf.d') + os.makedirs(dropin_dir, exist_ok=True) + + runtime_path = oci_runtime_path if oci_runtime_path else "/usr/bin/%s" % oci_runtime + dropin_path = os.path.join(dropin_dir, '50-oci-runtime.conf') + + with open(dropin_path, 'w') as f: + f.write("# OCI runtime configuration\n") + f.write("# Generated by container-oci-registry-config recipe\n\n") + f.write("[engine]\n") + f.write('runtime = "%s"\n\n' % oci_runtime) + f.write("[engine.runtimes]\n") + f.write('%s = ["%s"]\n' % (oci_runtime, runtime_path)) + + bb.note("Created OCI runtime drop-in for %s (%s)" % (oci_runtime, runtime_path)) # Install authfile if provided (for baked credentials) if authfile and os.path.exists(authfile): @@ -159,14 +188,12 @@ python do_install() { auth_json = os.path.join(containers_dir, 'auth.json') shutil.copy(authfile, auth_json) os.chmod(auth_json, 0o600) - bb.note(f"Installed OCI auth config from {authfile}") - - mode = "secure" if secure else ("insecure" if insecure else "default") - bb.note(f"Created registry config for {registry} (mode={mode})") + bb.note("Installed OCI auth config from %s" % authfile) } FILES:${PN} = " \ ${sysconfdir}/containers/registries.conf.d \ + ${sysconfdir}/containers/containers.conf.d \ ${sysconfdir}/containers/certs.d/*/ca.crt \ ${sysconfdir}/containers/auth.json \ " diff --git a/recipes-containers/container-registry/docker-registry-config.bb b/recipes-containers/container-registry/docker-registry-config.bb index 0e8d66ad..e558cccb 100644 --- a/recipes-containers/container-registry/docker-registry-config.bb +++ b/recipes-containers/container-registry/docker-registry-config.bb @@ -60,6 +60,13 @@ DOCKER_REGISTRY_INSECURE ?= "" # NOT stored in bitbake - should point to external file CONTAINER_REGISTRY_AUTHFILE ?= "" +# OCI runtime configuration for Docker daemon +# JSON object mapping runtime names to paths, e.g.: +# DOCKER_OCI_RUNTIMES = '{"vxn": {"path": "/usr/bin/vxn-oci-runtime"}}' +DOCKER_OCI_RUNTIMES ?= "" +# Default OCI runtime name (must be a key in DOCKER_OCI_RUNTIMES or "runc") +DOCKER_DEFAULT_RUNTIME ?= "" + def get_insecure_registries(d): """Get insecure registries from either Docker-specific or generic config""" # Prefer explicit DOCKER_REGISTRY_INSECURE if set @@ -87,8 +94,10 @@ python() { bb.fatal("CONTAINER_REGISTRY_SECURE='1' conflicts with insecure registry settings. " "Use secure mode (TLS+auth) OR insecure mode (HTTP), not both.") - if not secure and not registries: - raise bb.parse.SkipRecipe("No registry configured - recipe is opt-in only") + oci_runtimes = (d.getVar('DOCKER_OCI_RUNTIMES') or "").strip() + + if not secure and not registries and not oci_runtimes: + raise bb.parse.SkipRecipe("No registry or OCI runtime configured - recipe is opt-in only") # In secure mode, depend on PKI generation if secure: @@ -137,6 +146,17 @@ python do_install() { config["insecure-registries"] = registries bb.note(f"Created Docker config with insecure registries: {registries}") + # OCI runtime configuration + oci_runtimes = (d.getVar('DOCKER_OCI_RUNTIMES') or "").strip() + default_runtime = (d.getVar('DOCKER_DEFAULT_RUNTIME') or "").strip() + + if oci_runtimes: + config["runtimes"] = json.loads(oci_runtimes) + bb.note("Added OCI runtimes to Docker config: %s" % oci_runtimes) + if default_runtime: + config["default-runtime"] = default_runtime + bb.note("Set default Docker runtime: %s" % default_runtime) + # Install authfile if provided (for baked credentials) if authfile and os.path.exists(authfile): docker_dir = os.path.join(dest, 'root/.docker') -- cgit v1.2.3-54-g00ecf