1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
#!/usr/bin/python3
#
# 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.
#
# uses scratch local manifest LOCALMANIFEST, will be destroyed if present
from datetime import datetime
import functools
import json
import os
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'
def dump_vars(names, vardict):
for name in names:
print(f'{name}: {vardict[name]}', file=sys.stderr)
def run_command(args):
print(f'running {args}', file=sys.stderr)
if not isinstance(args, list):
args = args.split()
try:
result = subprocess.run(
args,
capture_output=True,
text=True,
check=True)
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
def get_command_output(args):
success, stdout, stderr = run_command(args)
return (stdout if success else None)
def run_command_show_failure(args):
success, stdout, stderr = run_command(args)
if not success:
print(f'{args} failed:', file=sys.stderr)
print(f'stdout:\n{stdout}')
print(f'stderr:\n{stderr}')
return success
@functools.lru_cache
def get_latest_tag(path):
latest_tag = json.loads(
get_command_output(f'skopeo list-tags docker://{path}')
)['Tags'][-1]
return latest_tag
@functools.lru_cache
def get_image_inspect(path):
info = json.loads(
get_command_output(f'skopeo inspect docker://{path}')
)
return info
def get_sha1(info):
return info['Labels']['GIT_COMMIT']
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')
dump_vars(
('host',
'amd64_repo',
'arm64_repo',
'manifest_host',
'manifest_repo',
),
locals())
repopaths = (
f'{host}/{amd64_repo}',
f'{host}/{arm64_repo}',
)
tags = [get_latest_tag(p) for p in repopaths]
print(f'latest tags: amd64:{tags[0]} arm64:{tags[1]}')
# check that version of latest tag matches
version_re = \
r'v(?P<major>\d+)\.(?P<minor>\d+)\.(?P<micro>\d+)-(?P<date>\d+)'
versions = list()
for tag in tags:
mo = re.match(version_re, tag)
ver = f'{mo.group("major")}.{mo.group("minor")}.{mo.group("micro")}'
versions.append(ver)
if versions[0] != versions[1]:
print(
f'version mismatch: amd64:{versions[0]} arm64:{versions[1]}',
file=sys.stderr,
)
return(1)
major, minor, micro = mo.group(1), mo.group(2), mo.group(3)
print(f'Ceph version: {major}.{minor}.{micro}', file=sys.stderr)
# check that ceph sha1 of two arch images matches
paths_with_tags = [f'{p}:{t}' for (p, t) in zip(repopaths, tags)]
info = [get_image_inspect(p) for p in paths_with_tags]
sha1s = [get_sha1(i) for i in info]
if sha1s[0] != sha1s[1]:
print(
f'sha1 mismatch: amd64: {sha1s[0]} arm64: {sha1s[1]}',
file=sys.stderr,
)
builddate = [i['Created'] for i in info]
print(
f'Build dates: amd64: {builddate[0]} arm64: {builddate[1]}',
file=sys.stderr,
)
return(1)
# 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')
for p in paths_with_tags:
run_command_show_failure(f'podman manifest add m {p}')
base = f'{manifest_host}/{manifest_repo}'
for t in (
f'v{major}',
f'v{major}.{minor}',
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 (__name__ == '__main__'):
sys.exit(main())
|