[Kimchi-devel] [PATCH 02/13] refactor model: Create a separated model for debugreport resource

Aline Manera alinefm at linux.vnet.ibm.com
Fri Jan 17 02:24:38 UTC 2014


From: Aline Manera <alinefm at br.ibm.com>

To avoid duplicating code in model and mockmodel, the common code related to
debugreport resource was added to model_/debugreports.py and the specific code
for each backend (libvirt or mock) was added to model_/libvirtbackend.py and
model_/mockbackend.py

Signed-off-by: Aline Manera <alinefm at br.ibm.com>
---
 src/kimchi/model_/debugreports.py   |   86 +++++++++++++++++++++++++++++++++++
 src/kimchi/model_/libvirtbackend.py |   85 ++++++++++++++++++++++++++++++++++
 src/kimchi/model_/mockbackend.py    |   27 +++++++++++
 3 files changed, 198 insertions(+)
 create mode 100644 src/kimchi/model_/debugreports.py

diff --git a/src/kimchi/model_/debugreports.py b/src/kimchi/model_/debugreports.py
new file mode 100644
index 0000000..4db1ace
--- /dev/null
+++ b/src/kimchi/model_/debugreports.py
@@ -0,0 +1,86 @@
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2013
+#
+# Authors:
+#  Adam Litke <agl at linux.vnet.ibm.com>
+#  Aline Manera <alinefm at linux.vnet.ibm.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+
+import glob
+import os
+import time
+
+from kimchi import config
+from kimchi.exception import NotFoundError
+
+class DebugReports(object):
+    def __init__(self, backend):
+        pass
+
+    def get_list(self):
+        path = config.get_debugreports_path()
+        file_pattern = os.path.join(path, '*.*')
+        file_lists = glob.glob(file_pattern)
+        file_lists = [os.path.split(file)[1] for file in file_lists]
+        name_lists = [file.split('.', 1)[0] for file in file_lists]
+
+        return name_lists
+
+class DebugReport(object):
+    def __init__(self, backend):
+        self.backend = backend
+
+    def lookup(self, name):
+        file_target = self._get_debugreport(name)
+        ctime = os.stat(file_target).st_ctime
+        ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime))
+        file_target = os.path.split(file_target)[-1]
+        file_target = os.path.join("/data/debugreports", file_target)
+        return {'file': file_target,
+                'ctime': ctime}
+
+    def create(self, params):
+        ident = params['name']
+        taskid = self.backend.gen_debugreport_file(ident)
+        if taskid is None:
+            raise OperationFailed("Debug report tool not found.")
+
+        with self.backend.objstore as session:
+            return session.get('task', str(taskid))
+
+    def delete(self, name):
+        file_target = self._get_debugreports(name)
+        os.remove(file_target)
+
+    def _get_debugreport(self, name):
+        path = config.get_debugreports_path()
+        file_pattern = os.path.join(path, name + '.*')
+        try:
+            file_target = glob.glob(file_pattern)[0]
+        except IndexError:
+            raise NotFoundError("Debug report '%s' not found.")
+
+        return file_target
+
+class DebugReportContent(object):
+    def __init__(self, backend):
+        self.backend = backend
+
+    def lookup(self, name):
+        debugreport = DebugReports(backend)
+        return self.debugreport.lookup(name)
diff --git a/src/kimchi/model_/libvirtbackend.py b/src/kimchi/model_/libvirtbackend.py
index 0c70116..ea46a13 100644
--- a/src/kimchi/model_/libvirtbackend.py
+++ b/src/kimchi/model_/libvirtbackend.py
@@ -21,8 +21,93 @@
 # License along with this library; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 
+import fnmatch
+import glob
+import logging
+import os
+import shutil
+import subprocess
+
+from kimchi import config
+from kimchi.asynctask import AsyncTask
+from kimchi.exception import OperationFailed
 from kimchi.objectstore import ObjectStore
+from kimchi.utils import kimchi_log
 
 class LibvirtBackend(object):
     def __init__(self, objstore_loc=None):
         self.objstore = ObjectStore(objstore_loc)
+        self.next_taskid = 1
+
+        # Please add new possible debug report command here
+        # and implement the report generating function
+        # based on the new report command
+        self.report_tools = ({'cmd': 'sosreport --help',
+                              'fn': self._sosreport_generate},)
+
+    def gen_debugreport_file(self, name):
+        gen_cmd = self._get_system_report_tool()
+        if gen_cmd is None:
+            return None
+
+        return self.add_task('', gen_cmd, name)
+
+    def _get_system_report_tool(self):
+        # check if the command can be found by shell one by one
+        for helper_tool in self.report_tools:
+            try:
+                retcode = subprocess.call(helper_tool['cmd'], shell=True,
+                                          stdout=subprocess.PIPE,
+                                          stderr=subprocess.PIPE)
+                if retcode == 0:
+                    return helper_tool['fn']
+            except Exception, e:
+                kimchi_log.info('Exception running command: %s', e)
+
+        return None
+
+    def _sosreport_generate(self, cb, name):
+        command = 'sosreport --batch --name "%s"' % name
+        try:
+            retcode = subprocess.call(command, shell=True,
+                                      stdout=subprocess.PIPE,
+                                      stderr=subprocess.PIPE)
+            if retcode < 0:
+                raise OperationFailed('Command terminated with signal')
+            elif retcode > 0:
+                raise OperationFailed('Command failed: rc = %i' % retcode)
+
+            pattern = '/tmp/sosreport-%s-*' % name
+            for reportFile in glob.glob(pattern):
+                if not fnmatch.fnmatch(reportFile, '*.md5'):
+                    output = reportFile
+                    break
+            else:
+                # sosreport tends to change the name mangling rule and
+                # compression file format between different releases.
+                # It's possible to fail to match a report file even sosreport
+                # runs successfully. In future we might have a general name
+                # mangling function in kimchi to format the name before passing
+                # it to sosreport. Then we can delete this exception.
+                raise OperationFailed('Can not find generated debug report '
+                                      'named by %s' % pattern)
+            ext = output.split('.', 1)[1]
+            path = config.get_debugreports_path()
+            target = os.path.join(path, name)
+            target_file = '%s.%s' % (target, ext)
+            shutil.move(output, target_file)
+            os.remove('%s.md5' % output)
+            cb('OK', True)
+        except Exception, e:
+            # No need to call cb to update the task status here.
+            # The task object will catch the exception rasied here
+            # and update the task status there
+            log = logging.getLogger('Model')
+            log.warning('Exception in generating debug file: %s', e)
+            raise OperationFailed(e)
+
+    def add_task(self, target_uri, fn, opaque=None):
+        id = self.next_taskid
+        self.next_taskid += 1
+        task = AsyncTask(id, target_uri, fn, self.objstore, opaque)
+        return id
diff --git a/src/kimchi/model_/mockbackend.py b/src/kimchi/model_/mockbackend.py
index e3c6ab9..fa60fc1 100644
--- a/src/kimchi/model_/mockbackend.py
+++ b/src/kimchi/model_/mockbackend.py
@@ -21,8 +21,35 @@
 # License along with this library; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 
+import os
+import random
+
+from kimchi import config
+from kimchi.asynctask import AsyncTask
 from kimchi.objectstore import ObjectStore
 
 class MockBackend(object):
     def __init__(self, objstore_loc=None):
         self.objstore = ObjectStore(objstore_loc)
+        self.next_taskid = 1
+
+    def gen_debugreport_file(self, ident):
+        return self.add_task('', self._create_debugreport, ident)
+
+    def _create_debugreport(self, cb, name):
+        path = config.get_debugreports_path()
+        tmpf = os.path.join(path, name + '.tmp')
+        realf = os.path.join(path, name + '.txt')
+        length = random.randint(1000, 10000)
+        with open(tmpf, 'w') as fd:
+            while length:
+                fd.write('mock debug report\n')
+                length = length - 1
+        os.rename(tmpf, realf)
+        cb("OK", True)
+
+    def add_task(self, target_uri, fn, opaque=None):
+        id = self.next_taskid
+        self.next_taskid += 1
+        task = AsyncTask(id, target_uri, fn, self.objstore, opaque)
+        return id
-- 
1.7.10.4




More information about the Kimchi-devel mailing list