
First, improve functions inside class. This will improve code reading, also, make more functions to split procedures like: validating disks, graphics xml and distro checking. Add separate function to identify the installation media. Signed-off-by: Ramon Medeiros <ramonn at linux.vnet.ibm.com> --- model/templates.py | 4 ++ vmtemplate.py | 142 +++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 132 insertions(+), 14 deletions(-) diff --git a/model/templates.py b/model/templates.py index b49ac50..a03a7cf 100644 --- a/model/templates.py +++ b/model/templates.py @@ -196,6 +196,10 @@ class TemplateModel(object): params['memory'].update(new_mem) validate_memory(params['memory']) + # params are cdrom or disk: add it to source_media + if "cdrom" in params: + params["source_media"] = params.get("cdrom") + new_t.update(params) for net_name in params.get(u'networks', []): diff --git a/vmtemplate.py b/vmtemplate.py index 4bcf324..8572dfe 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -17,6 +17,7 @@ # 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 magic import os import platform import stat @@ -29,10 +30,13 @@ from lxml.builder import E from wok.exception import InvalidParameter, ImageFormatError, IsoFormatError from wok.exception import MissingParameter, OperationFailed +from wok.xmlutils.utils import xpath_get_text from wok.plugins.kimchi import imageinfo from wok.plugins.kimchi import osinfo from wok.plugins.kimchi.isoinfo import IsoImage +from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection from wok.plugins.kimchi.utils import check_url_path, pool_name_from_uri +from wok.plugins.kimchi.utils import get_template_by_name from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml from wok.plugins.kimchi.xmlutils.disk import get_disk_xml from wok.plugins.kimchi.xmlutils.graphics import get_graphics_xml @@ -40,6 +44,9 @@ from wok.plugins.kimchi.xmlutils.interface import get_iface_xml from wok.plugins.kimchi.xmlutils.qemucmdline import get_qemucmdline_xml from wok.plugins.kimchi.xmlutils.serial import get_serial_xml +DISK_TYPE = {"QEMU QCOW Image": "qcow2", + "data": "raw"} +ISO_TYPE = "ISO 9660 CD-ROM" class VMTemplate(object): def __init__(self, args, scan=False): @@ -54,20 +61,16 @@ class VMTemplate(object): self.info = {} self.fc_host_support = args.get('fc_host_support') - # Fetch defaults based on the os distro and version - try: - distro, version = self._get_os_info(args, scan) - except ImageFormatError as e: - raise OperationFailed('KCHTMPL0020E', {'err': e.message}) - os_distro = args.get('os_distro', distro) - os_version = args.get('os_version', version) - entry = osinfo.lookup(os_distro, os_version) - self.info.update(entry) + # search for template with the same name + template = get_template_by_name(args.get("name")) - # Auto-generate a template name if no one is passed - if 'name' not in args or args['name'] == '': - args['name'] = self._gen_name(distro, version) - self.name = args['name'] + # no record found: create template + if len(template) == 0: + self._create_template(args, scan) + + # template already exists: load it + else: + self.info.update(args) # Merge graphics settings graph_args = args.get('graphics') @@ -87,6 +90,35 @@ class VMTemplate(object): # Override template values according to 'args' self.info.update(args) + + # validate disks + self._validate_disks(default_disk) + + def _create_template(self, args, scan=False): + """ + Creates a new template + """ + # identify installation media + self._identify_installation_media(args) + + # Fetch defaults based on the os distro and version + try: + distro, version = self._get_os_info(args, scan) + except ImageFormatError as e: + raise OperationFailed('KCHTMPL0020E', {'err': e.message}) + os_distro = args.get('os_distro', distro) + os_version = args.get('os_version', version) + entry = osinfo.lookup(os_distro, os_version) + + # update info + self.info.update(entry) + + # Auto-generate a template name if no one is passed + if 'name' not in args or args['name'] == '': + args['name'] = self._gen_name(distro, version) + self.info["name"] = args['name'] + + def _validate_disks(self, default_disk): disks = self.info.get('disks') basic_disk = ['index', 'format', 'pool', 'size'] @@ -95,7 +127,6 @@ class VMTemplate(object): for index, disk in enumerate(disks): disk_info = dict(default_disk) - pool_type = self._get_storage_type(disk['pool']['name']) if pool_type in ['iscsi', 'scsi']: disk_info = {'index': 0, 'format': 'raw', 'volume': None} @@ -118,6 +149,89 @@ class VMTemplate(object): disk_info['index'] = disk_info.get('index', index) self.info['disks'][index] = disk_info + def _identify_installation_media(self, args): + path = args.get("installation_media") + + # user did not passed installation media: return + if path is None: + return + + # create magic object to discover file type + file_type = magic.open(magic.MAGIC_NONE) + file_type.load() + + # file is local and exists: check if it's disk or cdrom + if path.startswith("/") and os.path.exists(path): + ftype = file_type.file(path) + + # cdrom + if ISO_TYPE in ftype: + args["cdrom"] = path + return + + # disk + for types in DISK_TYPE.keys(): + if types in ftype: + + # no disk list: create it + if args.get("disks") is None: + args["disks"] = [] + + # append disk to the list + args["disks"].insert(0, + {"base": path, + "format": DISK_TYPE[types], + "index": 0, + "pool": {"name": + "/plugins/kimchi/storagepools/default", + "type":"dir"}}) + + # get storage pool + pool = self._get_storagepool_from_storagevolume(path) + + # image not in any pool: get default pool + if len(pool) == 0: + os_info = osinfo.lookup("unknow", "unknow")["disks"][0]["pool"] + + # os_info has default pool: get it + if os_info != None: + args["disks"][0]["pool"] = os_info + return + + # pool available + args["disks"][0]["pool"] = pool + + # not local image: set as remote ISO + elif path.startswith("http") or path.startswith("ftp"): + args["cdrom"] = path + return + + def _get_storagepool_from_storagevolume(self, storagevolume_path): + conn = LibvirtConnection('qemu:///system').get() + storagepools = conn.listStoragePools() + storagepools += conn.listDefinedStoragePools() + + # discover storagepool + for storagepool in storagepools: + pool = conn.storagePoolLookupByName(storagepool) + spath = xpath_get_text(pool.XMLDesc(), "/pool/target/path")[0] + pool_type = xpath_get_text(pool.XMLDesc(), "/pool/@type")[0] + storagevolumes = sorted(map(lambda x: x.decode('utf-8'), + pool.listVolumes())) + for storagevolume in storagevolumes: + + # path does not exists: continue to the next + if not os.path.exists("%s/%s" % (spath, storagevolume)): + continue + + # storagepool found: return + volume = "%s/%s" % (spath, storagevolume) + if os.path.samefile(storagevolume_path, volume): + pool_uri = "/plugins/kimchi/storagepools/%s" % storagepool + return {"name": pool_uri, + "type": pool_type} + return {} + def _get_os_info(self, args, scan): distro = version = 'unknown' -- 2.5.0