From a6f188ac20aafc10ac3b91459d285507e9e15bdb Mon Sep 17 00:00:00 2001 From: Sebastian Wagner Date: Mon, 3 Aug 2020 14:00:47 +0200 Subject: [PATCH] cephadm: inspect_image also returns repo_digest Signed-off-by: Sebastian Wagner (cherry picked from commit 30d8787c577727a3146c7ca32488936fc972c802) Conflicts: src/pybind/mgr/cephadm/module.py --- src/cephadm/cephadm | 27 ++++++++++++++++----- src/cephadm/tests/test_cephadm.py | 17 +++++++++++++ src/pybind/mgr/cephadm/module.py | 40 ++++++++++++++++++++----------- src/pybind/mgr/cephadm/upgrade.py | 3 ++- 4 files changed, 66 insertions(+), 21 deletions(-) diff --git a/src/cephadm/cephadm b/src/cephadm/cephadm index d79bd0f858df1..c959c441f179f 100755 --- a/src/cephadm/cephadm +++ b/src/cephadm/cephadm @@ -2490,18 +2490,33 @@ def command_inspect_image(): # type: () -> int out, err, ret = call_throws([ container_path, 'inspect', - '--format', '{{.Id}}', + '--format', '{{.ID}},{{json .RepoDigests}}', args.image]) if ret: return errno.ENOENT - image_id = normalize_container_id(out.strip()) + info_from = get_image_info_from_inspect(out.strip(), args.image) + ver = CephContainer(args.image, 'ceph', ['--version']).run().strip() + info_from['ceph_version'] = ver + + print(json.dumps(info_from, indent=4, sort_keys=True)) + return 0 + + +def get_image_info_from_inspect(out, image): + # type: (str, str) -> Dict[str, str] + image_id, digests = out.split(',', 1) + if not out: + raise Error('inspect {}: empty result'.format(image)) r = { - 'image_id': image_id, - 'ceph_version': ver, + 'image_id': normalize_container_id(image_id) } - print(json.dumps(r, indent=4, sort_keys=True)) - return 0 + if digests: + json_digests = json.loads(digests) + if json_digests: + r['repo_digest'] = json_digests[0] + return r + ################################## diff --git a/src/cephadm/tests/test_cephadm.py b/src/cephadm/tests/test_cephadm.py index 19aa8e254882a..91c13a2038ae6 100644 --- a/src/cephadm/tests/test_cephadm.py +++ b/src/cephadm/tests/test_cephadm.py @@ -238,3 +238,20 @@ default via fe80::2480:28ec:5097:3fe2 dev wlp2s0 proto ra metric 20600 pref medi with pytest.raises(Exception) as e: cd.command_registry_login() assert str(e.value) == "Failed to login to custom registry @ sample-url as sample-user with given password" + + def test_get_image_info_from_inspect(self): + # podman + out = """204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1,["docker.io/ceph/ceph@sha256:1cc9b824e1b076cdff52a9aa3f0cc8557d879fb2fbbba0cafed970aca59a3992"]""" + r = cd.get_image_info_from_inspect(out, 'registry/ceph/ceph:latest') + assert r == { + 'image_id': '204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1', + 'repo_digest': 'docker.io/ceph/ceph@sha256:1cc9b824e1b076cdff52a9aa3f0cc8557d879fb2fbbba0cafed970aca59a3992' + } + + # docker + out = """sha256:16f4549cf7a8f112bbebf7946749e961fbbd1b0838627fe619aab16bc17ce552,["quay.ceph.io/ceph-ci/ceph@sha256:4e13da36c1bd6780b312a985410ae678984c37e6a9493a74c87e4a50b9bda41f"]""" + r = cd.get_image_info_from_inspect(out, 'registry/ceph/ceph:latest') + assert r == { + 'image_id': '16f4549cf7a8f112bbebf7946749e961fbbd1b0838627fe619aab16bc17ce552', + 'repo_digest': 'quay.ceph.io/ceph-ci/ceph@sha256:4e13da36c1bd6780b312a985410ae678984c37e6a9493a74c87e4a50b9bda41f' + } diff --git a/src/pybind/mgr/cephadm/module.py b/src/pybind/mgr/cephadm/module.py index 187a417ae66ce..d62ec3fc1bc1b 100644 --- a/src/pybind/mgr/cephadm/module.py +++ b/src/pybind/mgr/cephadm/module.py @@ -10,7 +10,7 @@ from threading import Event import string from typing import List, Dict, Optional, Callable, Tuple, TypeVar, \ - Any, Set, TYPE_CHECKING, cast, Iterator, Union + Any, Set, TYPE_CHECKING, cast, Iterator, Union, NamedTuple import datetime import six @@ -107,6 +107,12 @@ def trivial_completion(f: Callable[..., T]) -> Callable[..., CephadmCompletion[T return wrapper +class ContainerInspectInfo(NamedTuple): + image_id: str + ceph_version: Optional[str] + repo_digest: Optional[str] + + @six.add_metaclass(CLICommandMeta) class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule): @@ -2511,7 +2517,7 @@ To check that the host is reachable: def apply_alertmanager(self, spec: ServiceSpec) -> str: return self._apply(spec) - def _get_container_image_id(self, image_name): + def _get_container_image_info(self, image_name) -> ContainerInspectInfo: # pick a random host... host = None for host_name in self.inventory.keys(): @@ -2530,12 +2536,19 @@ To check that the host is reachable: if code: raise OrchestratorError('Failed to pull %s on %s: %s' % ( image_name, host, '\n'.join(out))) - j = json.loads('\n'.join(out)) - image_id = j.get('image_id') - ceph_version = j.get('ceph_version') - self.log.debug('image %s -> id %s version %s' % - (image_name, image_id, ceph_version)) - return image_id, ceph_version + try: + j = json.loads('\n'.join(out)) + r = ContainerInspectInfo( + j['image_id'], + j.get('ceph_version'), + j.get('repo_digest') + ) + self.log.debug(f'image {image_name} -> {r}') + return r + except (ValueError, KeyError) as _: + msg = 'Failed to pull %s on %s: %s' % (image_name, host, '\n'.join(out)) + self.log.exception(msg) + raise OrchestratorError(msg) @trivial_completion def upgrade_check(self, image, version) -> str: @@ -2546,19 +2559,18 @@ To check that the host is reachable: else: raise OrchestratorError('must specify either image or version') - target_id, target_version = self._get_container_image_id(target_name) - self.log.debug('Target image %s id %s version %s' % ( - target_name, target_id, target_version)) + image_info = self._get_container_image_info(target_name) + self.log.debug(f'image info {image} -> {image_info}') r = { 'target_name': target_name, - 'target_id': target_id, - 'target_version': target_version, + 'target_id': image_info.image_id, + 'target_version': image_info.ceph_version, 'needs_update': dict(), 'up_to_date': list(), } for host, dm in self.cache.daemons.items(): for name, dd in dm.items(): - if target_id == dd.container_image_id: + if image_info.image_id == dd.container_image_id: r['up_to_date'].append(dd.name()) else: r['needs_update'][dd.name()] = { diff --git a/src/pybind/mgr/cephadm/upgrade.py b/src/pybind/mgr/cephadm/upgrade.py index eb1929bc96110..22bc9a71da0be 100644 --- a/src/pybind/mgr/cephadm/upgrade.py +++ b/src/pybind/mgr/cephadm/upgrade.py @@ -217,7 +217,8 @@ class CephadmUpgrade: # need to learn the container hash logger.info('Upgrade: First pull of %s' % target_name) try: - target_id, target_version = self.mgr._get_container_image_id(target_name) + target_id, target_version, repo_digest = self.mgr._get_container_image_info( + target_name) except OrchestratorError as e: self._fail_upgrade('UPGRADE_FAILED_PULL', { 'severity': 'warning', -- 2.39.5