From: Sage Weil Date: Wed, 4 Dec 2019 21:27:34 +0000 (-0600) Subject: mgr/ssh: add 'upgrade check' command X-Git-Tag: v15.1.0~578^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=ba378a2f2eb92e3bc1d1037035359e0bb68ce879;p=ceph-ci.git mgr/ssh: add 'upgrade check' command Signed-off-by: Sage Weil --- diff --git a/src/pybind/mgr/orchestrator.py b/src/pybind/mgr/orchestrator.py index 6ccefeebfff..c248f3b83a4 100644 --- a/src/pybind/mgr/orchestrator.py +++ b/src/pybind/mgr/orchestrator.py @@ -980,6 +980,10 @@ class Orchestrator(object): """ raise NotImplementedError() + def upgrade_check(self, image, version): + # type: (Optional[str], Optional[str]) -> Completion + raise NotImplementedError() + @_hide_in_features def upgrade_start(self, upgrade_spec): # type: (UpgradeSpec) -> Completion diff --git a/src/pybind/mgr/orchestrator_cli/module.py b/src/pybind/mgr/orchestrator_cli/module.py index 057dea6bfa5..ffd1c76c663 100644 --- a/src/pybind/mgr/orchestrator_cli/module.py +++ b/src/pybind/mgr/orchestrator_cli/module.py @@ -724,3 +724,14 @@ Usage: c = orchestrator.TrivialReadCompletion(result=True) assert c.has_result + + @orchestrator._cli_write_command( + 'upgrade check', + 'name=image,type=CephString,req=false ' + 'name=ceph_version,type=CephString,req=false', + desc='Check service versions vs available and target containers') + def _upgrade_check(self, image=None, ceph_version=None): + completion = self.upgrade_check(image=image, version=ceph_version) + self._orchestrator_wait([completion]) + orchestrator.raise_if_exception(completion) + return HandleCommandResult(stdout=completion.result_str()) diff --git a/src/pybind/mgr/ssh/module.py b/src/pybind/mgr/ssh/module.py index 6c73e505a8e..c0e545149ef 100644 --- a/src/pybind/mgr/ssh/module.py +++ b/src/pybind/mgr/ssh/module.py @@ -260,6 +260,12 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator): 'default': 'root', 'desc': 'mode for remote execution of ceph-daemon', }, + { + 'name': 'container_image_base', + 'default': 'ceph/ceph', + 'desc': 'Container image name, without the tag', + 'runtime': True, + }, ] def __init__(self, *args, **kwargs): @@ -564,20 +570,22 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator): def _run_ceph_daemon(self, host, entity, command, args, stdin=None, no_fsid=False, - error_ok=False): + error_ok=False, + image=None): """ Run ceph-daemon on the remote host with the given command + args """ conn = self._get_connection(host) try: - # get container image - ret, image, err = self.mon_command({ - 'prefix': 'config get', - 'who': _name_to_entity_name(entity), - 'key': 'container_image', - }) - image = image.strip() + if not image: + # get container image + ret, image, err = self.mon_command({ + 'prefix': 'config get', + 'who': _name_to_entity_name(entity), + 'key': 'container_image', + }) + image = image.strip() self.log.debug('%s container image %s' % (entity, image)) final_args = [ @@ -1400,3 +1408,47 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator): def update_rbd_mirror(self, spec): return self._update_service('rbd-mirror', self.add_rbd_mirror, spec) + + def _get_container_image_id(self, image_name): + # pick a random host... + host = None + for host_name in self.inventory_cache: + host = host_name + break + if not host: + raise OrchestratorError('no hosts defined') + self.log.debug('using host %s' % host) + out, code = self._run_ceph_daemon( + host, None, 'pull', [], + image=image_name, + no_fsid=True) + return out[0] + + def upgrade_check(self, image, version): + if version: + target = self.container_image_base + ':v' + version + elif image: + target = image + else: + raise OrchestratorError('must specify either image or version') + return self._get_services().then(lambda daemons: self._upgrade_check(target, daemons)) + + def _upgrade_check(self, target, services): + # get service state + target_id = self._get_container_image_id(target) + self.log.debug('Target image %s id %s' % (target, target_id)) + r = { + 'target_image_name': target, + 'target_image_id': target_id, + 'needs_update': dict(), + 'up_to_date': list(), + } + for s in services: + if target_id == s.container_image_id: + r['up_to_date'].append(s.name()) + else: + r['needs_update'][s.name()] = { + 'current_name': s.container_image_name, + 'current_id': s.container_image_id, + } + return trivial_result(json.dumps(r, indent=4))