summaryrefslogtreecommitdiffstats
path: root/container/make-manifest-list.py
diff options
context:
space:
mode:
Diffstat (limited to 'container/make-manifest-list.py')
-rwxr-xr-xcontainer/make-manifest-list.py156
1 files changed, 122 insertions, 34 deletions
diff --git a/container/make-manifest-list.py b/container/make-manifest-list.py
index 010dcaed2b7..27b00cc4777 100755
--- a/container/make-manifest-list.py
+++ b/container/make-manifest-list.py
@@ -1,12 +1,34 @@
#!/usr/bin/python3
#
+# in default mode:
# make a combined "manifest-list" container out of two arch-specific containers
# searches for latest tags on HOST/{AMD,ARM}64_REPO, makes sure they refer
# to the same Ceph SHA1, and creates a manifest-list ("fat") image on
-# MANIFEST_HOST/MANIFEST_REPO with the 'standard' set of tags.
+# MANIFEST_HOST/MANIFEST_REPO with the 'standard' set of tags:
+# v<major>
+# v<major>.<minor>
+# v<major>.<minor>.<micro>
+# v<major>.<minor>.<micro>-<YYYYMMDD>
#
-# uses scratch local manifest LOCALMANIFEST, will be destroyed if present
+# uses scratch local manifest LOCALMANIFEST, defined here; will be destroyed if present
+#
+# in promote mode (by adding the --promote argument):
+# instead of building the manifest-list container, copy it
+# (and all of its tags) from the prerelease repo to the release repo
+#
+# Assumes valid logins to the necessary hosts/repos with permission to write images
+#
+# Environment variables to set:
+# ARCH_SPECIFIC_HOST (default 'quay.ceph.io'): host of prerelease repos
+# AMD64_REPO (default 'ceph/prerelease-amd64') prerelease amd64 repo
+# ARM64_REPO (default 'ceph/prerelease-arm64') prerelease arm64 repo
+# MANIFEST_HOST (default 'quay.ceph.io') prerelease manifest-list host
+# MANIFEST_REPO (default 'ceph/prerelease') prerelease manifest-list repo
+# RELEASE_MANIFEST_HOST (default 'quay.io') release host
+# RELEASE_MANIFEST_REPO (default 'ceph/ceph') release repo
+
+import argparse
from datetime import datetime
import functools
import json
@@ -15,16 +37,6 @@ import re
import subprocess
import sys
-# optional env vars (will default if not set)
-
-OPTIONAL_VARS = (
- 'HOST',
- 'AMD64_REPO',
- 'ARM64_REPO',
- 'MANIFEST_HOST',
- 'MANIFEST_REPO',
-)
-
# Manifest image. Will be destroyed if already present.
LOCALMANIFEST = 'localhost/m'
@@ -47,10 +59,7 @@ def run_command(args):
return True, result.stdout, result.stderr
except subprocess.CalledProcessError as e:
- print(f"Command '{e.cmd}' returned {e.returncode}")
- print("Error output:")
- print(e.stderr)
- return False, result.stdout, result.stderr
+ return False, e.output, e.stderr
def get_command_output(args):
@@ -68,10 +77,16 @@ def run_command_show_failure(args):
@functools.lru_cache
+def get_tags(path):
+ cmdout = get_command_output(f'skopeo list-tags docker://{path}')
+ return json.loads(cmdout)['Tags']
+
+
def get_latest_tag(path):
- latest_tag = json.loads(
- get_command_output(f'skopeo list-tags docker://{path}')
- )['Tags'][-1]
+ try:
+ latest_tag = get_tags(path)[-1]
+ except IndexError:
+ return None
return latest_tag
@@ -84,27 +99,53 @@ def get_image_inspect(path):
def get_sha1(info):
- return info['Labels']['GIT_COMMIT']
+ labels = info.get('Labels', None)
+ if not labels:
+ return None
+ return labels.get('CEPH_SHA1', None)
-def main():
- host = os.environ.get('HOST', 'quay.io')
- amd64_repo = os.environ.get('AMD64_REPO', 'ceph/ceph-amd64')
- arm64_repo = os.environ.get('ARM64_REPO', 'ceph/ceph-arm64')
- manifest_host = os.environ.get('MANIFEST_HOST', host)
- manifest_repo = os.environ.get('MANIFEST_REPO', 'ceph/ceph')
+@functools.lru_cache
+def get_all_matching_digest_tags(path, tag):
+
+ matching_tags = list()
+ digest = get_image_inspect(f'{path}:{tag}')['Digest']
+
+ for t in get_tags(path):
+ this_digest = get_image_inspect(f'{path}:{t}')['Digest']
+ if this_digest == digest:
+ matching_tags.append(t)
+
+ return matching_tags
+
+
+def parse_args():
+ ap = argparse.ArgumentParser()
+ ap.add_argument('-n', '--dry-run', action='store_true', help='do all local manipulations but do not push final containers to MANIFEST_HOST, or in --promote, calculate but do not copy images to release host')
+ ap.add_argument('-P', '--promote', action='store_true', help='promote newest prerelease manifest container to released (move from MANIFEST_HOST to RELEASE_MANIFEST_HOST')
+ args = ap.parse_args()
+ return args
+
+def build_prerelease(sysargs):
+ global args
+
+ arch_specific_host = os.environ.get('ARCH_SPECIFIC_HOST', 'quay.ceph.io')
+ amd64_repo = os.environ.get('AMD64_REPO', 'ceph/prerelease-amd64')
+ arm64_repo = os.environ.get('ARM64_REPO', 'ceph/prerelease-arm64')
+ manifest_host = os.environ.get('MANIFEST_HOST', 'quay.ceph.io')
+ manifest_repo = os.environ.get('MANIFEST_REPO', 'ceph/prerelease')
+
dump_vars(
- ('host',
+ ('arch_specific_host',
'amd64_repo',
'arm64_repo',
'manifest_host',
'manifest_repo',
),
locals())
-
repopaths = (
- f'{host}/{amd64_repo}',
- f'{host}/{arm64_repo}',
+ f'{arch_specific_host}/{amd64_repo}',
+ f'{arch_specific_host}/{arm64_repo}',
)
tags = [get_latest_tag(p) for p in repopaths]
print(f'latest tags: amd64:{tags[0]} arm64:{tags[1]}')
@@ -145,8 +186,8 @@ def main():
# create manifest list image with the standard list of tags
# ignore failure on manifest rm
- run_command(f'podman manifest rm localhost/m')
- run_command_show_failure(f'podman manifest create localhost/m')
+ run_command(f'podman manifest rm {LOCALMANIFEST}')
+ run_command_show_failure(f'podman manifest create {LOCALMANIFEST}')
for p in paths_with_tags:
run_command_show_failure(f'podman manifest add m {p}')
base = f'{manifest_host}/{manifest_repo}'
@@ -156,8 +197,55 @@ def main():
f'v{major}.{minor}.{micro}',
f'v{major}.{minor}.{micro}-{datetime.today().strftime("%Y%m%d")}',
):
- run_command_show_failure(
- f'podman manifest push localhost/m {base}:{t}')
+ if sysargs.dry_run:
+ print(f'skipping podman manifest push {LOCALMANIFEST} {base}:{t}')
+ else:
+ run_command_show_failure(
+ f'podman manifest push {LOCALMANIFEST} {base}:{t}')
+
+def promote(sysargs):
+ manifest_host = os.environ.get('MANIFEST_HOST', 'quay.ceph.io')
+ manifest_repo = os.environ.get('MANIFEST_REPO', 'ceph/prerelease')
+ release_manifest_host = os.environ.get('RELEASE_MANIFEST_HOST', 'quay.io')
+ release_manifest_repo = os.environ.get('RELEASE_MANIFEST_REPO', 'ceph/ceph')
+ dump_vars(
+ ('manifest_host',
+ 'manifest_repo',
+ 'release_manifest_host',
+ 'release_manifest_repo',
+ ),
+ locals())
+
+ manifest_path = f'{manifest_host}/{manifest_repo}'
+ release_path = f'{release_manifest_host}/{release_manifest_repo}'
+ latest_tag = get_latest_tag(manifest_path)
+ all_tags = get_all_matching_digest_tags(manifest_path, latest_tag)
+
+ copypaths = list()
+ for t in all_tags:
+ from_path = f'{manifest_path}:{t}'
+ to_path = f'{release_path}:{t}'
+ copypaths.append((from_path, to_path))
+
+ if sysargs.dry_run:
+ for f, t in copypaths:
+ print(f'dry-run: Would copy: {f} -> {t}')
+ return(0)
+
+ for f, t in copypaths:
+ print(f'Will copy: {f} -> {t}')
+
+ for f, t in copypaths:
+ run_command_show_failure(f'skopeo copy --multi-arch=all docker://{f} docker://{t}')
+
+
+def main():
+ args = parse_args()
+
+ if args.promote:
+ promote(args)
+ else:
+ build_prerelease(args)
if (__name__ == '__main__'):