[Kimchi-devel] [PATCH 11/23] refactor model: Create a separated model for storage pool resource

Aline Manera alinefm at linux.vnet.ibm.com
Wed Jan 29 23:34:52 UTC 2014


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

The model implementation for storage pool and its sub-resources were added to
model_/storagepools.py

Also add default pool verification in Model() as it is not related to
storage pool resource

Signed-off-by: Aline Manera <alinefm at br.ibm.com>
---
 src/kimchi/model_/model.py        |   30 +++++
 src/kimchi/model_/storagepools.py |  246 +++++++++++++++++++++++++++++++++++++
 2 files changed, 276 insertions(+)
 create mode 100644 src/kimchi/model_/storagepools.py

diff --git a/src/kimchi/model_/model.py b/src/kimchi/model_/model.py
index 3603ec1..6f3b6ab 100644
--- a/src/kimchi/model_/model.py
+++ b/src/kimchi/model_/model.py
@@ -41,6 +41,7 @@ class Model(BaseModel):
         kargs = {'objstore': self.objstore, 'conn': self.conn}
 
         if 'qemu:///' in libvirt_uri:
+            self._default_pool_check()
             self._default_network_check()
 
         this = os.path.basename(__file__)
@@ -93,3 +94,32 @@ class Model(BaseModel):
                                    "because of %s, exit kimchid" % e.message,
                                    severity=logging.ERROR)
                 sys.exit(1)
+
+    def _default_pool_check(self):
+        conn = self.conn.get()
+        xml = """
+            <pool type='dir'>
+              <name>default</name>
+              <target>
+                <path>/var/lib/libvirt/images</path>
+              </target>
+            </pool>
+        """
+        try:
+            pool = conn.storagePoolLookupByName("default")
+        except libvirt.libvirtError:
+            try:
+                pool = conn.storagePoolCreateXML(xml, 0)
+            except libvirt.libvirtError, e:
+                cherrypy.log.error("Fatal: Cannot create default pool because "
+                                   "of %s, exit kimchid" % e.message,
+                                   severity=logging.ERROR)
+                sys.exit(1)
+
+        if pool.isActive() == 0:
+            try:
+                pool.create(0)
+            except libvirt.libvirtError, e:
+                err = "Fatal: Default pool cannot be activated, exit kimchid"
+                cherrypy.log.error(err, severity=logging.ERROR)
+                sys.exit(1)
diff --git a/src/kimchi/model_/storagepools.py b/src/kimchi/model_/storagepools.py
new file mode 100644
index 0000000..2fca8e4
--- /dev/null
+++ b/src/kimchi/model_/storagepools.py
@@ -0,0 +1,246 @@
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2013
+#
+# Authors:
+#  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 libvirt
+
+from kimchi import xmlutils
+from kimchi.scan import Scanner
+from kimchi.exception import InvalidOperation, MissingParameter
+from kimchi.exception import NotFoundError, OperationFailed
+from kimchi.model_.libvirtstoragepool import StoragePoolDef
+from kimchi.utils import add_task, kimchi_log
+
+
+ISO_POOL_NAME = u'kimchi_isos'
+POOL_STATE_MAP = {0: 'inactive',
+                  1: 'initializing',
+                  2: 'active',
+                  3: 'degraded',
+                  4: 'inaccessible'}
+
+STORAGE_SOURCES = {'netfs': {'addr': '/pool/source/host/@name',
+                             'path': '/pool/source/dir/@path'}}
+
+
+class StoragePoolsModel(object):
+    def __init__(self, **kargs):
+        self.conn = kargs['conn']
+        self.objstore = kargs['objstore']
+        self.scanner = Scanner(self._clean_scan)
+        self.scanner.delete()
+
+    def get_list(self):
+        try:
+            conn = self.conn.get()
+            names = conn.listStoragePools()
+            names += conn.listDefinedStoragePools()
+            return sorted(names)
+        except libvirt.libvirtError as e:
+            raise OperationFailed(e.get_error_message())
+
+    def create(self, params):
+        task_id = None
+        conn = self.conn.get()
+        try:
+            name = params['name']
+            if name in (ISO_POOL_NAME, ):
+                raise InvalidOperation("StoragePool already exists")
+
+            if params['type'] == 'kimchi-iso':
+                task_id = self._do_deep_scan(params)
+            poolDef = StoragePoolDef.create(params)
+            poolDef.prepare(conn)
+            xml = poolDef.xml
+        except KeyError, key:
+            raise MissingParameter(key)
+
+        if name in self.get_list():
+            err = "The name %s has been used by a pool"
+            raise InvalidOperation(err % name)
+
+        try:
+            if task_id:
+                # Create transient pool for deep scan
+                conn.storagePoolCreateXML(xml, 0)
+                return name
+
+            pool = conn.storagePoolDefineXML(xml, 0)
+            if params['type'] in ['logical', 'dir', 'netfs']:
+                pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW)
+                # autostart dir and logical storage pool created from kimchi
+                pool.setAutostart(1)
+            else:
+                # disable autostart for others
+                pool.setAutostart(0)
+        except libvirt.libvirtError as e:
+            msg = "Problem creating Storage Pool: %s"
+            kimchi_log.error(msg, e)
+            raise OperationFailed(e.get_error_message())
+        return name
+
+    def _clean_scan(self, pool_name):
+        try:
+            conn = self.conn.get()
+            pool = conn.storagePoolLookupByName(pool_name)
+            pool.destroy()
+            with self.objstore as session:
+                session.delete('scanning', pool_name)
+        except Exception, e:
+            err = "Exception %s occured when cleaning scan result"
+            kimchi_log.debug(err % e.message)
+
+    def _do_deep_scan(self, params):
+        scan_params = dict(ignore_list=[])
+        scan_params['scan_path'] = params['path']
+        params['type'] = 'dir'
+
+        for pool in self.get_list():
+            try:
+                res = self.storagepool_lookup(pool)
+                if res['state'] == 'active':
+                    scan_params['ignore_list'].append(res['path'])
+            except Exception, e:
+                err = "Exception %s occured when get ignore path"
+                kimchi_log.debug(err % e.message)
+
+        params['path'] = self.scanner.scan_dir_prepare(params['name'])
+        scan_params['pool_path'] = params['path']
+        task_id = add_task('', self.scanner.start_scan, self.objstore,
+                           scan_params)
+        # Record scanning-task/storagepool mapping for future querying
+        with self.objstore as session:
+                session.store('scanning', params['name'], task_id)
+        return task_id
+
+
+class StoragePoolModel(object):
+    def __init__(self, **kargs):
+        self.conn = kargs['conn']
+        self.objstore = kargs['objstore']
+
+    @staticmethod
+    def get_storagepool(name, conn):
+        conn = conn.get()
+        try:
+            return conn.storagePoolLookupByName(name)
+        except libvirt.libvirtError as e:
+            if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL:
+                raise NotFoundError("Storage Pool '%s' not found" % name)
+            else:
+                raise
+
+    def _get_storagepool_vols_num(self, pool):
+        try:
+            if pool.isActive():
+                pool.refresh(0)
+                return pool.numOfVolumes()
+            else:
+                return 0
+        except libvirt.libvirtError as e:
+            raise OperationFailed(e.get_error_message())
+
+    def _get_storage_source(self, pool_type, pool_xml):
+        source = {}
+        if pool_type not in STORAGE_SOURCES:
+            return source
+
+        for key, val in STORAGE_SOURCES[pool_type].items():
+            res = xmlutils.xpath_get_text(pool_xml, val)
+            source[key] = res[0] if len(res) == 1 else res
+
+        return source
+
+    def lookup(self, name):
+        pool = self.get_storagepool(name, self.conn)
+        info = pool.info()
+        nr_volumes = self._get_storagepool_vols_num(pool)
+        autostart = True if pool.autostart() else False
+        xml = pool.XMLDesc(0)
+        path = xmlutils.xpath_get_text(xml, "/pool/target/path")[0]
+        pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
+        source = self._get_storage_source(pool_type, xml)
+        res = {'state': POOL_STATE_MAP[info[0]],
+               'path': path,
+               'source': source,
+               'type': pool_type,
+               'autostart': autostart,
+               'capacity': info[1],
+               'allocated': info[2],
+               'available': info[3],
+               'nr_volumes': nr_volumes}
+
+        if not pool.isPersistent():
+            # Deal with deep scan generated pool
+            try:
+                with self.objstore as session:
+                    task_id = session.get('scanning', name)
+                res['task_id'] = str(task_id)
+                res['type'] = 'kimchi-iso'
+            except NotFoundError:
+                # User created normal pool
+                pass
+        return res
+
+    def update(self, name, params):
+        autostart = params['autostart']
+        if autostart not in [True, False]:
+            raise InvalidOperation("Autostart flag must be true or false")
+        pool = self.get_storagepool(name, self.conn)
+        if autostart:
+            pool.setAutostart(1)
+        else:
+            pool.setAutostart(0)
+        ident = pool.name()
+        return ident
+
+    def activate(self, name):
+        pool = self.get_storagepool(name, self.conn)
+        try:
+            pool.create(0)
+        except libvirt.libvirtError as e:
+            raise OperationFailed(e.get_error_message())
+
+    def deactivate(self, name):
+        pool = self.get_storagepool(name, self.conn)
+        try:
+            pool.destroy()
+        except libvirt.libvirtError as e:
+            raise OperationFailed(e.get_error_message())
+
+    def delete(self, name):
+        pool = self.get_storagepool(name, self.conn)
+        if pool.isActive():
+            err = "Unable to delete the active storagepool %s"
+            raise InvalidOperation(err % name)
+        try:
+            pool.undefine()
+        except libvirt.libvirtError as e:
+            raise OperationFailed(e.get_error_message())
+
+
+class IsoPoolModel(object):
+    def __init__(self, **kargs):
+        pass
+
+    def lookup(self, name):
+        return {'state': 'active',
+                'type': 'kimchi-iso'}
-- 
1.7.10.4




More information about the Kimchi-devel mailing list