summaryrefslogtreecommitdiffstats
path: root/recipes-containers/container-registry
diff options
context:
space:
mode:
authorBruce Ashfield <bruce.ashfield@gmail.com>2026-02-19 01:53:36 +0000
committerBruce Ashfield <bruce.ashfield@gmail.com>2026-02-26 01:05:01 +0000
commit035e0daebeb53880ea2a6bd0f0e31785f3ec9e55 (patch)
tree1ae711e61d79ad2f7b0afba6fc4489f61d1a6202 /recipes-containers/container-registry
parentbf5abfe3d55604c6b22416cc23cbfaba1ff7bee2 (diff)
downloadmeta-virtualization-035e0daebeb53880ea2a6bd0f0e31785f3ec9e55.tar.gz
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 <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers/container-registry')
-rw-r--r--recipes-containers/container-registry/container-oci-registry-config.bb145
-rw-r--r--recipes-containers/container-registry/docker-registry-config.bb24
2 files changed, 108 insertions, 61 deletions
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"
64# NOT stored in bitbake - should point to external file 64# NOT stored in bitbake - should point to external file
65CONTAINER_REGISTRY_AUTHFILE ?= "" 65CONTAINER_REGISTRY_AUTHFILE ?= ""
66 66
67# OCI runtime configuration for Podman
68# Runtime name (e.g. "vxn") — creates a containers.conf.d drop-in
69PODMAN_OCI_RUNTIME ?= ""
70# Path to OCI runtime binary (e.g. "/usr/bin/vxn-oci-runtime")
71PODMAN_OCI_RUNTIME_PATH ?= ""
72
67# Skip recipe entirely if not configured 73# Skip recipe entirely if not configured
68# User must explicitly set CONTAINER_REGISTRY_URL to enable 74# User must explicitly set CONTAINER_REGISTRY_URL to enable
69python() { 75python() {
70 registry = d.getVar('CONTAINER_REGISTRY_URL') 76 registry = d.getVar('CONTAINER_REGISTRY_URL')
71 if not registry: 77 oci_runtime = (d.getVar('PODMAN_OCI_RUNTIME') or "").strip()
72 raise bb.parse.SkipRecipe("CONTAINER_REGISTRY_URL not set - recipe is opt-in only") 78 if not registry and not oci_runtime:
79 raise bb.parse.SkipRecipe("No registry or OCI runtime configured - recipe is opt-in only")
73 80
74 # Check for conflicting settings 81 # Check for conflicting settings
75 secure = d.getVar('CONTAINER_REGISTRY_SECURE') == '1' 82 secure = d.getVar('CONTAINER_REGISTRY_SECURE') == '1'
@@ -94,63 +101,85 @@ python do_install() {
94 search_first = d.getVar('CONTAINER_REGISTRY_SEARCH_FIRST') == "1" 101 search_first = d.getVar('CONTAINER_REGISTRY_SEARCH_FIRST') == "1"
95 ca_cert = d.getVar('CONTAINER_REGISTRY_CA_CERT') 102 ca_cert = d.getVar('CONTAINER_REGISTRY_CA_CERT')
96 authfile = d.getVar('CONTAINER_REGISTRY_AUTHFILE') or '' 103 authfile = d.getVar('CONTAINER_REGISTRY_AUTHFILE') or ''
97 104 oci_runtime = (d.getVar('PODMAN_OCI_RUNTIME') or "").strip()
98 # Extract registry host (strip any path) 105 oci_runtime_path = (d.getVar('PODMAN_OCI_RUNTIME_PATH') or "").strip()
99 registry_host = registry.split('/')[0] if '/' in registry else registry
100 106
101 dest = d.getVar('D') 107 dest = d.getVar('D')
102 confdir = os.path.join(dest, d.getVar('sysconfdir').lstrip('/'),
103 'containers', 'registries.conf.d')
104 os.makedirs(confdir, exist_ok=True)
105 108
106 # Install CA cert in secure mode 109 # --- Registry configuration ---
107 if secure: 110 if registry:
108 if os.path.exists(ca_cert): 111 # Extract registry host (strip any path)
109 cert_dir = os.path.join(dest, 'etc/containers/certs.d', registry_host) 112 registry_host = registry.split('/')[0] if '/' in registry else registry
110 os.makedirs(cert_dir, exist_ok=True) 113
111 shutil.copy(ca_cert, os.path.join(cert_dir, 'ca.crt')) 114 confdir = os.path.join(dest, d.getVar('sysconfdir').lstrip('/'),
112 bb.note(f"Installed CA certificate for registry: {registry_host}") 115 'containers', 'registries.conf.d')
113 else: 116 os.makedirs(confdir, exist_ok=True)
114 bb.warn(f"Secure mode enabled but CA certificate not found at {ca_cert}") 117
115 bb.warn("Run 'container-registry.sh start' to generate PKI, then rebuild this package") 118 # Install CA cert in secure mode
116
117 # In secure mode, insecure should be false
118 if secure:
119 insecure = False
120
121 # Generate drop-in config
122 # Filename starts with 50- so it's processed after base config but
123 # can be overridden by higher-numbered files
124 config_path = os.path.join(confdir, '50-custom-registry.conf')
125
126 with open(config_path, 'w') as f:
127 f.write(f"# Custom container registry: {registry}\n")
128 f.write(f"# Generated by container-oci-registry-config recipe\n")
129 f.write(f"# This is ADDITIVE - base registries.conf is unchanged\n")
130 f.write(f"# Public registries (docker.io, quay.io) remain accessible\n")
131 f.write(f"#\n")
132 if secure: 119 if secure:
133 f.write(f"# Mode: secure (TLS with CA certificate verification)\n") 120 if os.path.exists(ca_cert):
134 f.write(f"# CA cert: /etc/containers/certs.d/{registry_host}/ca.crt\n") 121 cert_dir = os.path.join(dest, 'etc/containers/certs.d', registry_host)
135 else: 122 os.makedirs(cert_dir, exist_ok=True)
136 f.write(f"# Mode: insecure (HTTP or untrusted TLS)\n") 123 shutil.copy(ca_cert, os.path.join(cert_dir, 'ca.crt'))
137 f.write(f"#\n") 124 bb.note("Installed CA certificate for registry: %s" % registry_host)
138 f.write(f"# To remove: uninstall container-oci-registry-config package\n") 125 else:
139 f.write(f"# or delete this file\n\n") 126 bb.warn("Secure mode enabled but CA certificate not found at %s" % ca_cert)
140 127 bb.warn("Run 'container-registry.sh start' to generate PKI, then rebuild this package")
141 if search_first: 128
142 # Add to unqualified-search-registries 129 # In secure mode, insecure should be false
143 # This means short names like "myapp:latest" will search here first 130 if secure:
144 f.write(f"# Search this registry for unqualified image names\n") 131 insecure = False
145 f.write(f'unqualified-search-registries = ["{registry}"]\n\n') 132
146 133 # Generate drop-in config
147 # Always create registry entry to set insecure flag explicitly 134 config_path = os.path.join(confdir, '50-custom-registry.conf')
148 f.write(f'[[registry]]\n') 135
149 f.write(f'location = "{registry_host}"\n') 136 with open(config_path, 'w') as f:
150 if insecure: 137 f.write("# Custom container registry: %s\n" % registry)
151 f.write(f'insecure = true\n') 138 f.write("# Generated by container-oci-registry-config recipe\n")
152 else: 139 f.write("# This is ADDITIVE - base registries.conf is unchanged\n")
153 f.write(f'insecure = false\n') 140 f.write("# Public registries (docker.io, quay.io) remain accessible\n")
141 f.write("#\n")
142 if secure:
143 f.write("# Mode: secure (TLS with CA certificate verification)\n")
144 f.write("# CA cert: /etc/containers/certs.d/%s/ca.crt\n" % registry_host)
145 else:
146 f.write("# Mode: insecure (HTTP or untrusted TLS)\n")
147 f.write("#\n")
148 f.write("# To remove: uninstall container-oci-registry-config package\n")
149 f.write("# or delete this file\n\n")
150
151 if search_first:
152 f.write("# Search this registry for unqualified image names\n")
153 f.write('unqualified-search-registries = ["%s"]\n\n' % registry)
154
155 f.write('[[registry]]\n')
156 f.write('location = "%s"\n' % registry_host)
157 if insecure:
158 f.write('insecure = true\n')
159 else:
160 f.write('insecure = false\n')
161
162 mode = "secure" if secure else ("insecure" if insecure else "default")
163 bb.note("Created registry config for %s (mode=%s)" % (registry, mode))
164
165 # --- OCI runtime configuration ---
166 if oci_runtime:
167 dropin_dir = os.path.join(dest, d.getVar('sysconfdir').lstrip('/'),
168 'containers', 'containers.conf.d')
169 os.makedirs(dropin_dir, exist_ok=True)
170
171 runtime_path = oci_runtime_path if oci_runtime_path else "/usr/bin/%s" % oci_runtime
172 dropin_path = os.path.join(dropin_dir, '50-oci-runtime.conf')
173
174 with open(dropin_path, 'w') as f:
175 f.write("# OCI runtime configuration\n")
176 f.write("# Generated by container-oci-registry-config recipe\n\n")
177 f.write("[engine]\n")
178 f.write('runtime = "%s"\n\n' % oci_runtime)
179 f.write("[engine.runtimes]\n")
180 f.write('%s = ["%s"]\n' % (oci_runtime, runtime_path))
181
182 bb.note("Created OCI runtime drop-in for %s (%s)" % (oci_runtime, runtime_path))
154 183
155 # Install authfile if provided (for baked credentials) 184 # Install authfile if provided (for baked credentials)
156 if authfile and os.path.exists(authfile): 185 if authfile and os.path.exists(authfile):
@@ -159,14 +188,12 @@ python do_install() {
159 auth_json = os.path.join(containers_dir, 'auth.json') 188 auth_json = os.path.join(containers_dir, 'auth.json')
160 shutil.copy(authfile, auth_json) 189 shutil.copy(authfile, auth_json)
161 os.chmod(auth_json, 0o600) 190 os.chmod(auth_json, 0o600)
162 bb.note(f"Installed OCI auth config from {authfile}") 191 bb.note("Installed OCI auth config from %s" % authfile)
163
164 mode = "secure" if secure else ("insecure" if insecure else "default")
165 bb.note(f"Created registry config for {registry} (mode={mode})")
166} 192}
167 193
168FILES:${PN} = " \ 194FILES:${PN} = " \
169 ${sysconfdir}/containers/registries.conf.d \ 195 ${sysconfdir}/containers/registries.conf.d \
196 ${sysconfdir}/containers/containers.conf.d \
170 ${sysconfdir}/containers/certs.d/*/ca.crt \ 197 ${sysconfdir}/containers/certs.d/*/ca.crt \
171 ${sysconfdir}/containers/auth.json \ 198 ${sysconfdir}/containers/auth.json \
172" 199"
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 ?= ""
60# NOT stored in bitbake - should point to external file 60# NOT stored in bitbake - should point to external file
61CONTAINER_REGISTRY_AUTHFILE ?= "" 61CONTAINER_REGISTRY_AUTHFILE ?= ""
62 62
63# OCI runtime configuration for Docker daemon
64# JSON object mapping runtime names to paths, e.g.:
65# DOCKER_OCI_RUNTIMES = '{"vxn": {"path": "/usr/bin/vxn-oci-runtime"}}'
66DOCKER_OCI_RUNTIMES ?= ""
67# Default OCI runtime name (must be a key in DOCKER_OCI_RUNTIMES or "runc")
68DOCKER_DEFAULT_RUNTIME ?= ""
69
63def get_insecure_registries(d): 70def get_insecure_registries(d):
64 """Get insecure registries from either Docker-specific or generic config""" 71 """Get insecure registries from either Docker-specific or generic config"""
65 # Prefer explicit DOCKER_REGISTRY_INSECURE if set 72 # Prefer explicit DOCKER_REGISTRY_INSECURE if set
@@ -87,8 +94,10 @@ python() {
87 bb.fatal("CONTAINER_REGISTRY_SECURE='1' conflicts with insecure registry settings. " 94 bb.fatal("CONTAINER_REGISTRY_SECURE='1' conflicts with insecure registry settings. "
88 "Use secure mode (TLS+auth) OR insecure mode (HTTP), not both.") 95 "Use secure mode (TLS+auth) OR insecure mode (HTTP), not both.")
89 96
90 if not secure and not registries: 97 oci_runtimes = (d.getVar('DOCKER_OCI_RUNTIMES') or "").strip()
91 raise bb.parse.SkipRecipe("No registry configured - recipe is opt-in only") 98
99 if not secure and not registries and not oci_runtimes:
100 raise bb.parse.SkipRecipe("No registry or OCI runtime configured - recipe is opt-in only")
92 101
93 # In secure mode, depend on PKI generation 102 # In secure mode, depend on PKI generation
94 if secure: 103 if secure:
@@ -137,6 +146,17 @@ python do_install() {
137 config["insecure-registries"] = registries 146 config["insecure-registries"] = registries
138 bb.note(f"Created Docker config with insecure registries: {registries}") 147 bb.note(f"Created Docker config with insecure registries: {registries}")
139 148
149 # OCI runtime configuration
150 oci_runtimes = (d.getVar('DOCKER_OCI_RUNTIMES') or "").strip()
151 default_runtime = (d.getVar('DOCKER_DEFAULT_RUNTIME') or "").strip()
152
153 if oci_runtimes:
154 config["runtimes"] = json.loads(oci_runtimes)
155 bb.note("Added OCI runtimes to Docker config: %s" % oci_runtimes)
156 if default_runtime:
157 config["default-runtime"] = default_runtime
158 bb.note("Set default Docker runtime: %s" % default_runtime)
159
140 # Install authfile if provided (for baked credentials) 160 # Install authfile if provided (for baked credentials)
141 if authfile and os.path.exists(authfile): 161 if authfile and os.path.exists(authfile):
142 docker_dir = os.path.join(dest, 'root/.docker') 162 docker_dir = os.path.join(dest, 'root/.docker')