[PATCH V1] [Kimchi] Updated API.md to reflect the changes related to host network interfaces in template.
by archus@linux.vnet.ibm.com
From: Archana Singh <archus(a)linux.vnet.ibm.com>
Updated API.md to reflect the changes done in previous patch for adding,
removing, listing host network interfaces in template GET and PUT
APIs implementations.
Signed-off-by: Archana Singh <archus(a)linux.vnet.ibm.com>
---
docs/API.md | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/docs/API.md b/docs/API.md
index 7bd677f..3808054 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -428,6 +428,12 @@ A interface represents available network interface on VM.
* cdrom: A volume name or URI to an ISO image
* storagepool: URI of the storagepool where template allocates vm storage.
* networks *(optional)*: list of networks will be assigned to the new VM.
+ * interfaces *(optional)*: list of host network interfaces will be assigned to the new VM.
+ * type: Type of host network interface. Type should be 'macvtap' for host network interface(Ethernet, Bond, VLAN) to be connected as direct MacVTap or type should be ovs for openvswitch host network interface to be connected as virtual switch to a VM.
+ * name: The host network interface. It should be host network interface(Ethernet, Bond, VLAN) for type 'macvtap' or host openvswitch bridge interface for type ovs.
+ * mode *(optional)*: Only applicable for interface type macvtap, to indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge).
+ * bridge: If packets have a destination on the host from which they originated, they are delivered directly to the target. For direct delivery, both origin and destination devices need to be in bridge mode. If either the origin or destination is in vepa mode, VEPA-capable bridge is required.
+ * vepa: All packets are sent to the external bridge. If packets have a destination on the host from which they originated, the VEPA-capable bridge will return the packets to the host.
* disks: An array of requested disks with the following optional fields
(either *size* or *volume* must be specified):
* index: The device index
@@ -473,6 +479,12 @@ 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
* networks *(optional)*: list of networks will be assigned to the new VM.
+ * interfaces *(optional)*: list of host network interfaces will be assigned to the new VM.
+ * type: Type of host network interface. Type should be 'macvtap' for host network interface(Ethernet, Bond, VLAN) to be connected as direct MacVTap or type should be ovs for openvswitch host network interface to be connected as virtual switch to a VM.
+ * name: The host network interface. It should be host network interface(Ethernet, Bond, VLAN) for type 'macvtap' or host openvswitch bridge interface for type ovs.
+ * mode *(optional)*: Only applicable for interface type macvtap, to indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge).
+ * bridge: If packets have a destination on the host from which they originated, they are delivered directly to the target. For direct delivery, both origin and destination devices need to be in bridge mode. If either the origin or destination is in vepa mode, VEPA-capable bridge is required.
+ * vepa: All packets are sent to the external bridge. If packets have a destination on the host from which they originated, the VEPA-capable bridge will return the packets to the host.
* disks: An array of requested disks with the following optional fields
(either *size* or *volume* must be specified):
* index: The device index
--
2.7.4
8 years, 3 months
[PATCH V1] [Kimchi] Updated code to support add, remove and list host network interface(s) to exiting template.
by archus@linux.vnet.ibm.com
From: Archana Singh <archus(a)linux.vnet.ibm.com>
interfaces is an additional optional attribute and hence exiting functionalities to add,
remove and list networks from/to template are not changed.
Below are the changes:
1) Added i18n error codes.
2) Added interface as new kimchitype in API.json. And ref added in update template.
-Interface expects an object with parameters: 'name', 'type' and 'mode'.
-Name should be name of host network interface(Ethernet, Bond, VLAN) for type 'macvtap'
or name should be name of host openvswitch bridge interface for type ovs.
-Mode only applicable for interface type macvtap to indicates whether packets
has to be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge).
-Mode is Optional.
3) Added interfaces as optional attribute in template control.
-This attribute returns to be list of host interface attached to template,
each interface will have above attribute.
-Empty list if no host network interface is attached to template.
4) Added method to generate valid interface xml from the interface based on above attribute.
-This will use below method to generate interface xml based on type and other attribute.
-Update vm xml generate method to add generated interfaces xml to vm xml.
5) Modified xmlutils which generates interface xml based on interface type and attributes.
Signed-off-by: Archana Singh <archus(a)linux.vnet.ibm.com>
---
API.json | 29 ++++++++++++++++++++-
control/templates.py | 1 +
i18n.py | 2 ++
vmtemplate.py | 24 +++++++++++++++++
xmlutils/interface.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 127 insertions(+), 1 deletion(-)
diff --git a/API.json b/API.json
index a3af02d..e323649 100644
--- a/API.json
+++ b/API.json
@@ -89,7 +89,29 @@
},
"additionalProperties": false,
"error": "KCHTMPL0030E"
- }
+ },
+ "interface": {
+ "description": "Host network interface, this indicates whether to configure the host network interface(Ethernet, Bond, VLAN) as direct MacVTap or to configure interface(OVS) as virtual switch to a VM",
+ "type": "object",
+ "properties": {
+ "type": {
+ "description": "Type of host network interface. Type should be 'macvtap' for host network interface(Ethernet, Bond, VLAN) to be connected as direct MacVTap and type ovs for openvswitch host network interface to be connected as virtual switch to a VM.",
+ "type": "string",
+ "pattern": "^(macvtap|ovs)$"
+ },
+ "name": {
+ "description": "The host network interface. It should be name of host network interface(Ethernet, Bond, VLAN) for type 'macvtap' and name of host openvswitch bridge interface for type ovs",
+ "type": "string"
+ },
+ "mode": {
+ "description": "Only applicable for interface type macvtap, to indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge). Optional.",
+ "type": "string",
+ "pattern": "^(bridge|vepa)$"
+ }
+ },
+ "additionalProperties": false,
+ "error": "KCHTMPL0033E"
+ }
},
"properties": {
"storagepools_create": {
@@ -783,6 +805,11 @@
"items": { "type": "string" },
"error": "KCHTMPL0017E"
},
+ "interfaces": {
+ "description": "list of host interfaces to be assigned to new VM",
+ "type": "array",
+ "items": { "ref": "#/kimchitype/interface" }
+ },
"folder": {
"description": "Folder",
"type": "array",
diff --git a/control/templates.py b/control/templates.py
index bb2e068..d81398a 100644
--- a/control/templates.py
+++ b/control/templates.py
@@ -68,6 +68,7 @@ class Template(Resource):
'cdrom': self.info.get('cdrom', None),
'disks': self.info['disks'],
'networks': self.info['networks'],
+ 'interfaces': self.info.get('interfaces', []),
'folder': self.info.get('folder', []),
'graphics': self.info['graphics'],
'cpu_info': self.info.get('cpu_info')
diff --git a/i18n.py b/i18n.py
index e8d9c05..7cda46d 100644
--- a/i18n.py
+++ b/i18n.py
@@ -159,6 +159,7 @@ messages = {
"KCHVMIF0009E": _("MAC Address %(mac)s already exists in virtual machine %(name)s"),
"KCHVMIF0010E": _("Invalid MAC Address"),
"KCHVMIF0011E": _("Cannot change MAC address of a running virtual machine"),
+ "KCHVMIF0012E": _("Invalid host network interface type (%(type)s). Type should be 'macvtap' for host network interface(Ethernet, Bond, VLAN) to be connected as direct MacVTap and type 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM."),
"KCHTMPL0001E": _("Template %(name)s already exists"),
"KCHTMPL0002E": _("Source media %(path)s not found"),
@@ -190,6 +191,7 @@ 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"),
+ "KCHTMPL0033E": _("Interface expects an object with parameters: 'name', 'type' and 'mode'. Name should be name of host network interface(Ethernet, Bond, VLAN) for type 'macvtap' and name of host openvswitch bridge interface for type ovs. Mode only applicable for interface type macvtap to indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge) and is Optional."),
"KCHPOOL0001E": _("Storage pool %(name)s already exists"),
"KCHPOOL0002E": _("Storage pool %(name)s does not exist"),
diff --git a/vmtemplate.py b/vmtemplate.py
index 7ac0541..fed6d28 100644
--- a/vmtemplate.py
+++ b/vmtemplate.py
@@ -22,6 +22,7 @@ import stat
import time
import urlparse
import uuid
+
from lxml import etree
from lxml.builder import E
@@ -295,6 +296,27 @@ class VMTemplate(object):
self.info['os_version'])
return unicode(networks, 'utf-8')
+ def _get_interfaces_xml(self):
+ interfaces = ""
+ params = {'model': self.info['nic_model']}
+ for interface in self.info.get('interfaces', []):
+ typ = interface['type']
+ if typ == 'macvtap':
+ params['type'] = 'direct'
+ params['mode'] = interface.get('mode', None)
+ elif typ == 'ovs':
+ params['type'] = 'bridge'
+ params['virtualport_type'] = 'openvswitch'
+ else:
+ raise InvalidParameter('KCHVMIF0012E', {'type':
+ params['type']})
+
+ params['name'] = interface['name']
+ interfaces += get_iface_xml(params, self.info['arch'],
+ self.info['os_distro'],
+ self.info['os_version'])
+ return unicode(interfaces, 'utf-8')
+
def _get_input_output_xml(self):
sound = """
<sound model='%(sound_model)s' />
@@ -341,6 +363,7 @@ class VMTemplate(object):
params['name'] = vm_name
params['uuid'] = vm_uuid
params['networks'] = self._get_networks_xml()
+ params['interfaces'] = self._get_interfaces_xml()
params['input_output'] = self._get_input_output_xml()
params['qemu-namespace'] = ''
params['cdroms'] = ''
@@ -432,6 +455,7 @@ class VMTemplate(object):
%(disks)s
%(cdroms)s
%(networks)s
+ %(interfaces)s
%(graphics)s
%(input_output)s
%(serial)s
diff --git a/xmlutils/interface.py b/xmlutils/interface.py
index 677ed81..255d491 100644
--- a/xmlutils/interface.py
+++ b/xmlutils/interface.py
@@ -24,6 +24,16 @@ from wok.plugins.kimchi import osinfo
def get_iface_xml(params, arch=None, os_distro=None, os_version=None):
+ typ = params.get('type', 'network')
+ if typ == 'network':
+ return get_iface_network_xml(params, arch, os_distro, os_version)
+ elif typ == 'bridge':
+ return get_iface_ovs_xml(params, arch, os_distro, os_version)
+ elif typ == 'direct':
+ return get_iface_macvtap_xml(params, arch, os_distro, os_version)
+
+
+def get_iface_network_xml(params, arch=None, os_distro=None, os_version=None):
"""
<interface type='network' name='ethX'>
<start mode='onboot'/>
@@ -62,3 +72,65 @@ def get_iface_xml(params, arch=None, os_distro=None, os_version=None):
interface.append(E.mac(address=mac))
return ET.tostring(interface, encoding='utf-8', pretty_print=True)
+
+
+def get_iface_macvtap_xml(params, arch=None, os_distro=None, os_version=None):
+ """
+ <interface type="direct">
+ <source dev="bondX" mode="bridge"/>
+ <model type="virtio"/>
+ </interface>
+ """
+ device = params['name']
+ interface = E.interface(type=params['type'])
+ mode = params.get('mode', None)
+ if mode is not None:
+ interface.append(E.source(dev=device, mode=mode))
+ else:
+ interface.append(E.source(dev=device))
+
+ model = params.get('model', None)
+ # no model specified; let's try querying osinfo
+ if model is None:
+ # if os_distro and os_version are invalid, nic_model will also be None
+ model = osinfo.lookup(os_distro, os_version).get('nic_model')
+
+ # only append 'model' to the XML if it's been specified as a parameter or
+ # returned by osinfo.lookup; otherwise let libvirt use its default value
+ if model is not None:
+ interface.append(E.model(type=model))
+
+ interface.append(E.model(type=model))
+
+ return ET.tostring(interface, encoding='utf-8', pretty_print=True)
+
+
+def get_iface_ovs_xml(params, arch=None, os_distro=None, os_version=None):
+ """
+ <interface type="bridge">
+ <source bridge="vswitchX"/>
+ <virtualport type="openvswitch"/>
+ <model type="virtio"/>
+ </interface>
+ """
+ device = params['name']
+ interface = E.interface(type=params['type'])
+ interface.append(E.source(bridge=device))
+ virtualport_type = params.get('virtualport_type', 'openvswitch')
+ interface.append(E.virtualport(type=virtualport_type))
+
+ model = params.get('model', None)
+ # no model specified; let's try querying osinfo
+ if model is None:
+ # if os_distro and os_version are invalid, nic_model will also be None
+ model = osinfo.lookup(os_distro, os_version).get('nic_model')
+
+ # only append 'model' to the XML if it's been specified as a parameter or
+ # returned by osinfo.lookup; otherwise let libvirt use its default value
+
+ if model is not None:
+ interface.append(E.model(type=model))
+
+ interface.append(E.model(type=model))
+
+ return ET.tostring(interface, encoding='utf-8', pretty_print=True)
--
2.7.4
8 years, 3 months
[PATCH] Issue #992 : Create template on s390x without libvirt storage
by harshalp@linux.vnet.ibm.com
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
+ 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
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):
+ """
+ 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"])
+
+ 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:
+ 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)
+
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)
+ 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')
+ 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')}
+
+ # 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:
+
+ """
+ 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
+ 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')
+ 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
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'])
+
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)
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
--
1.9.1
8 years, 3 months
[PATCH v2][Kimchi 0/2] Allow vm update graphics type
by Ramon Medeiros
Changes:
v2:
Fix typos
Add tests
Ramon Medeiros (2):
Issue #836: Allow user change guest graphics type
Create test to verify graphics type change
API.json | 6 ++++++
docs/API.md | 1 +
i18n.py | 2 +-
model/vms.py | 10 ++++++++++
tests/test_model.py | 18 +++++++-----------
5 files changed, 25 insertions(+), 12 deletions(-)
--
2.5.5
8 years, 3 months
[PATCH v3] [Kimchi] Issue #585: 'make clean' does not revert its changes from 'make rpm'
by bianca@linux.vnet.ibm.com
From: Bianca Carvalho <bianca(a)linux.vnet.ibm.com>
Edited Makefile.am to check if there is any file to be stashed or
commited before run 'make rpm' to avoid losing any changes.
Also included 'git clean -df & git reset --hard' command to remove
untracked files from the working tree and to revert changes made by
'make rpm' command.
Signed-off-by: Bianca Carvalho <bianca(a)linux.vnet.ibm.com>
---
Makefile.am | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 9bebb65..9917dcc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -135,17 +135,30 @@ kimchi.spec: contrib/kimchi.spec.fedora contrib/kimchi.spec.suse
/bin/false ; \
fi
-rpm: dist kimchi.spec
+check_files:
+ @if [ -d '.git' ]; then \
+ if [ `git status --porcelain --untracked-files=no | wc -l` -gt 0 ]; then \
+ echo "***** Aborting 'make rpm' command *****"; \
+ echo "There are some changes not commited in your working \
+directory. To avoid losing them, please commit or stage before run 'make rpm' command."; \
+ exit 1; \
+ fi \
+ fi
+
+rpm: check_files dist kimchi.spec
$(MKDIR_P) rpm/BUILD rpm/RPMS rpm/SOURCES rpm/SPECS rpm/SRPMS
cp $(top_srcdir)/kimchi.spec rpm/SPECS/kimchi.spec
cp $(DIST_ARCHIVES) rpm/SOURCES
rpmbuild -ba --define "_topdir `pwd`/rpm" rpm/SPECS/kimchi.spec
+ @if [ -d '.git' ]; then \
+ git reset --hard; \
+ fi
-fedora-rpm: contrib/kimchi.spec.fedora
+fedora-rpm: check_files contrib/kimchi.spec.fedora
ln -sf contrib/kimchi.spec.fedora kimchi.spec
$(MAKE) rpm
-suse-rpm: contrib/kimchi.spec.suse
+suse-rpm: check_files contrib/kimchi.spec.suse
ln -sf contrib/kimchi.spec.suse kimchi.spec
$(MAKE) rpm
--
2.7.4
8 years, 3 months
[PATCH] [Kimchi] Issue #982 - Fix broken testcases.
by pvital@linux.vnet.ibm.com
From: Paulo Vital <pvital(a)linux.vnet.ibm.com>
Several testcases started to fail in Fedora 24 after commit 24cc635 added
a solution to create a temporary file to represent the Virt Viewer script
contents in mockmodel.py. The solution is not able to create the directory
in where this temporary file will be created and is failing.
This patch adds a control to make sure the directory exists.
Signed-off-by: Paulo Vital <pvital(a)linux.vnet.ibm.com>
---
mockmodel.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/mockmodel.py b/mockmodel.py
index 2f55af7..cd06ee3 100644
--- a/mockmodel.py
+++ b/mockmodel.py
@@ -141,8 +141,12 @@ class MockModel(Model):
cherrypy.engine.subscribe('exit', self.virtviewertmpfile_cleanup)
def _create_virt_viewer_tmp_file(self):
+ path = '../data/virtviewerfiles/'
+ if not os.path.isdir(path):
+ os.makedirs(path)
+
self.virtviewerfile_tmp = tempfile.NamedTemporaryFile(
- dir='../data/virtviewerfiles/',
+ dir=path,
delete=False
)
file_content = "[virt-viewer]\ntype=vnc\nhost=127.0.0.1\nport=5999\n"
--
2.7.4
8 years, 3 months
[PATCH V2] [Kimchi] Added s390x architecture support in osinfo params.
by archus@linux.vnet.ibm.com
From: Archana Singh <archus(a)linux.vnet.ibm.com>
1) Added s390x in SUPPORTED_ARCHS.
2) Added memory devices slot limits for s390x.
3) Added template_spec for s390x.
4) Added arch check to add old template spec in params
and no need to do modern_version_bases check as for
s390x as template specs are same for all version.
Archana Singh (1):
Added s390x architecture support in osinfo params.
osinfo.py | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
--
2.7.4
8 years, 3 months
[PATCH V1] [Kimchi] Only on s390x add default networks to template if template.conf has default network configuration uncommented.
by archus@linux.vnet.ibm.com
From: Archana Singh <archus(a)linux.vnet.ibm.com>
Below are the changes done for s390x architecture to only add default networks
to template if template.conf has network configuration uncommented
otherwise do not add any network by default.
1) Only on s390x, osinfo._get_tmpl_defaults() does not add
default network in case template.conf has commented out network configuration.
2) Only on s390x, NetworksModel._check_default_networks() does
not throw key error if networks not found in tmpl_defaults.
3) Only on s390x, VMTemplate.validate_integrity() does not throw
key error if networks not found in the template.
4) Only on s390x, LibvirtVMTemplate._network_validate() does not
throw key error on s390x if networks not found in tmpl_default, as on s390x networks is optional.
5) Only on s390x, VMTemplate._get_network_xml() does
return empty string and does not throw key error if networks not found in template object.
6) Only on s390x, control/templates.py gets networks as [] if not found
self.info.
Archana Singh (1):
Only on s390x add default networks to template if template.conf has
default network configuration.
control/templates.py | 2 +-
model/networks.py | 7 ++++++-
model/templates.py | 5 ++++-
osinfo.py | 14 +++++++++++++-
vmtemplate.py | 15 +++++++++++++--
5 files changed, 37 insertions(+), 6 deletions(-)
--
2.7.4
8 years, 3 months
[PATCH V3] [Kimchi] Only on s390x add default networks to template if template.conf has default network configuration uncommented.
by archus@linux.vnet.ibm.com
From: Archana Singh <archus(a)linux.vnet.ibm.com>
Below are the changes done for s390x architecture to only add default networks
to template if template.conf has network configuration uncommented
otherwise do not add any network by default.
1) Only on s390x, osinfo._get_tmpl_defaults() does not add
default network in case template.conf has commented out
network configuration.
2) NetworksModel._check_default_networks() does not throw key error
if networks not found in tmpl_defaults.
3) VMTemplate.validate_integrity() does not throw key error
if networks not found in the template.
4) LibvirtVMTemplate._network_validate() does not throw key error
if networks not found in tmpl_default, as on s390x networks is optional.
5) VMTemplate._get_network_xml() does return empty string and does not
throw key error if networks not found in template object.
6) control/templates.py gets empty networks list if not found in self.info.
Signed-off-by: Archana Singh <archus(a)linux.vnet.ibm.com>
---
control/templates.py | 2 +-
model/networks.py | 3 ++-
model/templates.py | 2 +-
osinfo.py | 14 +++++++++++++-
vmtemplate.py | 11 ++++++++---
5 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/control/templates.py b/control/templates.py
index bb2e068..2dd8601 100644
--- a/control/templates.py
+++ b/control/templates.py
@@ -67,7 +67,7 @@ class Template(Resource):
'memory': self.info['memory'],
'cdrom': self.info.get('cdrom', None),
'disks': self.info['disks'],
- 'networks': self.info['networks'],
+ 'networks': self.info.get('networks', []),
'folder': self.info.get('folder', []),
'graphics': self.info['graphics'],
'cpu_info': self.info.get('cpu_info')
diff --git a/model/networks.py b/model/networks.py
index 35431d4..b9d363a 100644
--- a/model/networks.py
+++ b/model/networks.py
@@ -55,7 +55,8 @@ class NetworksModel(object):
self.caps = CapabilitiesModel(**kargs)
def _check_default_networks(self):
- networks = list(set(tmpl_defaults['networks']))
+ networks = list(set(tmpl_defaults.get('networks', [])))
+
conn = self.conn.get()
for net_name in networks:
diff --git a/model/templates.py b/model/templates.py
index a299c85..8df8c3b 100644
--- a/model/templates.py
+++ b/model/templates.py
@@ -358,7 +358,7 @@ class LibvirtVMTemplate(VMTemplate):
return sorted(map(lambda x: x.decode('utf-8'), names))
def _network_validate(self):
- names = self.info['networks']
+ names = self.info.get('networks', [])
for name in names:
try:
conn = self.conn.get()
diff --git a/osinfo.py b/osinfo.py
index 2c59312..528cf14 100644
--- a/osinfo.py
+++ b/osinfo.py
@@ -138,10 +138,22 @@ def _get_tmpl_defaults():
'pool': '/plugins/kimchi/storagepools/default'}},
'processor': {'vcpus': '1', 'maxvcpus': 1},
'graphics': {'type': 'spice', 'listen': '127.0.0.1'}}
+
+ The default values on s390x architecture:
+
+ {'memory': {'current': 1024, 'maxmemory': 1024},
+ 'storage': { 'disk.0': {'format': 'qcow2', 'size': '10',
+ 'pool': '/plugins/kimchi/storagepools/default'}},
+ 'processor': {'vcpus': '1', 'maxvcpus': 1},
+ 'graphics': {'type': 'spice', 'listen': '127.0.0.1'}}
"""
# Create dict with default values
tmpl_defaults = defaultdict(dict)
- tmpl_defaults['main']['networks'] = ['default']
+
+ host_arch = _get_arch()
+ if host_arch != 's390x':
+ tmpl_defaults['main']['networks'] = ['default']
+
tmpl_defaults['memory'] = {'current': _get_default_template_mem(),
'maxmemory': _get_default_template_mem()}
tmpl_defaults['storage']['disk.0'] = {'size': 10, 'format': 'qcow2',
diff --git a/vmtemplate.py b/vmtemplate.py
index 7ac0541..babf050 100644
--- a/vmtemplate.py
+++ b/vmtemplate.py
@@ -288,7 +288,10 @@ class VMTemplate(object):
networks = ""
params = {'type': 'network',
'model': self.info['nic_model']}
- for nw in self.info['networks']:
+
+ info_networks = self.info.get('networks', [])
+
+ for nw in info_networks:
params['network'] = nw
networks += get_iface_xml(params, self.info['arch'],
self.info['os_distro'],
@@ -353,7 +356,7 @@ class VMTemplate(object):
graphics.update(kwargs.get('graphics', {}))
# Graphics is not supported on s390x, this check will
# not add graphics tag in domain xml.
- if params['arch'] not in ['s390x']:
+ if params.get('arch') != 's390x':
params['graphics'] = get_graphics_xml(graphics)
libvirt_stream_protocols = kwargs.get('libvirt_stream_protocols', [])
@@ -487,7 +490,9 @@ class VMTemplate(object):
def validate_integrity(self):
invalid = {}
# validate networks integrity
- invalid_networks = list(set(self.info['networks']) -
+ networks = self.info.get('networks', [])
+
+ invalid_networks = list(set(networks) -
set(self._get_all_networks_name()))
if invalid_networks:
invalid['networks'] = invalid_networks
--
2.7.4
8 years, 3 months
[PATCHv2] [Kimchi] Issue# 973 Display resource name in confirmation dialog
by Socorro Stoppler
From: Socorro <socorro(a)linux.vnet.ibm.com>
v2:
Display resource name (with name in bold) in confirmation dialog
v1:
When confirmation dialogs are shown, also display the name of the resource being
acted on (i.e. guest name, network, storage, template) as part of the message.
Signed-off-by: Socorro <socorro(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.guest_main.js | 16 +++++++++++-----
ui/js/src/kimchi.network.js | 6 ++++--
ui/js/src/kimchi.storage_main.js | 8 +++++---
ui/js/src/kimchi.template_main.js | 5 +++--
ui/pages/i18n.json.tmpl | 20 ++++++++++----------
5 files changed, 33 insertions(+), 22 deletions(-)
diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js
index 9c1aa54..696cf8f 100644
--- a/ui/js/src/kimchi.guest_main.js
+++ b/ui/js/src/kimchi.guest_main.js
@@ -127,8 +127,10 @@ kimchi.vmpoweroff = function(event) {
var vm_id = vm.attr("id");
var vmObject = vm.data();
var vm_persistent = vmObject.persistent == true;
- var content_msg = vm_persistent ? i18n['KCHVM6003M'] :
- i18n['KCHVM6009M'];
+ var content_msg_1 = i18n['KCHVM6003M'].replace('%1', '<strong>'+vm_id+'</strong>');
+ var content_msg_2 = i18n['KCHVM6009M'].replace('%1', '<strong>'+vm_id+'</strong>');
+ var content_msg = vm_persistent ? content_msg_1 :
+ content_msg_2;
var settings = {
title: i18n['KCHVM6002M'],
content: content_msg,
@@ -153,9 +155,10 @@ kimchi.vmshutdown = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
var vm_id = vm.attr("id");
+ var confirmMessage = i18n['KCHVM6007M'].replace('%1', '<strong>'+vm_id+'</strong>');
var settings = {
title: i18n['KCHVM6006M'],
- content: i18n['KCHVM6007M'],
+ content: confirmMessage,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
@@ -174,9 +177,10 @@ kimchi.vmreset = function(event) {
$(button).addClass('loading');
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
+ var confirmMessage = i18n['KCHVM6005M'].replace('%1', '<strong>'+vm_id+'</strong>');
var settings = {
title: i18n['KCHVM6004M'],
- content: i18n['KCHVM6005M'],
+ content: confirmMessage,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
@@ -204,9 +208,11 @@ kimchi.vmdelete = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
+ var confirmMessage = i18n['KCHVM6001M'].replace('%1', '<strong>'+vm_id+'</strong>');
+
var settings = {
title: i18n['KCHVM6008M'],
- content: i18n['KCHVM6001M'],
+ content: confirmMessage,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index ac6bf74..7ce5b28 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -161,9 +161,10 @@ kimchi.addNetworkActions = function(network) {
return false;
}
if (!network.persistent) {
+ var confirmMessage = i18n['KCHNET6004M'].replace('%1', '<strong>'+network.name+'</strong>');
var settings = {
title : i18n['KCHAPI6001M'],
- content : i18n['KCHNET6004M'],
+ content : confirmMessage,
confirm : i18n['KCHAPI6002M'],
cancel : i18n['KCHAPI6003M']
};
@@ -180,9 +181,10 @@ kimchi.addNetworkActions = function(network) {
if (network.state === "up" || network.in_use) {
return false;
}
+ var confirmMessage = i18n['KCHNET6002M'].replace('%1', '<strong>'+network.name+'</strong>');
wok.confirm({
title : i18n['KCHAPI6006M'],
- content : i18n['KCHNET6002M'],
+ content : confirmMessage,
confirm : i18n['KCHAPI6002M'],
cancel : i18n['KCHAPI6003M']
}, function() {
diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js
index 6c99f93..18e6eea 100644
--- a/ui/js/src/kimchi.storage_main.js
+++ b/ui/js/src/kimchi.storage_main.js
@@ -310,14 +310,15 @@ kimchi.storageBindClick = function() {
$('.pool-delete').on('click', function(event) {
event.preventDefault();
var $pool = $(this);
+ var poolName = $pool.data('name');
+ var confirmMessage = i18n['KCHPOOL6001M'].replace('%1', '<strong>'+poolName+'</strong>');
var settings = {
title : i18n['KCHAPI6001M'],
- content : i18n['KCHPOOL6001M'],
+ content : confirmMessage,
confirm : i18n['KCHAPI6002M'],
cancel : i18n['KCHAPI6003M']
};
wok.confirm(settings, function() {
- var poolName = $pool.data('name');
kimchi.deleteStoragePool(poolName, function() {
kimchi.doListStoragePools();
}, function(err) {
@@ -339,9 +340,10 @@ kimchi.storageBindClick = function() {
$('.pool-deactivate').on('click', function(event) {
event.preventDefault();
var poolName = $(this).data('name');
+ var confirmMessage = i18n['KCHPOOL6012M'].replace('%1', '<strong>'+poolName+'</strong>');
var settings = {
title : i18n['KCHAPI6001M'],
- content : i18n['KCHPOOL6012M'],
+ content : confirmMessage,
confirm : i18n['KCHAPI6002M'],
cancel : i18n['KCHAPI6003M']
};
diff --git a/ui/js/src/kimchi.template_main.js b/ui/js/src/kimchi.template_main.js
index 302d906..cf98a7b 100644
--- a/ui/js/src/kimchi.template_main.js
+++ b/ui/js/src/kimchi.template_main.js
@@ -124,14 +124,15 @@ kimchi.templateBindClick = function() {
$('.template-delete a').on('click', function(event) {
event.preventDefault();
var $template = $(this);
+ var templateName = $template.data('template');
+ var confirmMessage = i18n['KCHTMPL6003M'].replace('%1', '<strong>'+templateName+'</strong>');
var settings = {
title: i18n['KCHAPI6001M'],
- content: i18n['KCHTMPL6003M'],
+ content: confirmMessage,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
wok.confirm(settings, function() {
- var templateName = $template.data('template');
kimchi.deleteTemplate(templateName, function() {
kimchi.doListTemplates();
}, function(err) {
diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl
index a5185b1..d29a206 100644
--- a/ui/pages/i18n.json.tmpl
+++ b/ui/pages/i18n.json.tmpl
@@ -47,24 +47,24 @@
"KCHTMPL6001W": "$_("No ISO found")",
"KCHTMPL6002M": "$_("This may take a long time. Do you want to continue?")",
- "KCHTMPL6003M": "$_("This will permanently delete the template. Would you like to continue?")",
+ "KCHTMPL6003M": "$_("This will permanently delete the %1 template. Would you like to continue?")",
"KCHTMPL6004M": "$_("View Table")",
"KCHTMPL6005M": "$_("View Gallery")",
"KCHTMPL6006M": "$_("Not Available")",
"KCHTMPL6007M": "$_("Please check the invalid Storage Pools")",
- "KCHVM6001M": "$_("This will delete the virtual machine and its virtual disks. This operation cannot be undone. Would you like to continue?")",
+ "KCHVM6001M": "$_("This will delete the %1 virtual machine and its virtual disks. This operation cannot be undone. Would you like to continue?")",
"KCHVM6002M": "$_("Power off Confirmation")",
"KCHVM6003M": "$_("This action may produce undesirable results, "
- "for example unflushed disk cache in the guest. "
+ "for example unflushed disk cache in the %1 guest. "
"Would you like to continue?")",
"KCHVM6004M": "$_("Reset Confirmation")",
"KCHVM6005M": "$_("There is a risk of data loss caused by reset without"
- " the guest OS shutdown. Would you like to continue?")",
+ " the %1 guest OS shutdown. Would you like to continue?")",
"KCHVM6006M": "$_("Shut Down Confirmation")",
- "KCHVM6007M": "$_("Note the guest OS may ignore this request. Would you like to continue?")",
+ "KCHVM6007M": "$_("Note the %1 guest OS may ignore this request. Would you like to continue?")",
"KCHVM6008M": "$_("Virtual Machine delete Confirmation")",
- "KCHVM6009M": "$_("This virtual machine is not persistent. Power Off will delete it. Continue?")",
+ "KCHVM6009M": "$_("The %1 virtual machine is not persistent. Power Off will delete it. Continue?")",
"KCHVM0001E": "$_("Input is not a number")",
"KCHVM0002E": "$_("Memory value cannot be higher than Max Memory value")",
@@ -89,11 +89,11 @@
"KCHVMED6012M": "$_("Following devices will be affected, confirm?")",
"KCHNET6001M": "$_("unavailable")",
- "KCHNET6002M": "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")",
- "KCHNET6004M": "$_("This network is not persistent. Instead of stop, this action will permanently delete it. Would you like to continue?")",
+ "KCHNET6002M": "$_("This action will interrupt network connectivity for any virtual machine that depend on the %1 network.")",
+ "KCHNET6004M": "$_("The %1 network is not persistent. Instead of stop, this action will permanently delete it. Would you like to continue?")",
"KCHNET6001W": "$_("The bridged VLAN tag may not work well with NetworkManager enabled. You should consider disabling it.")",
- "KCHPOOL6001M": "$_("This will permanently delete the storage pool. Would you like to continue?")",
+ "KCHPOOL6001M": "$_("This will permanently delete the %1 storage pool. Would you like to continue?")",
"KCHPOOL6002M": "$_("This storage pool is empty.")",
"KCHPOOL6003M": "$_("It will format your disk and you will loose any data in there, are you sure to continue? ")",
"KCHPOOL6004M": "$_("SCSI Fibre Channel")",
@@ -108,7 +108,7 @@
"KCHPOOL6006E": "$_("No logical device selected.")",
"KCHPOOL6009E": "$_("This is not a valid Server Name or IP. Please, modify it.")",
"KCHPOOL6011M": "$_("No available partitions found.")",
- "KCHPOOL6012M": "$_("This storage pool is not persistent. Instead of deactivate, this action will permanently delete it. Would you like to continue?")",
+ "KCHPOOL6012M": "$_("The %1 storage pool is not persistent. Instead of deactivate, this action will permanently delete it. Would you like to continue?")",
"KCHPOOL6013M": "$_("Unable to retrieve partitions information.")",
"KCHPOOL6014M": "$_("In progress...")",
"KCHPOOL6015M": "$_("Failed!")",
--
2.7.4
8 years, 3 months