From: Aline Manera <alinefm(a)br.ibm.com>
The model implementation for template and its sub-resources were added to
model_/templates.py
Signed-off-by: Aline Manera <alinefm(a)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(a)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