
From: Aline Manera <alinefm@br.ibm.com> The model implementation for template and its sub-resources were added to model_/templates.py Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/model_/templates.py | 172 ++++++++++++++++++++++++++++++++++++++++ src/kimchi/utils.py | 14 ++++ 2 files changed, 186 insertions(+) create mode 100644 src/kimchi/model_/templates.py diff --git a/src/kimchi/model_/templates.py b/src/kimchi/model_/templates.py new file mode 100644 index 0000000..03632a6 --- /dev/null +++ b/src/kimchi/model_/templates.py @@ -0,0 +1,172 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@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 copy + +import libvirt + +from kimchi import xmlutils +from kimchi.exception import InvalidOperation, InvalidParameter, NotFoundError +from kimchi.utils import pool_name_from_uri +from kimchi.vmtemplate import VMTemplate + + +class TemplatesModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def create(self, params): + name = params['name'] + conn = self.conn.get() + + pool_uri = params.get(u'storagepool', '') + if pool_uri: + pool_name = pool_name_from_uri(pool_uri) + try: + conn.storagePoolLookupByName(pool_name) + except Exception as e: + err = "Storagepool specified is not valid: %s." + raise InvalidParameter(err % e.message) + + for net_name in params.get(u'networks', []): + try: + conn.networkLookupByName(net_name) + except Exception, e: + raise InvalidParameter("Network '%s' specified by template " + "does not exist." % net_name) + + with self.objstore as session: + if name in session.get_list('template'): + raise InvalidOperation("Template already exists") + t = LibvirtVMTemplate(params, scan=True) + session.store('template', name, t.info) + return name + + def get_list(self): + with self.objstore as session: + return session.get_list('template') + + +class TemplateModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + self.templates = TemplatesModel(**kargs) + + @staticmethod + def get_template(name, objstore, conn, overrides=None): + with objstore as session: + params = session.get('template', name) + if overrides: + params.update(overrides) + return LibvirtVMTemplate(params, False, conn) + + def lookup(self, name): + t = self.get_template(name, self.objstore, self.conn) + return t.info + + def delete(self, name): + with self.objstore as session: + session.delete('template', name) + + def update(self, name, params): + old_t = self.lookup(name) + new_t = copy.copy(old_t) + new_t.update(params) + ident = name + + pool_uri = new_t.get(u'storagepool', '') + pool_name = pool_name_from_uri(pool_uri) + try: + conn = self.conn.get() + conn.storagePoolLookupByName(pool_name) + except Exception as e: + err = "Storagepool specified is not valid: %s." + raise InvalidParameter(err % e.message) + + for net_name in params.get(u'networks', []): + try: + conn = self.conn.get() + conn.networkLookupByName(net_name) + except Exception, e: + raise InvalidParameter("Network '%s' specified by template " + "does not exist" % net_name) + + self.delete(name) + try: + ident = self.templates.create(new_t) + except: + ident = self.templates.create(old_t) + raise + return ident + + +class LibvirtVMTemplate(VMTemplate): + def __init__(self, args, scan=False, conn=None): + VMTemplate.__init__(self, args, scan) + self.conn = conn + + def _storage_validate(self): + pool_uri = self.info['storagepool'] + pool_name = pool_name_from_uri(pool_uri) + try: + conn = self.conn.get() + pool = conn.storagePoolLookupByName(pool_name) + except libvirt.libvirtError: + err = 'Storage specified by template does not exist' + raise InvalidParameter(err) + + if not pool.isActive(): + err = 'Storage specified by template is not active' + raise InvalidParameter(err) + + return pool + + def _network_validate(self): + names = self.info['networks'] + for name in names: + try: + conn = self.conn.get() + network = conn.networkLookupByName(name) + except libvirt.libvirtError: + err = 'Network specified by template does not exist' + raise InvalidParameter(err) + + if not network.isActive(): + err = 'Network specified by template is not active' + raise InvalidParameter(err) + + def _get_storage_path(self): + pool = self._storage_validate() + xml = pool.XMLDesc(0) + return xmlutils.xpath_get_text(xml, "/pool/target/path")[0] + + def fork_vm_storage(self, vm_uuid): + # Provision storage: + # TODO: Rebase on the storage API once upstream + pool = self._storage_validate() + vol_list = self.to_volume_list(vm_uuid) + for v in vol_list: + # outgoing text to libvirt, encode('utf-8') + pool.createXML(v['xml'].encode('utf-8'), 0) + return vol_list diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index 30c09d4..5345d28 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -23,6 +23,7 @@ import cherrypy import os +import re import subprocess import urllib2 from threading import Timer @@ -31,12 +32,25 @@ from cherrypy.lib.reprconf import Parser from kimchi import config from kimchi.asynctask import AsyncTask +from kimchi.exception import InvalidParameter, TimeoutExpired kimchi_log = cherrypy.log.error_log task_id = 0 +def _uri_to_name(collection, uri): + expr = '/%s/(.*?)/?$' % collection + m = re.match(expr, uri) + if not m: + raise InvalidParameter(uri) + return m.group(1) + + +def pool_name_from_uri(uri): + return _uri_to_name('storagepools', uri) + + def get_next_task_id(): global task_id task_id += 1 -- 1.7.10.4