]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/ssh: add 'upgrade check' command
authorSage Weil <sage@redhat.com>
Wed, 4 Dec 2019 21:27:34 +0000 (15:27 -0600)
committerSage Weil <sage@redhat.com>
Thu, 5 Dec 2019 16:28:43 +0000 (10:28 -0600)
Signed-off-by: Sage Weil <sage@redhat.com>
src/pybind/mgr/orchestrator.py
src/pybind/mgr/orchestrator_cli/module.py
src/pybind/mgr/ssh/module.py

index 6ccefeebfff08487d20ac5ad6f5e78d69f9173e2..c248f3b83a4f8f237dde5012ceed1738235990f3 100644 (file)
@@ -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
index 057dea6bfa54a77ab18818a5a366b518dc774881..ffd1c76c663e014083113b02d71ccdb8d7e852c3 100644 (file)
@@ -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())
index 6c73e505a8efa15beaf257ae077d8e60c4453a3e..c0e545149efd5219cb7964be3abc6f5ec7b4d0c9 100644 (file)
@@ -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))