Hi Harshal,
Some inline comments below. Please feel free to reply back if it does
not make sense to you.
Thanks,
Archana Singh
On 08/30/2016 06:39 PM, harshalp(a)linux.vnet.ibm.com wrote:
From: Harshal Patil <harshalp(a)linux.vnet.ibm.com>
This patch adds support for creating templates on s390x arch
without using libvirt related storage calls
Signed-off-by: Harshal Patil <harshalp(a)linux.vnet.ibm.com>
---
docs/API.md | 2 +
i18n.py | 2 +
model/storagepools.py | 15 +++++--
model/storagevolumes.py | 10 +++--
model/templates.py | 56 +++++++++++++++++++++-----
model/vms.py | 38 ++++++++++++------
osinfo.py | 47 ++++++++++++++++++++--
utils.py | 13 ++++++
vmtemplate.py | 105 ++++++++++++++++++++++++++++++------------------
9 files changed, 213 insertions(+), 75 deletions(-)
diff --git a/docs/API.md b/docs/API.md
index 7bd677f..d8d191a 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -427,6 +427,7 @@ A interface represents available network interface on VM.
over current will be used exclusively for memory hotplug
* cdrom: A volume name or URI to an ISO image
* storagepool: URI of the storagepool where template allocates vm storage.
+ * path : Storage path to store virtual disks without libvirt
* networks *(optional)*: list of networks will be assigned to the new VM.
* disks: An array of requested disks with the following optional fields
(either *size* or *volume* must be specified):
@@ -481,6 +482,7 @@ A interface represents available network interface on VM.
* format: Format of the image. Valid formats: qcow, qcow2, qed, raw, vmdk,
vpc.
* pool: Storage pool information
* name: URI of the storagepool where template allocates vm disk.
+ * path (optional): Either pool or path to store the virtual disks should be
specified
* graphics *(optional)*: A dict of graphics paramenters of this template
* type: The type of graphics. It can be VNC or spice or None.
* vnc: Graphical display using the Virtual Network
diff --git a/i18n.py b/i18n.py
index e8d9c05..8e55e01 100644
--- a/i18n.py
+++ b/i18n.py
@@ -190,6 +190,8 @@ messages = {
"KCHTMPL0031E": _("Memory value (%(mem)sMiB) must be equal or lesser
than maximum memory value (%(maxmem)sMiB)"),
"KCHTMPL0032E": _("Unable to update template due error:
%(err)s"),
"KCHTMPL0033E": _("Parameter 'disks' requires at least one
disk object"),
+ "KCHTMPL0034E": _("Storage without libvirt pool is not supported on
this architecture"),
+ "KCHTMPL0035E": _("Error while creating the virtual disk for the
guest. Details: %(err)s"),
"KCHPOOL0001E": _("Storage pool %(name)s already exists"),
"KCHPOOL0002E": _("Storage pool %(name)s does not exist"),
diff --git a/model/storagepools.py b/model/storagepools.py
index a2dbaec..cbd756b 100644
--- a/model/storagepools.py
+++ b/model/storagepools.py
@@ -32,7 +32,7 @@ from wok.plugins.kimchi.model.host import DeviceModel
from wok.plugins.kimchi.model.libvirtstoragepool import StoragePoolDef
from wok.plugins.kimchi.osinfo import defaults as tmpl_defaults
from wok.plugins.kimchi.scan import Scanner
-from wok.plugins.kimchi.utils import pool_name_from_uri
+from wok.plugins.kimchi.utils import pool_name_from_uri, is_s390x
ISO_POOL_NAME = u'kimchi_isos'
@@ -56,6 +56,7 @@ STORAGE_SOURCES = {'netfs': {'addr':
'/pool/source/host/@name',
class StoragePoolsModel(object):
+
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
@@ -71,6 +72,11 @@ class StoragePoolsModel(object):
def _check_default_pools(self):
pools = {}
+ if 'disks' not in tmpl_defaults or len(tmpl_defaults['disks'])
== 0 \
+ or (not tmpl_defaults.get('disks')[0].get(
+ 'pool') and is_s390x()): # s390x specific handling
Can we
have some more details in comments on s390x checks?
+ return
+ tmpl_defaults.get('disks')
default_pool =
tmpl_defaults['disks'][0]['pool']['name']
default_pool = default_pool.split('/')[-1]
@@ -436,9 +442,10 @@ class StoragePoolModel(object):
for tmpl in templates:
t_info = session.get('template', tmpl)
for disk in t_info['disks']:
- t_pool = disk['pool']['name']
- if pool_name_from_uri(t_pool) == pool_name:
- return True
+ if 'pool' in disk:
+ t_pool = disk['pool']['name']
+ if pool_name_from_uri(t_pool) == pool_name:
+ return True
return False
def deactivate(self, name):
diff --git a/model/storagevolumes.py b/model/storagevolumes.py
index 7b2272b..1e4a2af 100644
--- a/model/storagevolumes.py
+++ b/model/storagevolumes.py
@@ -41,8 +41,7 @@ from wok.plugins.kimchi.kvmusertests import UserTests
from wok.plugins.kimchi.model.diskutils import get_disk_used_by
from wok.plugins.kimchi.model.diskutils import set_disk_used_by
from wok.plugins.kimchi.model.storagepools import StoragePoolModel
-from wok.plugins.kimchi.utils import get_next_clone_name
-
+from wok.plugins.kimchi.utils import get_next_clone_name, is_s390x
VOLUME_TYPE_MAP = {0: 'file',
1: 'block',
@@ -275,8 +274,11 @@ class StorageVolumeModel(object):
self.task = TaskModel(**kargs)
self.storagevolumes = StorageVolumesModel(**kargs)
self.storagepool = StoragePoolModel(**kargs)
- if self.conn.get() is not None:
- self.libvirt_user = UserTests().probe_user()
+ if is_s390x(): # s390x specific handling
+ if self.conn.get() is not None:
+ self.libvirt_user = UserTests().probe_user()
+ else:
+ self.libvirt_user = None
else:
self.libvirt_user = None
In case of architecture other than s390x
also UserTests().probe_user()
is called incase self.conn.get() is not None, otherwise
self.libvirt_user is assigned to None. Any specific reason of having
architecture check and doing the same thing?
diff --git a/model/templates.py b/model/templates.py
index a299c85..4edd98e 100644
--- a/model/templates.py
+++ b/model/templates.py
@@ -28,7 +28,8 @@ import urlparse
from wok.exception import InvalidOperation, InvalidParameter
from wok.exception import NotFoundError, OperationFailed
-from wok.utils import probe_file_permission_as_user, run_setfacl_set_attr
+from wok.utils import probe_file_permission_as_user, run_command
+from wok.utils import run_setfacl_set_attr
from wok.xmlutils.utils import xpath_get_text
from wok.plugins.kimchi.config import get_kimchi_version
@@ -47,6 +48,7 @@ if os.uname()[4] in ['ppc', 'ppc64',
'ppc64le']:
class TemplatesModel(object):
+
def __init__(self, **kargs):
self.objstore = kargs['objstore']
self.conn = kargs['conn']
@@ -142,7 +144,7 @@ class TemplatesModel(object):
get_kimchi_version())
except InvalidOperation:
raise
- except Exception, e:
+ except Exception as e:
raise OperationFailed('KCHTMPL0020E', {'err': e.message})
return name
@@ -171,6 +173,7 @@ class TemplatesModel(object):
class TemplateModel(object):
+
def __init__(self, **kargs):
self.objstore = kargs['objstore']
self.conn = kargs['conn']
@@ -198,10 +201,9 @@ class TemplateModel(object):
# set default name
subfixs = [v[len(name):] for v in self.templates.get_list()
if v.startswith(name)]
- indexs = [int(v.lstrip("-clone")) for v in subfixs
- if v.startswith("-clone") and
- v.lstrip("-clone").isdigit()]
- indexs.sort()
+ indexs = sorted([int(v.lstrip("-clone")) for v in subfixs
+ if v.startswith("-clone") and
+ v.lstrip("-clone").isdigit()])
index = "1" if not indexs else str(indexs[-1] + 1)
clone_name = name + "-clone" + index
@@ -267,7 +269,7 @@ class TemplateModel(object):
except InvalidOperation:
raise
- except Exception, e:
+ except Exception as e:
raise OperationFailed('KCHTMPL0032E', {'err': e.message})
return params['name']
@@ -290,7 +292,7 @@ def validate_memory(memory):
# memory limit
if (current > (MAX_MEM_LIM >> 10)) or (maxmem > (MAX_MEM_LIM >>
10)):
raise InvalidParameter("KCHVM0079E",
- {'value': str(MAX_MEM_LIM / (1024**3))})
+ {'value': str(MAX_MEM_LIM / (1024 ** 3))})
if (current > host_memory) or (maxmem > host_memory):
raise InvalidParameter("KCHVM0078E", {'memHost':
host_memory})
@@ -316,6 +318,7 @@ def validate_memory(memory):
class LibvirtVMTemplate(VMTemplate):
+
def __init__(self, args, scan=False, conn=None):
self.conn = conn
netboot = True if 'netboot' in args.keys() else False
@@ -398,16 +401,47 @@ class LibvirtVMTemplate(VMTemplate):
raise NotFoundError("KCHVOL0002E", {'name': vol,
'pool': pool})
+ def _create_disk_image(self, format_type, path, capacity):
This should not be
part of libvirtVMTemplate class as name says I guess
we should not have any non libvirt related handling here. What do you think?
+ """
+ Create a disk image for the Guest
+ Args:
+ format: Format of the storage. e.g. qcow2
+ path: Path where the virtual disk will be created
+ capacity: Capacity of the virtual disk in GBs
+
+ Returns:
+
+ """
+ out, err, rc = run_command(
+ ["/usr/bin/qemu-img", "create", "-f",
format_type, "-o",
+ "preallocation=metadata", path, str(capacity) + "G"])
str(capacity) will throw error in case of unicode characters. I will
suggest to ensure that its integer and use encode or decode methods to
do str conversion.
Does wok_log is taken care inside run_command, if not we need to take
care of that also.
+
+ if rc != 0:
+ raise OperationFailed("KCHTMPL0035E", {'err': err})
+
+ return
+
def fork_vm_storage(self, vm_uuid):
# Provision storages:
vol_list = self.to_volume_list(vm_uuid)
try:
for v in vol_list:
- pool = self._get_storage_pool(v['pool'])
- # outgoing text to libvirt, encode('utf-8')
- pool.createXML(v['xml'].encode('utf-8'), 0)
+ if v['pool'] is not None:
If 'pool' key will not
present, it will throw key error. Is this
expected to be the behaviour?
Are we saying that key should be there but value can be None?
+ pool =
self._get_storage_pool(v['pool'])
+ # outgoing text to libvirt, encode('utf-8')
+ pool.createXML(v['xml'].encode('utf-8'), 0)
+ else:
+ capacity = v['capacity']
+ format_type = v['format']
+ path = v['path']
+ self._create_disk_image(
+ format_type=format_type,
+ path=path,
+ capacity=capacity)
I think as name suggested
to_volume_list, it should look correct from
naming point of view as iterating to volume and handing non volume
related stuff. What do you think?
+
except libvirt.libvirtError as e:
raise OperationFailed("KCHVMSTOR0008E", {'error':
e.message})
+
return vol_list
def set_cpu_info(self):
diff --git a/model/vms.py b/model/vms.py
index 3380278..5d1eebb 100644
--- a/model/vms.py
+++ b/model/vms.py
@@ -60,13 +60,13 @@ from wok.plugins.kimchi.model.utils import remove_metadata_node
from wok.plugins.kimchi.model.utils import set_metadata_node
from wok.plugins.kimchi.osinfo import defaults, MEM_DEV_SLOTS
from wok.plugins.kimchi.screenshot import VMScreenshot
-from wok.plugins.kimchi.utils import get_next_clone_name
+from wok.plugins.kimchi.utils import get_next_clone_name, is_s390x
from wok.plugins.kimchi.utils import template_name_from_uri
from wok.plugins.kimchi.xmlutils.bootorder import get_bootorder_node
from wok.plugins.kimchi.xmlutils.bootorder import get_bootmenu_node
from wok.plugins.kimchi.xmlutils.cpu import get_topology_xml
from wok.plugins.kimchi.xmlutils.disk import get_vm_disk_info, get_vm_disks
-from utils import has_cpu_numa, set_numa_memory
+from .utils import has_cpu_numa, set_numa_memory
DOM_STATE_MAP = {0: 'nostate',
@@ -114,6 +114,7 @@ vm_locks = {}
class VMsModel(object):
+
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
@@ -231,6 +232,7 @@ class VMsModel(object):
class VMModel(object):
+
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
@@ -373,7 +375,7 @@ class VMModel(object):
vir_dom = self.get_vm(name, self.conn)
flags = libvirt.VIR_DOMAIN_XML_SECURE
xml = vir_dom.XMLDesc(flags).decode('utf-8')
- except libvirt.libvirtError, e:
+ except libvirt.libvirtError as e:
raise OperationFailed('KCHVM0035E', {'name': name,
'err': e.message})
@@ -407,7 +409,7 @@ class VMModel(object):
vir_conn = self.conn.get()
dom = vir_conn.defineXML(xml)
self._update_metadata_name(dom, nonascii_name)
- except libvirt.libvirtError, e:
+ except libvirt.libvirtError as e:
raise OperationFailed('KCHVM0035E', {'name': name,
'err': e.message})
@@ -480,7 +482,7 @@ class VMModel(object):
orig_pool_name = vir_pool.name().decode('utf-8')
orig_vol_name = vir_orig_vol.name().decode('utf-8')
- except libvirt.libvirtError, e:
+ except libvirt.libvirtError as e:
raise OperationFailed('KCHVM0035E', {'name':
domain_name,
'err': e.message})
@@ -1366,7 +1368,7 @@ class VMModel(object):
# "OperationFailed" in that case.
try:
snapshot_names = self.vmsnapshots.get_list(name)
- except OperationFailed, e:
+ except OperationFailed as e:
wok_log.error('cannot list snapshots: %s; '
'skipping snapshot deleting...' % e.message)
else:
@@ -1394,6 +1396,14 @@ class VMModel(object):
except libvirt.libvirtError as e:
wok_log.error('Unable to get storage volume by path: %s' %
e.message)
Below changes will not get called if
libvirtError will be thrown for the
path given. I guess we need to ensure that even if libvirt pool and
volume does not exit for path provided below gets executed for s390x.
+ try:
+ if is_s390x(): # s390x specific handling
+ if os.path.exists(path):
+ os.remove(path)
+ except Exception as e:
+ wok_log.error('Unable to delete storage path: %s' %
+ e.message)
+
except Exception as e:
raise OperationFailed('KCHVOL0017E', {'err':
e.message})
@@ -1538,7 +1548,7 @@ class VMModel(object):
raise OperationFailed("KCHVM0081E",
{'dir': serialconsole.BASE_DIRECTORY})
- websocket.add_proxy_token(name.encode('utf-8')+'-console',
+ websocket.add_proxy_token(name.encode('utf-8') + '-console',
os.path.join(serialconsole.BASE_DIRECTORY,
name.encode('utf-8')), True)
@@ -1596,7 +1606,7 @@ class VMModel(object):
try:
vir_dom.suspend()
- except libvirt.libvirtError, e:
+ except libvirt.libvirtError as e:
raise OperationFailed('KCHVM0038E', {'name': name,
'err': e.message})
@@ -1617,7 +1627,7 @@ class VMModel(object):
try:
vir_dom.resume()
- except libvirt.libvirtError, e:
+ except libvirt.libvirtError as e:
raise OperationFailed('KCHVM0040E', {'name': name,
'err': e.message})
@@ -1657,7 +1667,7 @@ class VMModel(object):
'destarch': dest_arch
}
)
- except Exception, e:
+ except Exception as e:
raise OperationFailed("KCHVM0066E", {'error':
e.message})
finally:
@@ -1768,7 +1778,7 @@ class VMModel(object):
ssh_client,
id_rsa_data
)
- except Exception, e:
+ except Exception as e:
raise OperationFailed(
"KCHVM0068E",
{'host': remote_host, 'user': user, 'error':
e.message}
@@ -1833,7 +1843,7 @@ class VMModel(object):
conn = self.conn.get()
vol_obj = conn.storageVolLookupByPath(disk_path)
return vol_obj.info()[1]
- except Exception, e:
+ except Exception as e:
raise OperationFailed(
"KCHVM0062E",
{'path': disk_path, 'error': e.message}
@@ -1949,6 +1959,7 @@ class VMModel(object):
class VMScreenshotModel(object):
+
def __init__(self, **kargs):
self.objstore = kargs['objstore']
self.conn = kargs['conn']
@@ -1995,6 +2006,7 @@ class VMScreenshotModel(object):
class LibvirtVMScreenshot(VMScreenshot):
+
def __init__(self, vm_uuid, conn):
VMScreenshot.__init__(self, vm_uuid)
self.conn = conn
@@ -2004,7 +2016,7 @@ class LibvirtVMScreenshot(VMScreenshot):
fd = opaque
os.write(fd, buf)
- fd = os.open(thumbnail, os.O_WRONLY | os.O_TRUNC | os.O_CREAT, 0644)
+ fd = os.open(thumbnail, os.O_WRONLY | os.O_TRUNC | os.O_CREAT, 0o644)
try:
conn = self.conn.get()
dom = conn.lookupByUUIDString(self.vm_uuid)
diff --git a/osinfo.py b/osinfo.py
index 2c59312..524b3bd 100644
--- a/osinfo.py
+++ b/osinfo.py
@@ -146,6 +146,12 @@ def _get_tmpl_defaults():
'maxmemory': _get_default_template_mem()}
tmpl_defaults['storage']['disk.0'] = {'size': 10,
'format': 'qcow2',
'pool': 'default'}
+ is_on_s390x = True if _get_arch() == 's390x' else False
+
+ if is_on_s390x:
+ tmpl_defaults['storage']['disk.0']['path'] =
'/var/lib/libvirt/images/'
+ del tmpl_defaults['storage']['disk.0']['pool']
+
tmpl_defaults['processor']['vcpus'] = 1
tmpl_defaults['processor']['maxvcpus'] = 1
tmpl_defaults['graphics'] = {'type': 'vnc',
'listen': '127.0.0.1'}
@@ -153,7 +159,12 @@ def _get_tmpl_defaults():
default_config = ConfigObj(tmpl_defaults)
# Load template configuration file
- config_file = os.path.join(kimchiPaths.sysconf_dir, 'template.conf')
+ if is_on_s390x:
+ config_file = os.path.join(
+ kimchiPaths.sysconf_dir,
+ 'template_s390x.conf')
Not sure, but should we handle scenario
where in case s390x specific
arch conf file is not present just go with template.conf?
+ else:
+ config_file = os.path.join(kimchiPaths.sysconf_dir, 'template.conf')
config = ConfigObj(config_file)
# Merge default configuration with file configuration
@@ -174,11 +185,39 @@ def _get_tmpl_defaults():
# Parse storage section to get disks values
storage_section = default_config.pop('storage')
defaults['disks'] = []
- for disk in storage_section.keys():
+
+ pool_exists = False
+ path_exists = False
+ for index, disk in enumerate(storage_section.keys()):
data = storage_section[disk]
data['index'] = int(disk.split('.')[1])
- data['pool'] = {"name":
'/plugins/kimchi/storagepools/' +
- storage_section[disk].pop('pool')}
+ # Right now 'Path' is only supported on s390x
+ if storage_section[disk].get('path') and is_on_s390x:
+ path_exists = True
+ data['path'] = storage_section[disk].pop('path')
+ if 'size' not in storage_section[disk]:
+ data['size'] =
tmpl_defaults['storage']['disk.0']['size']
+ else:
+ data['size'] = storage_section[disk].pop('size')
+
+ if 'format' not in storage_section[disk]:
+ data['format'] =
tmpl_defaults['storage']['disk.0']['format']
+ else:
+ data['format'] = storage_section[disk].pop('format')
+
+ if storage_section[disk].get('pool'):
+ pool_exists = True
+ data['pool'] = {"name":
'/plugins/kimchi/storagepools/' +
+ storage_section[disk].pop('pool')}
For
one disk either it can be pool or path, both should not be added. Do
you agree?
I guess getting pool should be in else of first if.
+
+ # If both pool and path don't exist, pick the defaults
+ if index == len(storage_section.keys()) - 1 and \
+ (not pool_exists and not path_exists):
+ if is_on_s390x: # Special handling for s390x
+ data['path'] =
tmpl_defaults['storage']['disk.0']['path']
+ else:
+ data['pool'] = {"name":
'/plugins/kimchi/storagepools/default'}
+
defaults['disks'].append(data)
# Parse processor section to get vcpus and cpu_topology values
diff --git a/utils.py b/utils.py
index 26d3cf6..b8f81ca 100644
--- a/utils.py
+++ b/utils.py
@@ -24,6 +24,7 @@ import platform
import re
import sqlite3
import time
+import os
import urllib2
from httplib import HTTPConnection, HTTPException
from urlparse import urlparse
@@ -272,3 +273,15 @@ def is_libvirtd_up():
output, error, rc = run_command(cmd, silent=True)
return True if output == 'active\n' else False
+
+
+def is_s390x():
+ """
+ Check if current arch is 's390x'
+ Returns:
+
+ """
do we need new line in comment?
+ if os.uname()[4] == 's390x':
+ return True
+
+ return False
diff --git a/vmtemplate.py b/vmtemplate.py
index 7ac0541..c0d51a5 100644
--- a/vmtemplate.py
+++ b/vmtemplate.py
@@ -31,7 +31,8 @@ from wok.exception import MissingParameter, OperationFailed
from wok.plugins.kimchi import imageinfo
from wok.plugins.kimchi import osinfo
from wok.plugins.kimchi.isoinfo import IsoImage
-from wok.plugins.kimchi.utils import check_url_path, pool_name_from_uri
+from wok.plugins.kimchi.utils import check_url_path, is_s390x
+from wok.plugins.kimchi.utils import pool_name_from_uri
from wok.plugins.kimchi.xmlutils.bootorder import get_bootorder_xml
from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml
from wok.plugins.kimchi.xmlutils.disk import get_disk_xml
@@ -42,6 +43,7 @@ from wok.plugins.kimchi.xmlutils.serial import get_serial_xml
class VMTemplate(object):
+
def __init__(self, args, scan=False, netboot=False):
"""
Construct a VM Template from a widely variable amount of information.
@@ -95,35 +97,49 @@ class VMTemplate(object):
disks = self.info.get('disks')
basic_disk = ['index', 'format', 'pool',
'size']
+ basic_path_disk = ['index', 'format', 'path',
'size']
ro_disk = ['index', 'format', 'pool',
'volume']
base_disk = ['index', 'base', 'pool', 'size',
'format']
for index, disk in enumerate(disks):
disk_info = dict(default_disk)
-
- pool = disk.get('pool', default_disk['pool'])
- pool_type = self._get_storage_type(pool['name'])
-
- if pool_type in ['iscsi', 'scsi']:
- disk_info = {'index': 0, 'format': 'raw',
'volume': None}
-
- disk_info.update(disk)
- pool_name = disk_info.get('pool', {}).get('name')
- if pool_name is None:
- raise MissingParameter('KCHTMPL0028E')
-
- keys = sorted(disk_info.keys())
- if ((keys != sorted(basic_disk)) and (keys != sorted(ro_disk)) and
- (keys != sorted(base_disk))):
- raise MissingParameter('KCHTMPL0028E')
-
- if pool_type in ['logical', 'iscsi', 'scsi']:
- if disk_info['format'] != 'raw':
- raise InvalidParameter('KCHTMPL0029E')
-
- disk_info['pool']['type'] = pool_type
- disk_info['index'] = disk_info.get('index', index)
- self.info['disks'][index] = disk_info
+ if disk.get('pool'):
+ pool = disk.get('pool', default_disk.get('pool'))
+ pool_type = self._get_storage_type(pool['name'])
+ if pool_type in ['iscsi', 'scsi']:
+ disk_info = {'index': 0, 'format': 'raw',
'volume': None}
+
+ disk_info.update(disk)
+ pool_name = disk_info.get('pool', {}).get('name')
+ if pool_name is None:
+ raise MissingParameter('KCHTMPL0028E')
+
+ keys = sorted(disk_info.keys())
+ if ((keys != sorted(basic_disk)) and
+ (keys != sorted(ro_disk)) and
+ (keys != sorted(base_disk)) and
+ (keys != basic_path_disk)):
+ raise MissingParameter('KCHTMPL0028E')
+
+ if pool_type in ['logical', 'iscsi', 'scsi']:
+ if disk_info['format'] != 'raw':
+ raise InvalidParameter('KCHTMPL0029E')
+
+ disk_info['pool']['type'] = pool_type
+ disk_info['index'] = disk_info.get('index', index)
+ self.info['disks'][index] = disk_info
+ else:
+ if is_s390x(): # For now support 'path' only on s390x
any
specific reason of keeping if in side else and not just elif?
+ path = disk.get('path',
default_disk['path'])
+ disk_info.update(disk)
+ keys = sorted(disk_info.keys())
+ if keys != sorted(basic_path_disk):
+ raise MissingParameter('KCHTMPL0028E')
i18n
message has to be changed to convey that either pool or path has to
be given in a disk, as current is "/KCHTMPL0028E/": _("When setting
template disks, following parameters are required: 'index', 'pool name',
'format', 'size' or 'volume' (for scsi/iscsi pools)")
+ disk_info['path'] = path
+ disk_info['index'] = disk_info.get('index', index)
+ self.info['disks'][index] = disk_info
+ else:
+ raise InvalidParameter('KCHTMPL0034E')
def _get_os_info(self, args, scan):
distro = version = 'unknown'
@@ -217,8 +233,9 @@ class VMTemplate(object):
params = dict(base_disk_params)
params['format'] = disk['format']
params['index'] = index
- params.update(locals().get('%s_disk_params' %
- disk['pool']['type'], {}))
+ if disk.get('pool'):
+ params.update(locals().get('%s_disk_params' %
+ disk['pool']['type'], {}))
volume = disk.get('volume')
if volume is not None:
@@ -226,9 +243,13 @@ class VMTemplate(object):
volume)
else:
img = "%s-%s.img" % (vm_uuid, params['index'])
- storage_path =
self._get_storage_path(disk['pool']['name'])
+ if disk.get('pool'):
+ storage_path =
self._get_storage_path(disk['pool']['name'])
+ params['pool_type'] = disk['pool']['type']
+ elif disk.get('path'):
+ storage_path = disk.get('path')
+ params['pool_type'] = None
params['path'] = os.path.join(storage_path, img)
- params['pool_type'] = disk['pool']['type']
disks_xml += get_disk_xml(params)[1]
return unicode(disks_xml, 'utf-8')
@@ -237,20 +258,24 @@ class VMTemplate(object):
ret = []
for i, d in enumerate(self.info['disks']):
# Create only .img. If storagepool is (i)SCSI, volumes will be LUNs
- if d['pool']['type'] in ["iscsi",
"scsi"]:
+ if not is_s390x() and d['pool']['type'] in
["iscsi", "scsi"]:
continue
in case of s390x also if pool is present and type is
iscsi or scsi we
should continue.
so the check should be:- in case of arch is 390x if pool is not present
or if pool of type iscsi or scsi just continue. Or can have for all arch
also that if pool not present or if pool type is scsi or iscsi just
continue.
@Aline: What do you think, pool not present just continue can be true
for all arch. Or you think we should get key error in case of non s390x
arch?
index = d.get('index', i)
volume = "%s-%s.img" % (vm_uuid, index)
- storage_path = self._get_storage_path(d['pool']['name'])
+ if 'path' in d:
+ storage_path = d['path']
+ else:
+ storage_path =
self._get_storage_path(d['pool']['name'])
+
I guess as this method is meant for libvirt volume listing, I guess we
should restructure.
May be one method to deal with pool and vol, and another to deal with
path, and use both while iterating through list of disks.
info = {'name': volume,
'capacity': d['size'],
'format': d['format'],
'path': '%s/%s' % (storage_path, volume),
- 'pool': d['pool']['name']}
+ 'pool': d['pool']['name'] if 'pool'
in d else None}
- if 'logical' == d['pool']['type'] or \
+ if ('pool' in d and 'logical' ==
d['pool']['type']) or \
info['format'] not in ['qcow2', 'raw']:
info['allocation'] = info['capacity']
else:
@@ -444,8 +469,9 @@ class VMTemplate(object):
def validate(self):
for disk in self.info.get('disks'):
- pool_uri = disk.get('pool', {}).get('name')
- self._get_storage_pool(pool_uri)
+ if not is_s390x(): # s390x specific handling
+ pool_uri = disk.get('pool', {}).get('name')
+ self._get_storage_pool(pool_uri)
Again in case of s390x also if
pool is present, it should validate it.
self._network_validate()
self._iso_validate()
self.cpuinfo_validate()
@@ -494,10 +520,11 @@ class VMTemplate(object):
# validate storagepools and image-based templates integrity
for disk in self.info['disks']:
- pool_uri = disk['pool']['name']
- pool_name = pool_name_from_uri(pool_uri)
- if pool_name not in self._get_active_storagepools_name():
- invalid['storagepools'] = [pool_name]
+ if 'pool' in disk:
+ pool_uri = disk['pool']['name']
+ pool_name = pool_name_from_uri(pool_uri)
+ if pool_name not in self._get_active_storagepools_name():
+ invalid['storagepools'] = [pool_name]
if disk.get("base") is None:
continue