aboutsummaryrefslogtreecommitdiff
path: root/releng/docker.xsh
diff options
context:
space:
mode:
authorJade Lovelace <lix@jade.fyi>2024-06-09 00:27:06 -0700
committerJade Lovelace <lix@jade.fyi>2024-06-09 20:33:24 -0700
commit9aeb314e6a8276d3bd29f968c2baa44d5d19ca37 (patch)
tree9177ce42c9e62776b0a71ae31830ccb1c79ff05c /releng/docker.xsh
parent4392d89eeaf4560bf41e0c914b8f42f2959964d3 (diff)
releng: support multiarch docker images
If we don't want to have separate registry tags by architecture (EWWWW), we need to be able to build multiarch docker images. This is pretty simple, and just requires making a manifest pointing to each of the component images. I was *going* to just do this API prodding with manifest-tool, but it doesn't support putting metadata on the outer manifest, which is actually kind of a problem because it then doesn't render the metadata on github. So I guess we get a simple little containers API implementation that is 90% auth code. Change-Id: I8bdd118d4cbc13b23224f2fb174b232432686bea
Diffstat (limited to 'releng/docker.xsh')
-rw-r--r--releng/docker.xsh69
1 files changed, 65 insertions, 4 deletions
diff --git a/releng/docker.xsh b/releng/docker.xsh
index 1ed2330cf..f45a69d27 100644
--- a/releng/docker.xsh
+++ b/releng/docker.xsh
@@ -1,6 +1,18 @@
-from .environment import DockerTarget, RelengEnvironment
-from .version import VERSION
+import json
+import logging
from pathlib import Path
+import tempfile
+
+import requests
+
+from .environment import DockerTarget, RelengEnvironment
+from .version import VERSION, MAJOR
+from . import gitutils
+from .docker_assemble import Registry, OCIIndex, OCIIndexItem
+from . import docker_assemble
+
+log = logging.getLogger(__name__)
+log.setLevel(logging.INFO)
def check_all_logins(env: RelengEnvironment):
for target in env.docker_targets:
@@ -9,5 +21,54 @@ def check_all_logins(env: RelengEnvironment):
def check_login(target: DockerTarget):
skopeo login @(target.registry_name())
-def upload_docker_image(target: DockerTarget, path: Path):
- skopeo --insecure-policy copy docker-archive:@(path) docker://@(target.resolve(version=VERSION))
+def upload_docker_images(target: DockerTarget, paths: list[Path]):
+ if not paths: return
+
+ sess = requests.Session()
+ sess.headers['User-Agent'] = 'lix-releng'
+
+ tag_names = [DockerTarget.resolve(tag, version=VERSION, major=MAJOR) for tag in target.tags]
+
+ # latest only gets tagged for the current release branch of Lix
+ if not gitutils.is_maintenance_branch('HEAD'):
+ tag_names.append('latest')
+
+ meta = {}
+
+ reg = docker_assemble.Registry(sess)
+ manifests = []
+
+ with tempfile.TemporaryDirectory() as tmp:
+ tmp = Path(tmp)
+
+ for path in paths:
+ digest_file = tmp / (path.name + '.digest')
+ inspection = json.loads($(skopeo inspect docker-archive:@(path)))
+
+ docker_arch = inspection['Architecture']
+ docker_os = inspection['Os']
+ meta = inspection['Labels']
+
+ log.info('Pushing image %s for %s', path, docker_arch)
+
+ # insecure-policy: we don't have any signature policy, we are just uploading an image
+ # We upload to a junk tag, because otherwise it will upload to `latest`, which is undesirable
+ skopeo --insecure-policy copy --format oci --digestfile @(digest_file) docker-archive:@(path) docker://@(target.registry_path):temp
+
+ digest = digest_file.read_text().strip()
+
+ # skopeo doesn't give us the manifest size directly, so we just ask the registry
+ metadata = reg.image_info(target.registry_path, digest)
+
+ manifests.append(OCIIndexItem(metadata=metadata, architecture=docker_arch, os=docker_os))
+ # delete the temp tag, which we only have to create because of skopeo
+ # limitations anyhow (it seems to not have a way to say "don't tag it, find
+ # your checksum and put it there")
+ # FIXME: this is not possible because GitHub only has a proprietary API for it. amazing. 11/10.
+ # reg.delete_tag(target.registry_path, 'temp')
+
+ log.info('Pushed images, building a bigger and more menacing manifest from %r with metadata %r', manifests, meta)
+ # send the multiarch manifest to each tag
+ index = OCIIndex(manifests=manifests, annotations=meta)
+ for tag in tag_names:
+ reg.upload_index(target.registry_path, tag, index)