# 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
+
##################################
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'
+ }
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 os
return wrapper
+class ContainerInspectInfo(NamedTuple):
+ image_id: str
+ ceph_version: Optional[str]
+ repo_digest: Optional[str]
+
+
class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule,
metaclass=CLICommandMeta):
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():
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:
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()] = {