Skip to content

Commit ac0f799

Browse files
ravanellijlebon
authored andcommitted
cmd-push-container-manifest: attempt to make more idempotent
Check if the digests are already present in the remote manifest and if you want to force or not a new manifest upload. Fixes coreos#3150 Signed-off-by: Renata Ravanelli <[email protected]> (cherry picked from commit bfbbe41) jlebon: Had to modify new code to use `runcmd` from `cosalib.utils.`. (cherry picked from commit 9d3bdd9)
1 parent d3167c0 commit ac0f799

File tree

1 file changed

+39
-4
lines changed

1 file changed

+39
-4
lines changed

src/cmd-push-container-manifest

+39-4
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,24 @@
44
# arguments provided by the user.
55

66
import argparse
7+
import json
78
import os
89
import sys
910
from cosalib.container_manifest import create_and_push_container_manifest
1011
from cosalib.builds import Builds
1112
from cosalib.meta import GenericBuildMeta
13+
from cosalib.utils import runcmd
1214
from cosalib.cmdlib import sha256sum_file
1315

1416
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
1517

1618

1719
def main():
1820
args = parse_args()
21+
map_arch = {}
22+
map_arch['arm64'] = 'aarch64'
23+
map_arch['amd64'] = 'x86_64'
24+
1925
if args.authfile:
2026
os.environ["REGISTRY_AUTH_FILE"] = args.authfile
2127
if args.images:
@@ -37,6 +43,18 @@ def main():
3743
# - Store the path to the container image in the container_images list
3844
images = []
3945
buildmetas = dict()
46+
registry_digests = {}
47+
upload = False
48+
# Collect registry_digests of current manifest list in remote registry
49+
inspect = skopeo_inspect(f'{args.repo}:{args.tags[0]}', args.authfile)
50+
if inspect.returncode == 0:
51+
manifests = json.loads(inspect.stdout)
52+
for manifest in manifests['manifests']:
53+
arch = manifest['platform']['architecture']
54+
if arch in map_arch:
55+
arch = map_arch[arch]
56+
registry_digests[arch] = manifest['digest']
57+
4058
for arch in args.arches:
4159
if arch not in build_arches:
4260
print(f"Requested architecture {arch} is not in {args.build}")
@@ -48,6 +66,13 @@ def main():
4866
if not buildmeta['images'][args.artifact]:
4967
print(f"No artifact {args.artifact} in {args.build}/{arch}")
5068
raise Exception
69+
70+
# Checks if the meta digest matches each arch digest in the remote.
71+
# If it doesn't match (or doesn't exist), we need to upload.
72+
if 'digest' in buildmetas[arch][args.metajsonname]:
73+
meta_digest = buildmetas[arch][args.metajsonname]['digest']
74+
if meta_digest != registry_digests.get(arch):
75+
upload = True
5176
ociarchive = os.path.join(builddir, buildmeta['images'][args.artifact]['path'])
5277
ocisha256sum = buildmeta['images'][args.artifact]['sha256']
5378
if not os.path.exists(ociarchive):
@@ -58,6 +83,10 @@ def main():
5883
raise Exception
5984
images.append(f"oci-archive:{ociarchive}")
6085

86+
if not upload and not args.force:
87+
print("Remote already matches desired state; skipping push. Use --force to override.")
88+
return
89+
6190
# Create/Upload the manifest list to the container registry
6291
manifest_info = create_and_push_container_manifest(
6392
args.repo, args.tags, images, args.v2s2)
@@ -68,10 +97,8 @@ def main():
6897
assert len(manifest_info['manifests']) == len(buildmetas)
6998
for manifest in manifest_info['manifests']:
7099
arch = manifest['platform']['architecture']
71-
if arch == 'arm64':
72-
arch = 'aarch64'
73-
elif arch == 'amd64':
74-
arch = 'x86_64'
100+
if arch in map_arch:
101+
arch = map_arch[arch]
75102
buildmetas[arch][args.metajsonname] = {
76103
'image': args.repo,
77104
'digest': manifest['digest']
@@ -107,6 +134,7 @@ Examples:
107134
parser.add_argument("--authfile", help="A file to use for registry auth")
108135
parser.add_argument('--v2s2', action='store_true',
109136
help='Use old image manifest version 2 schema 2 format')
137+
parser.add_argument("--force", help="Force manifest overwriting", action='store_true')
110138

111139
group = parser.add_mutually_exclusive_group(required=True)
112140
group.add_argument("--image", dest='images', action='append', default=[],
@@ -126,5 +154,12 @@ Examples:
126154
return parser.parse_args()
127155

128156

157+
def skopeo_inspect(fqin, authfile):
158+
args = ['skopeo', 'inspect', '--raw']
159+
if authfile:
160+
args += ['--authfile', authfile]
161+
return runcmd((args + [f'docker://{fqin}']), capture_output=True, check=False)
162+
163+
129164
if __name__ == '__main__':
130165
sys.exit(main())

0 commit comments

Comments
 (0)