
Signed-off-by: Ramon Medeiros <ramonn@linux.vnet.ibm.com> --- API.json | 5 +++++ docs/API.md | 1 + i18n.py | 1 + model/vms.py | 30 +++++++++++++++++++++--------- xmlutils/bootorder.py | 4 ++++ 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/API.json b/API.json index 1772abb..4fdd522 100644 --- a/API.json +++ b/API.json @@ -317,6 +317,11 @@ "additionalItems": false, "uniqueItems": true }, + "bootmenu": { + "description": "Bootmenu on guest power on", + "error": "KCHVM0053E", + "type": "boolean" + }, "users": { "description": "Array of users who have permission to the VM", "type": "array", diff --git a/docs/API.md b/docs/API.md index 4a40e70..971f28e 100644 --- a/docs/API.md +++ b/docs/API.md @@ -175,6 +175,7 @@ server. * cores - The number of cores per socket. * threads - The number of threads per core. * bootorder: guest bootorder, types accepted: hd, cdrom, network or fd + * bootmenu: prompts guest bootmenu. Bool type. * **POST**: *See Virtual Machine Actions* diff --git a/i18n.py b/i18n.py index e8fdf88..6ca19fd 100644 --- a/i18n.py +++ b/i18n.py @@ -105,6 +105,7 @@ messages = { "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."), + "KCHVM0053E": _("Bootmenu must be boolean. Values accepted: true of false."), "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."), diff --git a/model/vms.py b/model/vms.py index 17159fe..dc637d7 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_bootmenu_node 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 @@ -82,7 +83,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', 'bootorder'] + 'name', 'users', 'bootorder', 'bootmenu'] XPATH_DOMAIN_DISK = "/domain/devices/disk[@device='disk']/source/@file" XPATH_DOMAIN_DISK_BY_FILE = "./devices/disk[@device='disk']/source[@file='%s']" @@ -95,6 +96,7 @@ XPATH_DOMAIN_UUID = '/domain/uuid' XPATH_DOMAIN_DEV_CPU_ID = '/domain/devices/spapr-cpu-socket/@id' XPATH_BOOT = 'os/boot/@dev' +XPATH_BOOTMENU = 'os/bootmenu/@enable' XPATH_CPU = './cpu' XPATH_NAME = './name' XPATH_NUMA_CELL = './cpu/numa/cell' @@ -758,9 +760,16 @@ class VMModel(object): for device in os.findall("boot"): os.remove(device) - # add new - for device in get_bootorder_node(params): - os.append(device) + # add new bootorder + if "bootorder" in params: + for device in get_bootorder_node(params["bootorder"]): + os.append(device) + + # update bootmenu + if params.get("bootmenu") is False: + [os.remove(bm) for bm in os.findall("bootmenu")] + elif params.get("bootmenu") is True: + os.append(get_bootmenu_node()) # update <os> return ET.tostring(et) @@ -811,9 +820,9 @@ 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"]) + # update bootorder or bootmenu + if "bootorder" or "bootmenu" in params: + new_xml = self._update_bootorder(new_xml, params) snapshots_info = [] conn = self.conn.get() @@ -1252,8 +1261,10 @@ class VMModel(object): else: maxmemory = memory - # get boot order + # get boot order and bootmenu boot = xpath_get_text(xml, XPATH_BOOT) + bootmenu = "yes" if "yes" in xpath_get_text(xml, XPATH_BOOTMENU) \ + else "no" return {'name': name, 'state': state, @@ -1273,7 +1284,8 @@ class VMModel(object): 'groups': groups, 'access': 'full', 'persistent': True if dom.isPersistent() else False, - 'bootorder': boot + 'bootorder': boot, + 'bootmenu': bootmenu } def _vm_get_disk_paths(self, dom): diff --git a/xmlutils/bootorder.py b/xmlutils/bootorder.py index 6d92bd6..f8bc6ea 100644 --- a/xmlutils/bootorder.py +++ b/xmlutils/bootorder.py @@ -47,3 +47,7 @@ def get_bootorder_xml(boot_order=None): boot_xml += ET.tostring(device, encoding='utf-8', pretty_print=True) return boot_xml + + +def get_bootmenu_node(): + return E.bootmenu(enable="yes", timeout="5000") -- 2.5.5