[PATCH] Template: Assign 'raw' to disk format if pool is 'logical' or [i]scsi
by Rodrigo Trujillo
Kimchi always creates raw disk format to new vm disks if the storagepool
is logical, iscsi or scsi. But, new templates where not using this
logic and was possible, through API calls, to create a template with a
SCSI storagepool and disk format vmdk, for instance.
This patch fixes this issue.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo(a)linux.vnet.ibm.com>
---
src/kimchi/model/templates.py | 4 ++--
src/kimchi/vmtemplate.py | 5 +++++
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/model/templates.py b/src/kimchi/model/templates.py
index 6bc8aca..8a1820d 100644
--- a/src/kimchi/model/templates.py
+++ b/src/kimchi/model/templates.py
@@ -94,7 +94,7 @@ class TemplatesModel(object):
# Creates the template class with necessary information
# Checkings will be done while creating this class, so any exception
# will be raised here
- t = LibvirtVMTemplate(params, scan=True)
+ t = LibvirtVMTemplate(params, scan=True, conn=self.conn)
name = params['name']
try:
with self.objstore as session:
@@ -231,8 +231,8 @@ class TemplateModel(object):
class LibvirtVMTemplate(VMTemplate):
def __init__(self, args, scan=False, conn=None):
- VMTemplate.__init__(self, args, scan)
self.conn = conn
+ VMTemplate.__init__(self, args, scan)
def _storage_validate(self):
pool_uri = self.info['storagepool']
diff --git a/src/kimchi/vmtemplate.py b/src/kimchi/vmtemplate.py
index 62772e5..a309357 100644
--- a/src/kimchi/vmtemplate.py
+++ b/src/kimchi/vmtemplate.py
@@ -75,6 +75,11 @@ class VMTemplate(object):
args['graphics'] = graphics
self.info.update(args)
+ # Assign right disk format to logical and [i]scsi storagepools
+ if self._get_storage_type() in ['logical', 'iscsi', 'scsi']:
+ for i,disk in enumerate(self.info['disks']):
+ self.info['disks'][i]['format'] = 'raw'
+
def _get_os_info(self, args, scan):
distro = version = 'unknown'
--
2.1.0
9 years, 8 months
[PATCH] UI-Template Edit: Enable user to change disk format
by Rodrigo Trujillo
This patch adds a new field (Disk Format) in Storage tab in Template
edit window. Users will then be allowed to select any disk format
supported by Libvirt and Kimchi backend.
The default disk format is qcow2 (first option), so, for compatibility,
if the template register in objecstore does not contain the disk format
information, the new field is going to set 'qcow2' automatically.
For iscsi storagepools, the new field is going to be disabled and the
format is going to be set automatically as 'raw', just like the backend
behaves currently, avoiding errors.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo(a)linux.vnet.ibm.com>
---
ui/css/theme-default/template-edit.css | 8 +++++--
ui/js/src/kimchi.template_edit_main.js | 40 +++++++++++++++++++++++++++++-----
ui/pages/template-edit.html.tmpl | 16 ++++++++++++++
3 files changed, 56 insertions(+), 8 deletions(-)
diff --git a/ui/css/theme-default/template-edit.css b/ui/css/theme-default/template-edit.css
index 7abee7c..ed9f02c 100644
--- a/ui/css/theme-default/template-edit.css
+++ b/ui/css/theme-default/template-edit.css
@@ -95,7 +95,7 @@
#edit-template-tabs .template-storage-cell{
display: inline-block;
- width: 230px;
+ width: 180px;
}
#edit-template-tabs .template-storage-cell label {
@@ -114,7 +114,11 @@
}
#form-template-storage .template-tab-body .template-storage-name {
- width: 220px;
+ width: 170px;
+}
+
+#form-template-storage .template-tab-body .template-storage-disk-format {
+ width: 160px;
}
#edit-template-tabs .template-tab-body input[readonly] {
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index 85f76cd..48ae26b 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -67,7 +67,7 @@ kimchi.template_edit_main = function() {
$('.template-tab-body', '#form-template-storage').append(nodeStorage);
var storageOptions = '';
var scsiOptions = '';
- $('select', '#form-template-storage').find('option').remove();
+ $('select:first', '#form-template-storage').find('option').remove();
$.each(result, function(index, storageEntities) {
if((storageEntities.state === 'active') && (storageEntities.type != 'kimchi-iso')) {
if(storageEntities.type === 'iscsi' || storageEntities.type === 'scsi') {
@@ -77,7 +77,7 @@ kimchi.template_edit_main = function() {
var isSlected = tmpPath === thisName ? ' selected' : '';
scsiOptions += '<option' + isSlected + '>' + tmpPath + '</option>';
});
- $('select', '#form-template-storage').append(scsiOptions);
+ $('select:first', '#form-template-storage').append(scsiOptions);
}, function() {});
} else {
var isSlected = storageEntities.name === thisName ? ' selected' : '';
@@ -85,8 +85,20 @@ kimchi.template_edit_main = function() {
}
}
});
- $('select', '#form-template-storage').append(storageOptions);
- $('select', '#form-template-storage').change(function() {
+ $('select:first', '#form-template-storage').append(storageOptions);
+
+ // Set disk format
+ $('select:last option', '#form-template-storage').each(function() {
+ if ($(this).text() == storageData.storageDiskFormat) {
+ $(this).prop('selected', true);
+ }
+ });
+
+ $('select:last', '#form-template-storage').change(function() {
+ $('.template-storage-disk-format').val($(this).val());
+ });
+
+ $('select:first', '#form-template-storage').change(function() {
var selectedItem = $(this).parent().parent();
var tempStorageNameFull = $(this).val();
var tempName = tempStorageNameFull.split('/');
@@ -99,9 +111,19 @@ kimchi.template_edit_main = function() {
kimchi.getStoragePoolVolume(tempStorageName, tempName[tempName.length-1], function(info) {
volSize = info.capacity / Math.pow(1024, 3);
$('.template-storage-disk', selectedItem).attr('readonly', true).val(volSize);
+ $('select:last option', selectedItem).each(function() {
+ this.selected = (this.text == 'raw');
+ });
+ $('select:last', selectedItem).prop('disabled', true).change();
});
} else {
$('.template-storage-disk', selectedItem).attr('readonly', false);
+ if ($('select:last', selectedItem).prop('disabled') == true) {
+ $('select:last option', selectedItem).each(function() {
+ this.selected = (this.text == 'qcow2');
+ });
+ $('select:last', selectedItem).prop('disabled', false).change();
+ }
}
});
});
@@ -120,7 +142,8 @@ kimchi.template_edit_main = function() {
editMode : 'hide',
storageName : defaultPool,
storageType : defaultType,
- storageDisk : diskEntities.size
+ storageDisk : diskEntities.size,
+ storageDiskFormat : diskEntities.format ? diskEntities.format : 'qcow2'
}
if (diskEntities.volume) {
@@ -131,6 +154,10 @@ kimchi.template_edit_main = function() {
nodeData.storageDisk = volSize;
addStorageItem(nodeData);
$('.template-storage-disk').attr('readonly', true);
+ $('select:last option', '#form-template-storage').each(function() {
+ this.selected = (this.text == 'raw');
+ });
+ $('select:last', '#form-template-storage').prop('disabled', true).change();
});
} else {
addStorageItem(storageNodeData);
@@ -271,7 +298,8 @@ kimchi.template_edit_main = function() {
origDisks[0]['volume'] && delete origDisks[0]['volume'];
origDisks[0].size = Number($('.template-storage-disk', tmpItem).val());
}
- data[field] = origDisks;
+ origDisks[0].format = $('.template-storage-disk-format', tmpItem).val();
+ data[field] = origDisks;
}
else if (field == 'graphics') {
var type = $('#form-template-general [name="' + field + '"]').val();
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index c7832c9..e64a30f 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -104,6 +104,7 @@
<span class="template-storage-cell">$_("Storage Pool")</span>
<span class="template-storage-cell">$_("Type")</span>
<span class="template-storage-cell">$_("Disk(GB)")</span>
+ <span class="template-storage-cell">$_("Disk Format")</span>
<button type="button" id="template-edit-storage-add-button" class="action-area"></button>
</div>
<div class="template-tab-body">
@@ -160,6 +161,21 @@
<span class="template-storage-cell">
<input class="template-storage-disk" value={storageDisk} type="text" />
</span>
+ <span class="template-storage-cell">
+ <input class="template-storage-disk-format" value={storageDiskFormat} type="text" style="display:none" />
+ <select>
+ <option>qcow2</option>
+ <option>raw</option>
+ <option>bochs</option>
+ <option>cloop</option>
+ <option>cow</option>
+ <option>dmg</option>
+ <option>qcow</option>
+ <option>qed</option>
+ <option>vmdk</option>
+ <option>vpc</option>
+ </select>
+ </span>
</div>
</script>
<script id="template-interface-tmpl" type="text/html">
--
2.1.0
9 years, 8 months
[PATCH] Set qcow2 as default disk format in new templates
by Rodrigo Trujillo
Users are allowed to provide disk format when creating a new Template.
However this is optional. This option sets qcow2 as default disk format
for every new Template created.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo(a)linux.vnet.ibm.com>
---
src/kimchi/osinfo.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/kimchi/osinfo.py b/src/kimchi/osinfo.py
index 3c31346..ede2541 100644
--- a/src/kimchi/osinfo.py
+++ b/src/kimchi/osinfo.py
@@ -33,7 +33,8 @@ SUPPORTED_ARCHS = {'x86': ('i386', 'i686', 'x86_64'),
'ppc64le': ('ppc64le')}
-common_spec = {'cpus': 1, 'memory': 1024, 'disks': [{'index': 0, 'size': 10}],
+common_spec = {'cpus': 1, 'memory': 1024, 'disks': [{'index': 0, 'size': 10,
+ 'format': 'qcow2'}],
'cdrom_bus': 'ide', 'cdrom_index': 2, 'mouse_bus': 'ps2'}
--
2.1.0
9 years, 8 months
[PATCH 0/2] Objectstore and server tests
by Aline Manera
On way to complete the tests refactoring, I am sending 2 patches: one related to
objectstore tests and other one about server tests.
Aline Manera (2):
Object store tests
Server tests
tests/test_mockmodel.py | 35 ------
tests/test_model.py | 71 ------------
tests/test_objectstore.py | 96 ++++++++++++++++
tests/test_rest.py | 176 -----------------------------
tests/test_server.py | 274 +++++++++++++++++++++++++++++++++++++++++++---
5 files changed, 356 insertions(+), 296 deletions(-)
create mode 100644 tests/test_objectstore.py
--
2.1.0
9 years, 8 months
[PATCH] Fix disk format lock during VM creation
by Rodrigo Trujillo
Users are able to pass the disk format (qcow, raw, etc) in disk Template
information. However, Kimchi is ignoring this information and always
creating qcow2 disk images (if the storagepool is not 'LOGICAL') when it
creates a VM based on a given Template.
This patch fixes this problem, using the disk format from the template,
if it does not exist, uses qcow2 as default.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo(a)linux.vnet.ibm.com>
---
src/kimchi/vmtemplate.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/kimchi/vmtemplate.py b/src/kimchi/vmtemplate.py
index ec477dd..de750d4 100644
--- a/src/kimchi/vmtemplate.py
+++ b/src/kimchi/vmtemplate.py
@@ -193,7 +193,6 @@ class VMTemplate(object):
def to_volume_list(self, vm_uuid):
storage_path = self._get_storage_path()
- fmt = 'raw' if self._get_storage_type() in ['logical'] else 'qcow2'
ret = []
for i, d in enumerate(self.info['disks']):
index = d.get('index', i)
@@ -201,11 +200,16 @@ class VMTemplate(object):
info = {'name': volume,
'capacity': d['size'],
- 'format': fmt,
+ 'format': d.get('format', 'qcow2'),
'path': '%s/%s' % (storage_path, volume)}
+ # Validate disk format
+ if self._get_storage_type() in ['logical'] and \
+ info['format'] != 'raw':
+ info['format'] = 'raw'
+
if 'logical' == self._get_storage_type() or \
- fmt not in ['qcow2', 'raw']:
+ info['format'] not in ['qcow2', 'raw']:
info['allocation'] = info['capacity']
else:
info['allocation'] = 0
--
2.1.0
9 years, 8 months
[PATCH] issue #548: Hotplug network interfaces
by Crístian Deives
Currently, network interfaces can only be added to shutoff VMs. However,
the use might want to attach an interface to a running VM as well.
Allow network interfaces to be attached also while the VM is running.
The related test cases have been updated to perform the same operations
on both a shutoff and a running VM.
Fix issue #548 (Kimchi does not support NIC hot plug) - backend only.
Signed-off-by: Crístian Deives <cristiandeives(a)gmail.com>
---
src/kimchi/i18n.py | 1 -
src/kimchi/model/vmifaces.py | 45 ++++++++++++++---------
tests/test_model.py | 86 ++++++++++++++++++++++----------------------
3 files changed, 73 insertions(+), 59 deletions(-)
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 46990a5..d4c1cc6 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -118,7 +118,6 @@ messages = {
"KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"),
"KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"),
- "KCHVMIF0003E": _("Do not support guest interface hot plug attachment"),
"KCHVMIF0004E": _("Supported virtual machine interfaces type is only network"),
"KCHVMIF0005E": _("Network name for virtual machine interface must be a string"),
"KCHVMIF0006E": _("Invalid network model card specified for virtual machine interface"),
diff --git a/src/kimchi/model/vmifaces.py b/src/kimchi/model/vmifaces.py
index 0c10fa9..a64315d 100644
--- a/src/kimchi/model/vmifaces.py
+++ b/src/kimchi/model/vmifaces.py
@@ -22,7 +22,7 @@ import random
import libvirt
from lxml import etree, objectify
-from kimchi.exception import InvalidOperation, InvalidParameter, NotFoundError
+from kimchi.exception import InvalidParameter, NotFoundError
from kimchi.model.config import CapabilitiesModel
from kimchi.model.vms import DOM_STATE_MAP, VMModel
from kimchi.xmlutils.interface import get_iface_xml
@@ -48,10 +48,6 @@ class VMIfacesModel(object):
raise InvalidParameter("KCHVMIF0002E",
{'name': vm, 'network': params["network"]})
- dom = VMModel.get_vm(vm, self.conn)
- if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
- raise InvalidOperation("KCHVMIF0003E")
-
macs = (iface.mac.get('address')
for iface in self.get_vmifaces(vm, self.conn))
@@ -60,10 +56,19 @@ class VMIfacesModel(object):
if params['mac'] not in macs:
break
+ dom = VMModel.get_vm(vm, self.conn)
+
os_data = VMModel.vm_get_os_metadata(dom, self.caps.metadata_support)
os_distro, os_version = os_data
xml = get_iface_xml(params, conn.getInfo()[0], os_distro, os_version)
- dom.attachDeviceFlags(xml, libvirt.VIR_DOMAIN_AFFECT_CURRENT)
+
+ flags = 0
+ if dom.isPersistent():
+ flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
+ if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
+ flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
+
+ dom.attachDeviceFlags(xml, flags)
return params['mac']
@@ -118,14 +123,16 @@ class VMIfaceModel(object):
dom = VMModel.get_vm(vm, self.conn)
iface = self._get_vmiface(vm, mac)
- if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
- raise InvalidOperation("KCHVMIF0003E")
-
if iface is None:
raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac})
- dom.detachDeviceFlags(etree.tostring(iface),
- libvirt.VIR_DOMAIN_AFFECT_CURRENT)
+ flags = 0
+ if dom.isPersistent():
+ flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
+ if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
+ flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
+
+ dom.detachDeviceFlags(etree.tostring(iface), flags)
def update(self, vm, mac, params):
dom = VMModel.get_vm(vm, self.conn)
@@ -134,16 +141,22 @@ class VMIfaceModel(object):
if iface is None:
raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac})
- # FIXME we will support to change the live VM configuration later.
+ flags = 0
+ if dom.isPersistent():
+ flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
+ if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
+ flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
+
if iface.attrib['type'] == 'network' and 'network' in params:
iface.source.attrib['network'] = params['network']
xml = etree.tostring(iface)
- dom.updateDeviceFlags(xml, flags=libvirt.VIR_DOMAIN_AFFECT_CONFIG)
- # change on the persisted VM configuration only.
- if 'model' in params and dom.isPersistent():
+ dom.updateDeviceFlags(xml, flags=flags)
+
+ if 'model' in params:
iface.model.attrib["type"] = params['model']
xml = etree.tostring(iface)
- dom.updateDeviceFlags(xml, flags=libvirt.VIR_DOMAIN_AFFECT_CONFIG)
+
+ dom.updateDeviceFlags(xml, flags=flags)
return mac
diff --git a/tests/test_model.py b/tests/test_model.py
index 63bd721..39e4fe6 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -297,9 +297,6 @@ class ModelTests(unittest.TestCase):
params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
- params = {'name': 'kimchi-ifaces', 'template': '/templates/test'}
- inst.vms_create(params)
- rollback.prependDefer(inst.vm_delete, 'kimchi-ifaces')
# Create a network
net_name = 'test-network'
@@ -311,45 +308,50 @@ class ModelTests(unittest.TestCase):
inst.network_activate(net_name)
rollback.prependDefer(inst.network_deactivate, net_name)
- ifaces = inst.vmifaces_get_list('kimchi-ifaces')
- self.assertEquals(1, len(ifaces))
-
- iface = inst.vmiface_lookup('kimchi-ifaces', ifaces[0])
- self.assertEquals(17, len(iface['mac']))
- self.assertEquals("default", iface['network'])
- self.assertIn("model", iface)
-
- # attach network interface to vm
- iface_args = {"type": "network",
- "network": "test-network",
- "model": "virtio"}
- mac = inst.vmifaces_create('kimchi-ifaces', iface_args)
- # detach network interface from vm
- rollback.prependDefer(inst.vmiface_delete, 'kimchi-ifaces', mac)
- self.assertEquals(17, len(mac))
-
- iface = inst.vmiface_lookup('kimchi-ifaces', mac)
- self.assertEquals("network", iface["type"])
- self.assertEquals("test-network", iface['network'])
- self.assertEquals("virtio", iface["model"])
-
- # attach network interface to vm without providing model
- iface_args = {"type": "network",
- "network": "test-network"}
- mac = inst.vmifaces_create('kimchi-ifaces', iface_args)
- rollback.prependDefer(inst.vmiface_delete, 'kimchi-ifaces', mac)
-
- iface = inst.vmiface_lookup('kimchi-ifaces', mac)
- self.assertEquals("network", iface["type"])
- self.assertEquals("test-network", iface['network'])
-
- # update vm interface
- iface_args = {"network": "default",
- "model": "e1000"}
- inst.vmiface_update('kimchi-ifaces', mac, iface_args)
- iface = inst.vmiface_lookup('kimchi-ifaces', mac)
- self.assertEquals("default", iface['network'])
- self.assertEquals("e1000", iface["model"])
+ for vm_name in ['kimchi-ifaces', 'kimchi-ifaces-running']:
+ params = {'name': vm_name, 'template': '/templates/test'}
+ inst.vms_create(params)
+ rollback.prependDefer(inst.vm_delete, vm_name)
+
+ ifaces = inst.vmifaces_get_list(vm_name)
+ self.assertEquals(1, len(ifaces))
+
+ iface = inst.vmiface_lookup(vm_name, ifaces[0])
+ self.assertEquals(17, len(iface['mac']))
+ self.assertEquals("default", iface['network'])
+ self.assertIn("model", iface)
+
+ # attach network interface to vm
+ iface_args = {"type": "network",
+ "network": "test-network",
+ "model": "virtio"}
+ mac = inst.vmifaces_create(vm_name, iface_args)
+ # detach network interface from vm
+ rollback.prependDefer(inst.vmiface_delete, vm_name, mac)
+ self.assertEquals(17, len(mac))
+
+ iface = inst.vmiface_lookup(vm_name, mac)
+ self.assertEquals("network", iface["type"])
+ self.assertEquals("test-network", iface['network'])
+ self.assertEquals("virtio", iface["model"])
+
+ # attach network interface to vm without providing model
+ iface_args = {"type": "network",
+ "network": "test-network"}
+ mac = inst.vmifaces_create(vm_name, iface_args)
+ rollback.prependDefer(inst.vmiface_delete, vm_name, mac)
+
+ iface = inst.vmiface_lookup(vm_name, mac)
+ self.assertEquals("network", iface["type"])
+ self.assertEquals("test-network", iface['network'])
+
+ # update vm interface
+ iface_args = {"network": "default",
+ "model": "e1000"}
+ inst.vmiface_update(vm_name, mac, iface_args)
+ iface = inst.vmiface_lookup(vm_name, mac)
+ self.assertEquals("default", iface['network'])
+ self.assertEquals("e1000", iface["model"])
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_vm_disk(self):
--
2.1.0
9 years, 8 months
[PATCH v2 0/3] VM suspend/resume
by Crístian Deives
This is the difference between this and the previous patchset:
- Use string (instead of Unicode) when comparing VM states.
Crístian Viana (3):
Optimize VM update function
Update some VM state conditions
Add support for VM suspend and resume
src/kimchi/control/vms.py | 2 ++
src/kimchi/i18n.py | 4 ++++
src/kimchi/model/vms.py | 47 ++++++++++++++++++++++++++++++++++++++++++++---
tests/test_model.py | 20 ++++++++++++++++++++
tests/test_rest.py | 28 ++++++++++++++++++++++++++++
5 files changed, 98 insertions(+), 3 deletions(-)
--
2.1.0
9 years, 8 months
[PATCH 0/2] fix: Update VM stats in "lookup"
by Crístian Deives
Crístian Deives (2):
Update stats when looking up one single VM
Move stats-related VM functions to VMModel
src/kimchi/model/vms.py | 205 +++++++++++++++++++++++-------------------------
1 file changed, 99 insertions(+), 106 deletions(-)
--
2.1.0
9 years, 8 months