[PATCH v3][Kimchi 0/6] Make Kimchi able to change guest's boot order

Changes: v3: Update test on test_model to keep working v2: Do not manipulate xml on model Improve parameters checking at API.json Increase test cases Ramon Medeiros (6): Add function get_bootorder_node Create method to change bootorder of a guest Update documentation about bootorder on vm update Update REST API Add function to retrieve bootorder on vm lookup Add test to check bootorder API.json | 23 +++++++++++++++++++++++ docs/API.md | 1 + i18n.py | 1 + model/vms.py | 32 ++++++++++++++++++++++++++++++-- tests/test_model.py | 15 ++++++++++++++- xmlutils/bootorder.py | 19 +++++++++++++------ 6 files changed, 82 insertions(+), 9 deletions(-) -- 2.5.5

This function retrieves ElementTree nodes instead of xml Signed-off-by: Ramon Medeiros <ramonn@linux.vnet.ibm.com> --- xmlutils/bootorder.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/xmlutils/bootorder.py b/xmlutils/bootorder.py index 9e444bd..6d92bd6 100644 --- a/xmlutils/bootorder.py +++ b/xmlutils/bootorder.py @@ -21,6 +21,17 @@ import lxml.etree as ET from lxml.builder import E +def get_bootorder_node(boot_order=None): + if boot_order is None: + boot_order = ['hd', 'cdrom', 'network'] + + boot_nodes = [] + for device in boot_order: + boot_nodes.append(E.boot(dev=device)) + + return boot_nodes + + def get_bootorder_xml(boot_order=None): """ Returns the XML for boot order. The default return includes the following: @@ -31,12 +42,8 @@ def get_bootorder_xml(boot_order=None): To a different boot order, specify the order by a list as argument. """ - if boot_order is None: - boot_order = ['hd', 'cdrom', 'network'] - boot_xml = '' - for device in boot_order: - boot = E.boot(dev=device) - boot_xml += ET.tostring(boot, encoding='utf-8', pretty_print=True) + for device in get_bootorder_node(boot_order): + boot_xml += ET.tostring(device, encoding='utf-8', pretty_print=True) return boot_xml -- 2.5.5

Signed-off-by: Ramon Medeiros <ramonn@linux.vnet.ibm.com> --- model/vms.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/model/vms.py b/model/vms.py index 6a309fc..1ed4bd4 100644 --- a/model/vms.py +++ b/model/vms.py @@ -62,6 +62,7 @@ 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 template_name_from_uri +from wok.plugins.kimchi.xmlutils.bootorder import get_bootorder_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 @@ -81,7 +82,7 @@ VM_ONLINE_UPDATE_PARAMS = ['graphics', 'groups', 'memory', 'users'] # update parameters which are updatable when the VM is offline VM_OFFLINE_UPDATE_PARAMS = ['cpu_info', 'graphics', 'groups', 'memory', - 'name', 'users'] + 'name', 'users', 'bootorder'] XPATH_DOMAIN_DISK = "/domain/devices/disk[@device='disk']/source/@file" XPATH_DOMAIN_DISK_BY_FILE = "./devices/disk[@device='disk']/source[@file='%s']" @@ -745,6 +746,24 @@ class VMModel(object): else: remove_metadata_node(dom, 'name') + def _update_bootorder(self, xml, params): + # get element tree from xml + et = ET.fromstring(xml) + + # get machine type + os = et.find("os") + + # remove old order + for device in os.findall("boot"): + os.remove(device) + + # add new + for device in get_bootorder_node(params): + os.append(device) + + # update <os> + return ET.tostring(et) + def _static_vm_update(self, vm_name, dom, params): old_xml = new_xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) params = copy.deepcopy(params) @@ -791,6 +810,10 @@ class VMModel(object): if ('memory' in params and params['memory'] != {}): new_xml = self._update_memory_config(new_xml, params, dom) + # update bootorder + if "bootorder" in params: + new_xml = self._update_bootorder(new_xml, params["bootorder"]) + snapshots_info = [] conn = self.conn.get() try: -- 2.5.5

Signed-off-by: Ramon Medeiros <ramonn@linux.vnet.ibm.com> --- docs/API.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/API.md b/docs/API.md index 84ef7c9..4a40e70 100644 --- a/docs/API.md +++ b/docs/API.md @@ -174,6 +174,7 @@ server. * sockets - The maximum number of sockets to use. * cores - The number of cores per socket. * threads - The number of threads per core. + * bootorder: guest bootorder, types accepted: hd, cdrom, network or fd * **POST**: *See Virtual Machine Actions* -- 2.5.5

Signed-off-by: Ramon Medeiros <ramonn@linux.vnet.ibm.com> --- API.json | 23 +++++++++++++++++++++++ i18n.py | 1 + 2 files changed, 24 insertions(+) diff --git a/API.json b/API.json index 8d4f725..1772abb 100644 --- a/API.json +++ b/API.json @@ -294,6 +294,29 @@ "minLength": 1, "error": "KCHVM0011E" }, + "bootorder": { + "description": "Boot order", + "type": "array", + "error": "KCHVM0052E", + "items": [ + {"type": "string", + "enum": ["hd", "cdrom", "network", "fd"] + }, + {"type": "string", + "enum": ["hd", "cdrom", "network", "fd"] + }, + {"type": "string", + "enum": ["hd", "cdrom", "network", "fd"] + }, + {"type": "string", + "enum": ["hd", "cdrom", "network", "fd"] + } + ], + "minItems": 1, + "maxItems": 4, + "additionalItems": false, + "uniqueItems": true + }, "users": { "description": "Array of users who have permission to the VM", "type": "array", diff --git a/i18n.py b/i18n.py index 08a3ac8..e8fdf88 100644 --- a/i18n.py +++ b/i18n.py @@ -104,6 +104,7 @@ messages = { "KCHVM0049E": _("Cannot power off %(name)s. Virtual machine is shut off."), "KCHVM0050E": _("Cannot shutdown %(name)s. Virtual machine is shut off."), "KCHVM0051E": _("Cannot reset %(name)s. Virtual machine is already shut off."), + "KCHVM0052E": _("Boot order must be a list. Devices accepted: hd, cdrom, fd or network."), "KCHVM0055E": _("Migrate to localhost %(host)s is not allowed."), "KCHVM0056E": _("To migrate a virtual machine to the remote host %(host)s the user %(user)s must have password-less login to the remote host."), -- 2.5.5

Signed-off-by: Ramon Medeiros <ramonn@linux.vnet.ibm.com> --- model/vms.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/model/vms.py b/model/vms.py index 1ed4bd4..17159fe 100644 --- a/model/vms.py +++ b/model/vms.py @@ -94,6 +94,7 @@ XPATH_DOMAIN_MEMORY_UNIT = '/domain/memory/@unit' XPATH_DOMAIN_UUID = '/domain/uuid' XPATH_DOMAIN_DEV_CPU_ID = '/domain/devices/spapr-cpu-socket/@id' +XPATH_BOOT = 'os/boot/@dev' XPATH_CPU = './cpu' XPATH_NAME = './name' XPATH_NUMA_CELL = './cpu/numa/cell' @@ -1251,6 +1252,9 @@ class VMModel(object): else: maxmemory = memory + # get boot order + boot = xpath_get_text(xml, XPATH_BOOT) + return {'name': name, 'state': state, 'stats': res, @@ -1268,7 +1272,8 @@ class VMModel(object): 'users': users, 'groups': groups, 'access': 'full', - 'persistent': True if dom.isPersistent() else False + 'persistent': True if dom.isPersistent() else False, + 'bootorder': boot } def _vm_get_disk_paths(self, dom): -- 2.5.5

Also, update new entry on a test at test_model Signed-off-by: Ramon Medeiros <ramonn@linux.vnet.ibm.com> --- tests/test_model.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/test_model.py b/tests/test_model.py index 9a6a1aa..09ef995 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -118,7 +118,7 @@ class ModelTests(unittest.TestCase): keys = set(('name', 'state', 'stats', 'uuid', 'memory', 'cpu_info', 'screenshot', 'icon', 'graphics', 'users', 'groups', - 'access', 'persistent')) + 'access', 'persistent', 'bootorder')) stats_keys = set(('cpu_utilization', 'mem_utilization', 'net_throughput', 'net_throughput_peak', @@ -1124,6 +1124,19 @@ class ModelTests(unittest.TestCase): self.assertEquals([], inst.vm_lookup(u'пeω-∨м')['users']) self.assertEquals([], inst.vm_lookup(u'пeω-∨м')['groups']) + # change bootorder + b_order = ["hd", "network", "cdrom"] + inst.vm_update(u'пeω-∨м', {"bootorder": b_order}) + self.assertEquals(b_order, inst.vm_lookup(u'пeω-∨м')['bootorder']) + + # try to add empty list + self.assertRaises(OperationFailed, inst.vm_update, u'пeω-∨м', + {"bootorder": [""]}) + + # try to pass invalid parameter + self.assertRaises(OperationFailed, inst.vm_update, u'пeω-∨м', + {"bootorder": ["bla"]}) + def test_get_interfaces(self): inst = model.Model('test:///default', objstore_loc=self.tmp_store) -- 2.5.5

Please, ignore. I will resend it On 07/13/2016 01:30 PM, Ramon Medeiros wrote:
Changes:
v3: Update test on test_model to keep working
v2: Do not manipulate xml on model Improve parameters checking at API.json Increase test cases
Ramon Medeiros (6): Add function get_bootorder_node Create method to change bootorder of a guest Update documentation about bootorder on vm update Update REST API Add function to retrieve bootorder on vm lookup Add test to check bootorder
API.json | 23 +++++++++++++++++++++++ docs/API.md | 1 + i18n.py | 1 + model/vms.py | 32 ++++++++++++++++++++++++++++++-- tests/test_model.py | 15 ++++++++++++++- xmlutils/bootorder.py | 19 +++++++++++++------ 6 files changed, 82 insertions(+), 9 deletions(-)
-- Ramon Nunes Medeiros Kimchi Developer Linux Technology Center Brazil IBM Systems & Technology Group Phone : +55 19 2132 7878 ramonn@br.ibm.com
participants (1)
-
Ramon Medeiros