Skip to content

Commit e6da3f7

Browse files
committed
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]>
1 parent bc2a455 commit e6da3f7

File tree

1 file changed

+47
-20
lines changed

1 file changed

+47
-20
lines changed

src/cmd-push-container-manifest

Lines changed: 47 additions & 20 deletions
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.cmdlib 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,19 @@ def main():
3743
# - Store the path to the container image in the container_images list
3844
images = []
3945
buildmetas = dict()
46+
digests = {}
47+
upload = False
48+
# Checks if we already have it in the remote
49+
cmd = ["skopeo", "inspect", "--raw", f"docker://{args.repo}:{args.tags[0]}"]
50+
manifest_meta = runcmd(cmd, capture_output=True, check=False).stdout
51+
if manifest_meta:
52+
manifests = json.loads(manifest_meta)
53+
for manifest in manifests['manifests']:
54+
arch = manifest['platform']['architecture']
55+
if arch in map_arch:
56+
arch = map_arch[arch]
57+
digests[arch] = manifest['digest']
58+
4059
for arch in args.arches:
4160
if arch not in build_arches:
4261
print(f"Requested architecture {arch} is not in {args.build}")
@@ -48,6 +67,14 @@ def main():
4867
if not buildmeta['images'][args.artifact]:
4968
print(f"No artifact {args.artifact} in {args.build}/{arch}")
5069
raise Exception
70+
71+
# Checks if the meta digest matches each arch digest in the remote
72+
if 'digest' in buildmetas[arch][args.metajsonname]:
73+
digest = buildmetas[arch][args.metajsonname]['digest']
74+
if arch not in digests:
75+
upload = True
76+
elif digest != digests[arch]:
77+
upload = True
5178
ociarchive = os.path.join(builddir, buildmeta['images'][args.artifact]['path'])
5279
ocisha256sum = buildmeta['images'][args.artifact]['sha256']
5380
if not os.path.exists(ociarchive):
@@ -58,26 +85,25 @@ def main():
5885
raise Exception
5986
images.append(f"oci-archive:{ociarchive}")
6087

61-
# Create/Upload the manifest list to the container registry
62-
manifest_info = create_and_push_container_manifest(
63-
args.repo, args.tags, images, args.v2s2)
64-
65-
# Update the `meta.json` files. Note the digest included is the
66-
# arch-specific one for each individual arch, and not the manifest list
67-
# digest. See: https://github.com/coreos/coreos-assembler/issues/3122.
68-
assert len(manifest_info['manifests']) == len(buildmetas)
69-
for manifest in manifest_info['manifests']:
70-
arch = manifest['platform']['architecture']
71-
if arch == 'arm64':
72-
arch = 'aarch64'
73-
elif arch == 'amd64':
74-
arch = 'x86_64'
75-
buildmetas[arch][args.metajsonname] = {
76-
'image': args.repo,
77-
'digest': manifest['digest'],
78-
'tags': args.tags
79-
}
80-
buildmetas[arch].write(artifact_name=args.metajsonname)
88+
if upload is True or args.force is True:
89+
# Create/Upload the manifest list to the container registry
90+
manifest_info = create_and_push_container_manifest(
91+
args.repo, args.tags, images, args.v2s2)
92+
93+
# Update the `meta.json` files. Note the digest included is the
94+
# arch-specific one for each individual arch, and not the manifest list
95+
# digest. See: https://github.com/coreos/coreos-assembler/issues/3122.
96+
assert len(manifest_info['manifests']) == len(buildmetas)
97+
for manifest in manifest_info['manifests']:
98+
arch = manifest['platform']['architecture']
99+
if arch in map_arch:
100+
arch = map_arch[arch]
101+
buildmetas[arch][args.metajsonname] = {
102+
'image': args.repo,
103+
'digest': manifest['digest'],
104+
'tags': args.tags
105+
}
106+
buildmetas[arch].write(artifact_name=args.metajsonname)
81107

82108

83109
def parse_args():
@@ -108,6 +134,7 @@ Examples:
108134
parser.add_argument("--authfile", help="A file to use for registry auth")
109135
parser.add_argument('--v2s2', action='store_true',
110136
help='Use old image manifest version 2 schema 2 format')
137+
parser.add_argument("--force", help="Force manifest overwriting", action='store_true')
111138

112139
group = parser.add_mutually_exclusive_group(required=True)
113140
group.add_argument("--image", dest='images', action='append', default=[],

0 commit comments

Comments
 (0)