diff options
author | Dan Mick <dan.mick@redhat.com> | 2024-11-16 01:21:26 +0100 |
---|---|---|
committer | Dan Mick <dan.mick@redhat.com> | 2024-12-03 21:32:13 +0100 |
commit | 4f050d7811fa6ec347c3414d5749e0f86480d7f4 (patch) | |
tree | 223483e3e6bc89a4010e94c744bbd2dcafe20550 /container | |
parent | container/Containerfile, build.sh: Add PRERELEASE_USERNAME/PASSWORD (diff) | |
download | ceph-4f050d7811fa6ec347c3414d5749e0f86480d7f4.tar.xz ceph-4f050d7811fa6ec347c3414d5749e0f86480d7f4.zip |
containers/make-manifest.py: Add --promote
The promote function finds the latest image on the prerelease repo,
finds all its tags, and copies them all to the release repo.
Signed-off-by: Dan Mick <dan.mick@redhat.com>
Diffstat (limited to 'container')
-rwxr-xr-x | container/make-manifest-list.py | 117 |
1 files changed, 96 insertions, 21 deletions
diff --git a/container/make-manifest-list.py b/container/make-manifest-list.py index 371e65a1329..b12598e0b6a 100755 --- a/container/make-manifest-list.py +++ b/container/make-manifest-list.py @@ -1,11 +1,32 @@ #!/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 @@ -16,16 +37,6 @@ import re import subprocess import sys -# optional env vars (will default if not set) - -OPTIONAL_VARS = ( - 'ARCH_SPECIFIC_HOST', - 'AMD64_REPO', - 'ARM64_REPO', - 'MANIFEST_HOST', - 'MANIFEST_REPO', -) - # Manifest image. Will be destroyed if already present. LOCALMANIFEST = 'localhost/m' @@ -66,10 +77,14 @@ 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): try: - cmdout = get_command_output(f'skopeo list-tags docker://{path}') - latest_tag = json.loads(cmdout)['Tags'][-1] + latest_tag = get_tags(path)[-1] except IndexError: return None return latest_tag @@ -90,19 +105,36 @@ def get_sha1(info): return labels.get('CEPH_SHA1', None) +@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') + 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 main(): - args = parse_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', arch_specific_host) + manifest_host = os.environ.get('MANIFEST_HOST', 'quay.ceph.io') manifest_repo = os.environ.get('MANIFEST_REPO', 'ceph/prerelease') + dump_vars( ('arch_specific_host', 'amd64_repo', @@ -111,7 +143,6 @@ def main(): 'manifest_repo', ), locals()) - repopaths = ( f'{arch_specific_host}/{amd64_repo}', f'{arch_specific_host}/{arm64_repo}', @@ -166,12 +197,56 @@ def main(): f'v{major}.{minor}.{micro}', f'v{major}.{minor}.{micro}-{datetime.today().strftime("%Y%m%d")}', ): - if args.dry_run: - print(f'skipping 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 localhost/m {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__'): sys.exit(main()) |