]> git.apps.os.sepia.ceph.com Git - teuthology.git/commitdiff
Add console_log task
authorZack Cerza <zack@redhat.com>
Thu, 18 Aug 2016 21:53:02 +0000 (15:53 -0600)
committerZack Cerza <zack@redhat.com>
Tue, 23 Aug 2016 20:40:20 +0000 (14:40 -0600)
Signed-off-by: Zack Cerza <zack@redhat.com>
teuthology/task/console_log.py [new file with mode: 0644]
teuthology/test/task/test_console_log.py [new file with mode: 0644]

diff --git a/teuthology/task/console_log.py b/teuthology/task/console_log.py
new file mode 100644 (file)
index 0000000..2624aed
--- /dev/null
@@ -0,0 +1,90 @@
+import logging
+import os
+
+from teuthology.orchestra.cluster import Cluster
+
+from . import Task
+
+log = logging.getLogger(__name__)
+
+
+class ConsoleLog(Task):
+    enabled = True
+    name = 'console_log'
+
+    def __init__(self, ctx=None, config=None):
+        super(ConsoleLog, self).__init__(ctx, config)
+        if self.config.get('enabled') is False:
+            self.enabled = False
+        if not getattr(self.ctx, 'archive', None):
+            self.enabled = False
+
+    def filter_hosts(self):
+        super(ConsoleLog, self).filter_hosts()
+        if not hasattr(self.ctx, 'cluster'):
+            return
+        new_cluster = Cluster()
+        for (remote, roles) in self.cluster.remotes.iteritems():
+            if not hasattr(remote.console, 'spawn_sol_log'):
+                log.debug("%s does not support IPMI; excluding",
+                          remote.shortname)
+            elif not remote.console.has_credentials:
+                log.debug("IPMI credentials not found for %s; excluding",
+                          remote.shortname)
+            else:
+                new_cluster.add(remote, roles)
+        self.cluster = new_cluster
+        return self.cluster
+
+    def setup(self):
+        if not self.enabled:
+            return
+        super(ConsoleLog, self).setup()
+        self.processes = list()
+        self.setup_archive()
+
+    def setup_archive(self):
+        self.archive_dir = os.path.join(
+            self.ctx.archive,
+            'console_logs',
+        )
+        os.makedirs(self.archive_dir)
+
+    def begin(self):
+        if not self.enabled:
+            return
+        super(ConsoleLog, self).begin()
+        self.start_logging()
+
+    def start_logging(self):
+        for remote in self.cluster.remotes.keys():
+            log_path = os.path.join(
+                self.archive_dir,
+                "%s.log" % remote.shortname,
+            )
+            proc = remote.console.spawn_sol_log(log_path)
+            self.processes.append(proc)
+
+    def end(self):
+        if not self.enabled:
+            return
+        super(ConsoleLog, self).end()
+        self.stop_logging()
+
+    def stop_logging(self, force=False):
+        for proc in self.processes:
+            if proc.poll() is not None:
+                continue
+            if force:
+                proc.kill()
+            else:
+                proc.terminate()
+
+    def teardown(self):
+        if not self.enabled:
+            return
+        self.stop_logging(force=True)
+        super(ConsoleLog, self).teardown()
+
+
+task = ConsoleLog
diff --git a/teuthology/test/task/test_console_log.py b/teuthology/test/task/test_console_log.py
new file mode 100644 (file)
index 0000000..e16eec2
--- /dev/null
@@ -0,0 +1,78 @@
+import os
+
+from mock import patch
+
+from teuthology.config import FakeNamespace
+from teuthology.config import config as teuth_config
+from teuthology.orchestra.cluster import Cluster
+from teuthology.orchestra.remote import Remote
+from teuthology.task.console_log import ConsoleLog
+
+from . import TestTask
+
+
+class TestConsoleLog(TestTask):
+    klass = ConsoleLog
+    task_name = 'console_log'
+
+    def setup(self):
+        teuth_config.ipmi_domain = 'ipmi.domain'
+        teuth_config.ipmi_user = 'ipmi_user'
+        teuth_config.ipmi_password = 'ipmi_pass'
+        self.ctx = FakeNamespace()
+        self.ctx.cluster = Cluster()
+        self.ctx.cluster.add(Remote('user@remote1'), ['role1'])
+        self.ctx.cluster.add(Remote('user@remote2'), ['role2'])
+        self.ctx.config = dict()
+        self.ctx.archive = '/fake/path'
+        self.task_config = dict()
+        self.start_patchers()
+
+    def start_patchers(self):
+        self.patchers = list()
+        self.patchers.append(patch(
+            'teuthology.task.console_log.os.makedirs',
+        ))
+        for patcher in self.patchers:
+            patcher.start()
+
+    def teardown(self):
+        for patcher in self.patchers:
+            patcher.stop()
+
+    def test_enabled(self):
+        task = self.klass(self.ctx, self.task_config)
+        assert task.enabled is True
+
+    def test_disabled_noarchive(self):
+        self.ctx.archive = None
+        task = self.klass(self.ctx, self.task_config)
+        assert task.enabled is False
+
+    def test_has_credentials(self):
+        for remote in self.ctx.cluster.remotes.keys():
+            remote.console.has_credentials = False
+        task = self.klass(self.ctx, self.task_config)
+        assert len(task.cluster.remotes.keys()) == 0
+
+    def test_remotes(self):
+        with self.klass(self.ctx, self.task_config) as task:
+            assert len(task.cluster.remotes) == len(self.ctx.cluster.remotes)
+
+    @patch('teuthology.orchestra.console.PhysicalConsole')
+    def test_begin(self, m_pconsole):
+        with self.klass(self.ctx, self.task_config) as task:
+            assert len(task.processes) == len(self.ctx.cluster.remotes)
+            for remote in task.cluster.remotes.keys():
+                dest_path = os.path.join(
+                    self.ctx.archive, '%s.log' % remote.shortname)
+                assert remote.console.spawn_sol_log.called_once_with(
+                    dest_path=dest_path)
+
+    @patch('teuthology.orchestra.console.PhysicalConsole')
+    def test_end(self, m_pconsole):
+        with self.klass(self.ctx, self.task_config) as task:
+            pass
+        for proc in task.processes:
+            assert proc.terminate.called_once_with()
+            assert proc.kill.called_once_with()