[PATCH V5] [Kimchi 0/4] Issue #372: Add support to netboot installation.

From: Paulo Vital <pvital@linux.vnet.ibm.com> V5: * Improved the changes in API for source_media * Added two new test cases * Updated UI to reflect the changes in template API V4: * Changed API of source_media to be a dictionary with type and path * Adapted source code to the new API V3: * set network as third default option to boot order V2: * Adapted patch to new template API (automatic detection of cdrom) V1: This patchset adds support in backend to create templates and guests to netboot without setting a cdrom path or URL as image to install. Once created a guest to boot via network, the guest will request DHCP/TFTP/(NFS/HTTP/FTP) network installation servers to download the configured images and start the install. Reference: http://miud.in/1Ht3 To test, use the curl commands (look the parameters used): $ curl -k -u test -H "Content-Type: application/json" -H \ "Accept: application/json" 'https://localhost:8001/plugins/kimchi/templates' \ -X POST -d '{"name": "test-netboot", "source_media": {"type": "netboot", "path": "/var/lib/libvirt/images/netboot"}}' Enter host password for user 'test': { "cpu_info":{ "maxvcpus":1, "vcpus":1 }, "graphics":{ "type":"vnc", "listen":"127.0.0.1" }, "cdrom":null, "networks":[ "default" ], "icon":"plugins/kimchi/images/icon-vm.png", "os_distro":"unknown", "name":"test-netboot", "disks":[ { "index":0, "format":"qcow2", "pool":{ "type":"dir", "name":"/plugins/kimchi/storagepools/default" }, "size":10 } ], "invalid":{}, "os_version":"unknown", "memory":{ "current":1024, "maxmemory":1024 }, "folder":[] } $ curl -k -u test -H "Content-Type: application/json" -H \ "Accept: application/json" 'https://localhost:8001/plugins/kimchi/vms' -X POST \ -d '{"name":"1netboot-test","template":"/plugins/kimchi/templates/test-netboot"}' Enter host password for user 'test': { "status":"running", "message":"Provisioning storages for new VM", "id":"1", "target_uri":"/plugins/kimchi/vms/1netboot-test" } $ sudo virsh dumpxml 1netboot-test <domain type='kvm'> <name>1netboot-test</name> <uuid>5c9fa5b3-3203-4c93-92d6-2b4103fe7b40</uuid> <metadata> <kimchi:metadata xmlns:kimchi="https://github.com/kimchi-project/kimchi"> <kimchi:os version="unknown" distro="unknown"/> </kimchi:metadata> </metadata> <memory unit='KiB'>1048576</memory> <currentMemory unit='KiB'>1048576</currentMemory> <memtune> <hard_limit unit='KiB'>2097152</hard_limit> </memtune> <vcpu placement='static'>1</vcpu> <os> <type arch='x86_64' machine='pc-i440fx-2.4'>hvm</type> <boot dev='hd'/> <boot dev='cdrom'/> <boot dev='network'/> </os> <acpi/> <apic/> <pae/> </features> <cpu> <numa> <cell id='0' cpus='0' memory='1048576' unit='KiB'/> </numa> </cpu> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> <emulator>/usr/bin/qemu-kvm</emulator> <disk type='file' device='disk'> <driver name='qemu' type='qcow2' cache='none'/> <source file='/var/lib/libvirt/images/5c9fa5b3-3203-4c93-92d6-2b4103fe7b40-0.img'/> <target dev='hda' bus='ide'/> <address type='drive' controller='0' bus='0' target='0' unit='0'/> </disk> <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> </controller> <controller type='pci' index='0' model='pci-root'/> <controller type='ide' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> </controller> <interface type='network'> <mac address='52:54:00:ea:7e:ad'/> <source network='default'/> <model type='e1000'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> <serial type='pty'> <target port='0'/> </serial> <console type='pty'> <target type='serial' port='0'/> </console> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'> <listen type='address' address='127.0.0.1'/> </graphics> <sound model='ich6'> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </sound> <video> <model type='cirrus' vram='16384' heads='1'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </video> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </memballoon> </devices> </domain> Paulo Vital (4): Add support to create netboot templates. Add support to create guests to netboot. Update test cases to support netboot. Update UI to reflect modifications in template API API.json | 18 +++++-- model/templates.py | 14 +++++- tests/test_authorization.py | 4 +- tests/test_mockmodel.py | 15 ++++-- tests/test_model.py | 73 ++++++++++++++++++++------- tests/test_rest.py | 95 ++++++++++++++++++++++++++++++----- tests/test_template.py | 53 ++++++++++++++----- tests/test_vmtemplate.py | 18 +++++++ ui/js/src/kimchi.template_add_main.js | 4 +- vmtemplate.py | 28 +++++++---- xmlutils/bootorder.py | 39 ++++++++++++++ 11 files changed, 298 insertions(+), 63 deletions(-) create mode 100644 xmlutils/bootorder.py -- 2.5.5

From: Paulo Vital <pvital@linux.vnet.ibm.com> Changed API.json and model to accept 'netboot' as source media parameter while creating a new template. Now, when creating a new template and specifying 'netboot' as source media parameter, it is assumed the template will use netboot process - PXE/DHCP/ TFTP/(NFS/HTTP/FTP). This is part of solution to Issue #372. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- API.json | 18 +++++++++++++++--- model/templates.py | 14 +++++++++++++- vmtemplate.py | 4 ++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/API.json b/API.json index 380ed19..d452270 100644 --- a/API.json +++ b/API.json @@ -505,9 +505,21 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", - "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "type" : "object", + "properties" : { + "type": { + "description": "Type of source media: disk or netboot", + "type": "string", + "pattern": "^disk|netboot$", + "required": true + }, + "path": { + "description": "Path for installation media (ISO, disk, remote ISO)", + "type": "string", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$" + } + }, + "additionalProperties": false, "required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index 431cae0..90b6603 100644 --- a/model/templates.py +++ b/model/templates.py @@ -63,9 +63,21 @@ class TemplatesModel(object): 'template': name}) # get source_media - path = params.pop("source_media") + source_media = params.get("source_media", None) + + if source_media['type'] == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + else: + # Get path of source media if it's based on disk type. + path = source_media.get('path', None) + + if path is None: + raise InvalidParameter("KCHTMPL0016E") # not local image: set as remote ISO + path = path.encode('utf-8') if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: params["cdrom"] = path diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..3e4418f 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -123,6 +123,10 @@ class VMTemplate(object): def _get_os_info(self, args, scan): distro = version = 'unknown' + if 'source_media' in args.keys(): + if args['source_media']['type'] == 'netboot': + return distro, version + # Identify the cdrom if present iso = args.get('cdrom', '') if len(iso) > 0: -- 2.5.5

On 04/26/2016 03:30 PM, pvital@linux.vnet.ibm.com wrote:
From: Paulo Vital <pvital@linux.vnet.ibm.com>
Changed API.json and model to accept 'netboot' as source media parameter while creating a new template.
Now, when creating a new template and specifying 'netboot' as source media parameter, it is assumed the template will use netboot process - PXE/DHCP/ TFTP/(NFS/HTTP/FTP).
This is part of solution to Issue #372.
Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- API.json | 18 +++++++++++++++--- model/templates.py | 14 +++++++++++++- vmtemplate.py | 4 ++++ 3 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/API.json b/API.json index 380ed19..d452270 100644 --- a/API.json +++ b/API.json @@ -505,9 +505,21 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", - "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "type" : "object", + "properties" : { + "type": { + "description": "Type of source media: disk or netboot", + "type": "string", + "pattern": "^disk|netboot$", + "required": true + }, + "path": { + "description": "Path for installation media (ISO, disk, remote ISO)", + "type": "string", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$" + } + }, + "additionalProperties": false, "required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index 431cae0..90b6603 100644 --- a/model/templates.py +++ b/model/templates.py @@ -63,9 +63,21 @@ class TemplatesModel(object): 'template': name})
# get source_media - path = params.pop("source_media") + source_media = params.get("source_media", None) + + if source_media['type'] == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + else: + # Get path of source media if it's based on disk type. + path = source_media.get('path', None) + + if path is None: + raise InvalidParameter("KCHTMPL0016E")
# not local image: set as remote ISO + path = path.encode('utf-8') if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: params["cdrom"] = path diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..3e4418f 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -123,6 +123,10 @@ class VMTemplate(object): def _get_os_info(self, args, scan): distro = version = 'unknown'
+ if 'source_media' in args.keys(): how can source_media be present here? We used .pop on model/templates + if args['source_media']['type'] == 'netboot': + return distro, version + # Identify the cdrom if present iso = args.get('cdrom', '') if len(iso) > 0:
-- Ramon Nunes Medeiros Kimchi Developer Linux Technology Center Brazil IBM Systems & Technology Group Phone : +55 19 2132 7878 ramonn@br.ibm.com

On Apr 26 04:32PM, Ramon Medeiros wrote:
On 04/26/2016 03:30 PM, pvital@linux.vnet.ibm.com wrote:
From: Paulo Vital <pvital@linux.vnet.ibm.com>
Changed API.json and model to accept 'netboot' as source media parameter while creating a new template.
Now, when creating a new template and specifying 'netboot' as source media parameter, it is assumed the template will use netboot process - PXE/DHCP/ TFTP/(NFS/HTTP/FTP).
This is part of solution to Issue #372.
Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- API.json | 18 +++++++++++++++--- model/templates.py | 14 +++++++++++++- vmtemplate.py | 4 ++++ 3 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/API.json b/API.json index 380ed19..d452270 100644 --- a/API.json +++ b/API.json @@ -505,9 +505,21 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", - "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "type" : "object", + "properties" : { + "type": { + "description": "Type of source media: disk or netboot", + "type": "string", + "pattern": "^disk|netboot$", + "required": true + }, + "path": { + "description": "Path for installation media (ISO, disk, remote ISO)", + "type": "string", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$" + } + }, + "additionalProperties": false, "required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index 431cae0..90b6603 100644 --- a/model/templates.py +++ b/model/templates.py @@ -63,9 +63,21 @@ class TemplatesModel(object): 'template': name})
# get source_media - path = params.pop("source_media") + source_media = params.get("source_media", None) + + if source_media['type'] == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + else: + # Get path of source media if it's based on disk type. + path = source_media.get('path', None) + + if path is None: + raise InvalidParameter("KCHTMPL0016E")
# not local image: set as remote ISO + path = path.encode('utf-8') if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: params["cdrom"] = path diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..3e4418f 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -123,6 +123,10 @@ class VMTemplate(object): def _get_os_info(self, args, scan): distro = version = 'unknown'
+ if 'source_media' in args.keys(): how can source_media be present here? We used .pop on model/templates
I changed to .get to keep the parameters persistent through the code flow.
+ if args['source_media']['type'] == 'netboot': + return distro, version + # Identify the cdrom if present iso = args.get('cdrom', '') if len(iso) > 0:
--
Ramon Nunes Medeiros Kimchi Developer Linux Technology Center Brazil IBM Systems & Technology Group Phone : +55 19 2132 7878 ramonn@br.ibm.com
-- Paulo Ricardo Paz Vital Linux Technology Center, IBM Systems http://www.ibm.com/linux/ltc/

On 04/26/2016 04:47 PM, Paulo Ricardo Paz Vital wrote:
On Apr 26 04:32PM, Ramon Medeiros wrote:
On 04/26/2016 03:30 PM, pvital@linux.vnet.ibm.com wrote:
From: Paulo Vital <pvital@linux.vnet.ibm.com>
Changed API.json and model to accept 'netboot' as source media parameter while creating a new template.
Now, when creating a new template and specifying 'netboot' as source media parameter, it is assumed the template will use netboot process - PXE/DHCP/ TFTP/(NFS/HTTP/FTP).
This is part of solution to Issue #372.
Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- API.json | 18 +++++++++++++++--- model/templates.py | 14 +++++++++++++- vmtemplate.py | 4 ++++ 3 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/API.json b/API.json index 380ed19..d452270 100644 --- a/API.json +++ b/API.json @@ -505,9 +505,21 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", - "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "type" : "object", + "properties" : { + "type": { + "description": "Type of source media: disk or netboot", + "type": "string", + "pattern": "^disk|netboot$", + "required": true + }, + "path": { + "description": "Path for installation media (ISO, disk, remote ISO)", + "type": "string", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$" + } + }, + "additionalProperties": false, "required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index 431cae0..90b6603 100644 --- a/model/templates.py +++ b/model/templates.py @@ -63,9 +63,21 @@ class TemplatesModel(object): 'template': name})
# get source_media - path = params.pop("source_media") + source_media = params.get("source_media", None) + + if source_media['type'] == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + else: + # Get path of source media if it's based on disk type. + path = source_media.get('path', None) + + if path is None: + raise InvalidParameter("KCHTMPL0016E")
# not local image: set as remote ISO + path = path.encode('utf-8') if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: params["cdrom"] = path diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..3e4418f 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -123,6 +123,10 @@ class VMTemplate(object): def _get_os_info(self, args, scan): distro = version = 'unknown'
+ if 'source_media' in args.keys(): how can source_media be present here? We used .pop on model/templates
I changed to .get to keep the parameters persistent through the code flow. ok. Don't forget to remove the source_media before storing the template to objectstore. We don't want to save this info at template
+ if args['source_media']['type'] == 'netboot': + return distro, version + # Identify the cdrom if present iso = args.get('cdrom', '') if len(iso) > 0: --
Ramon Nunes Medeiros Kimchi Developer Linux Technology Center Brazil IBM Systems & Technology Group Phone : +55 19 2132 7878 ramonn@br.ibm.com
-- Paulo Ricardo Paz Vital Linux Technology Center, IBM Systems http://www.ibm.com/linux/ltc/
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Ramon Nunes Medeiros Kimchi Developer Linux Technology Center Brazil IBM Systems & Technology Group Phone : +55 19 2132 7878 ramonn@br.ibm.com

On 04/26/2016 05:48 PM, Ramon Medeiros wrote:
On 04/26/2016 04:47 PM, Paulo Ricardo Paz Vital wrote:
On Apr 26 04:32PM, Ramon Medeiros wrote:
On 04/26/2016 03:30 PM, pvital@linux.vnet.ibm.com wrote:
From: Paulo Vital <pvital@linux.vnet.ibm.com>
Changed API.json and model to accept 'netboot' as source media parameter while creating a new template.
Now, when creating a new template and specifying 'netboot' as source media parameter, it is assumed the template will use netboot process - PXE/DHCP/ TFTP/(NFS/HTTP/FTP).
This is part of solution to Issue #372.
Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- API.json | 18 +++++++++++++++--- model/templates.py | 14 +++++++++++++- vmtemplate.py | 4 ++++ 3 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/API.json b/API.json index 380ed19..d452270 100644 --- a/API.json +++ b/API.json @@ -505,9 +505,21 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", - "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "type" : "object", + "properties" : { + "type": { + "description": "Type of source media: disk or netboot", + "type": "string", + "pattern": "^disk|netboot$", + "required": true + }, + "path": { + "description": "Path for installation media (ISO, disk, remote ISO)", + "type": "string", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$" + } + }, + "additionalProperties": false, "required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index 431cae0..90b6603 100644 --- a/model/templates.py +++ b/model/templates.py @@ -63,9 +63,21 @@ class TemplatesModel(object): 'template': name})
# get source_media - path = params.pop("source_media") + source_media = params.get("source_media", None) + + if source_media['type'] == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + else: + # Get path of source media if it's based on disk type. + path = source_media.get('path', None) + + if path is None: + raise InvalidParameter("KCHTMPL0016E")
# not local image: set as remote ISO + path = path.encode('utf-8') if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: params["cdrom"] = path diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..3e4418f 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -123,6 +123,10 @@ class VMTemplate(object): def _get_os_info(self, args, scan): distro = version = 'unknown'
+ if 'source_media' in args.keys(): how can source_media be present here? We used .pop on model/templates
I changed to .get to keep the parameters persistent through the code flow.
ok. Don't forget to remove the source_media before storing the template to objectstore. We don't want to save this info at template
Good point! Thinking about that, it would be better to have the netboot information as a parameter instead of part of params object. VMTemplate(..., netboot=True)
+ if args['source_media']['type'] == 'netboot': + return distro, version + # Identify the cdrom if present iso = args.get('cdrom', '') if len(iso) > 0: --
Ramon Nunes Medeiros Kimchi Developer Linux Technology Center Brazil IBM Systems & Technology Group Phone : +55 19 2132 7878 ramonn@br.ibm.com
-- Paulo Ricardo Paz Vital Linux Technology Center, IBM Systems http://www.ibm.com/linux/ltc/
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

From: Paulo Vital <pvital@linux.vnet.ibm.com> Add support to create guests without CD-ROM device information and setting the second boot order option as 'netboot'. This is part of solution to Issue #372. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- vmtemplate.py | 24 +++++++++++++++--------- xmlutils/bootorder.py | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 xmlutils/bootorder.py diff --git a/vmtemplate.py b/vmtemplate.py index 3e4418f..0611a07 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -33,6 +33,7 @@ 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.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 from wok.plugins.kimchi.xmlutils.graphics import get_graphics_xml @@ -174,7 +175,7 @@ class VMTemplate(object): def _get_cdrom_xml(self, libvirt_stream_protocols): if 'cdrom' not in self.info: - return '' + return None params = {} params['type'] = 'cdrom' @@ -354,12 +355,18 @@ class VMTemplate(object): libvirt_stream_protocols = kwargs.get('libvirt_stream_protocols', []) cdrom_xml = self._get_cdrom_xml(libvirt_stream_protocols) - if not urlparse.urlparse(self.info.get('cdrom', "")).scheme in \ - libvirt_stream_protocols and \ - params.get('iso_stream', False): - params['qemu-stream-cmdline'] = cdrom_xml - else: - params['cdroms'] = cdrom_xml + # Add information of CD-ROM device only if template have info about it. + if cdrom_xml is not None: + if not urlparse.urlparse(self.info.get('cdrom', "")).scheme in \ + libvirt_stream_protocols and \ + params.get('iso_stream', False): + params['qemu-stream-cmdline'] = cdrom_xml + else: + params['cdroms'] = cdrom_xml + + # Set the boot order of VM + # TODO: need modify this when boot order edition feature came upstream. + params['boot_order'] = get_bootorder_xml() # Setting maximum number of slots to avoid errors when hotplug memory # Number of slots are the numbers of chunks of 1GB that fit inside @@ -413,8 +420,7 @@ class VMTemplate(object): %(cpu_info_xml)s <os> <type arch='%(arch)s'>hvm</type> - <boot dev='hd'/> - <boot dev='cdrom'/> + %(boot_order)s </os> <features> <acpi/> diff --git a/xmlutils/bootorder.py b/xmlutils/bootorder.py new file mode 100644 index 0000000..28457e7 --- /dev/null +++ b/xmlutils/bootorder.py @@ -0,0 +1,39 @@ +# +# Project Kimchi +# +# Copyright IBM Corp, 2016 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import lxml.etree as ET +from lxml.builder import E + + +def get_bootorder_xml(boot_order=['hd', 'cdrom', 'network']): + """ + Returns the XML for boot order. The default return includes the following: + + <boot dev='hd'/> + <boot dev='cdrom'/> + <boot dev='network'/> + + To a different boot order, specify the order by a list as argument. + """ + boot_xml = '' + for device in boot_order: + boot = E.boot(dev=device) + boot_xml += ET.tostring(boot, encoding='utf-8', pretty_print=True) + + return boot_xml -- 2.5.5

From: Paulo Vital <pvital@linux.vnet.ibm.com> Update test cases to support the creation of netboot templates and creation of guests without cdrom. This is part of solution to Issue #372. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- tests/test_authorization.py | 4 +- tests/test_mockmodel.py | 15 ++++--- tests/test_model.py | 74 +++++++++++++++++++++++++++-------- tests/test_rest.py | 95 +++++++++++++++++++++++++++++++++++++++------ tests/test_template.py | 53 ++++++++++++++++++------- tests/test_vmtemplate.py | 18 +++++++++ 6 files changed, 211 insertions(+), 48 deletions(-) diff --git a/tests/test_authorization.py b/tests/test_authorization.py index 7cf8da2..cbeca04 100644 --- a/tests/test_authorization.py +++ b/tests/test_authorization.py @@ -100,7 +100,9 @@ class AuthorizationTests(unittest.TestCase): self.assertEquals(403, resp.status) # Non-root users can only get vms authorized to them - model.templates_create({'name': u'test', 'source_media': fake_iso}) + model.templates_create({'name': u'test', + 'source_media': {'type': 'disk', + 'path': fake_iso}}) task_info = model.vms_create({ 'name': u'test-me', diff --git a/tests/test_mockmodel.py b/tests/test_mockmodel.py index 41156f9..d5fffb4 100644 --- a/tests/test_mockmodel.py +++ b/tests/test_mockmodel.py @@ -66,7 +66,8 @@ class MockModelTests(unittest.TestCase): def test_screenshot_refresh(self): # Create a VM - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': fake_iso}}) request(host, ssl_port, '/plugins/kimchi/templates', req, 'POST') req = json.dumps({'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}) @@ -96,7 +97,8 @@ class MockModelTests(unittest.TestCase): resp.getheader('last-modified')) def test_vm_list_sorted(self): - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': fake_iso}}) request(host, ssl_port, '/plugins/kimchi/templates', req, 'POST') def add_vm(name): @@ -116,7 +118,8 @@ class MockModelTests(unittest.TestCase): def test_memory_window_changes(self): model.templates_create({'name': u'test', - 'source_media': fake_iso}) + 'source_media': {'type': 'disk', + 'path': fake_iso}}) task = model.vms_create({'name': u'test-vm', 'template': '/plugins/kimchi/templates/test'}) wait_task(model.task_lookup, task['id']) @@ -128,7 +131,8 @@ class MockModelTests(unittest.TestCase): def test_hotplug_3D_card(self): model.templates_create({'name': u'test', - 'source_media': fake_iso}) + 'source_media': {'type': 'disk', + 'path': fake_iso}}) task = model.vms_create({'name': u'test-vm', 'template': '/plugins/kimchi/templates/test'}) wait_task(model.task_lookup, task['id']) @@ -148,7 +152,8 @@ class MockModelTests(unittest.TestCase): def test_vm_info(self): model.templates_create({'name': u'test', - 'source_media': fake_iso}) + 'source_media': {'type': 'disk', + 'path': fake_iso}}) task = model.vms_create({'name': u'test-vm', 'template': '/plugins/kimchi/templates/test'}) wait_task(model.task_lookup, task['id']) diff --git a/tests/test_model.py b/tests/test_model.py index 0804228..bf5ed28 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -136,7 +136,8 @@ class ModelTests(unittest.TestCase): task = inst.task_lookup(task['id']) self.assertEquals('finished', task['status']) - params = {'name': 'test', 'source_media': UBUNTU_ISO} + params = {'name': 'test', + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -269,7 +270,7 @@ class ModelTests(unittest.TestCase): "networks": ["default"], "memory": {'current': 1024}, "folder": [], "icon": "images/icon-vm.png", "os_distro": "unknown", "os_version": "unknown", - "source_media": vol_path} + "source_media": {'type': 'disk', 'path': vol_path}} inst.templates_create(tmpl_info) rollback.prependDefer(inst.template_delete, tmpl_name) @@ -296,7 +297,8 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_vm_graphics(self): inst = model.Model(objstore_loc=self.tmp_store) - params = {'name': 'test', 'source_media': UBUNTU_ISO} + params = {'name': 'test', + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) with RollbackContext() as rollback: params = {'name': 'kimchi-vnc', @@ -326,7 +328,8 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), "Must be run as root") def test_vm_serial(self): inst = model.Model(objstore_loc=self.tmp_store) - params = {'name': 'test', 'source_media': UBUNTU_ISO} + params = {'name': 'test', + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) with RollbackContext() as rollback: params = {'name': 'kimchi-serial', @@ -347,7 +350,8 @@ class ModelTests(unittest.TestCase): def test_vm_ifaces(self): inst = model.Model(objstore_loc=self.tmp_store) with RollbackContext() as rollback: - params = {'name': 'test', 'source_media': UBUNTU_ISO} + params = {'name': 'test', + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -414,6 +418,37 @@ class ModelTests(unittest.TestCase): self.assertEquals(mac, iface['mac']) @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_netboot(self): + inst = model.Model(objstore_loc=self.tmp_store) + with RollbackContext() as rollback: + params = {'name': 'test-netboot', + 'source_media': {'type': 'netboot'}} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test-netboot') + + params = {'name': 'kimchi-netboot-vm', + 'template': '/plugins/kimchi/templates/test-netboot'} + task = inst.vms_create(params) + rollback.prependDefer(inst.vm_delete, 'kimchi-netboot-vm') + inst.task_wait(task['id'], 10) + task = inst.task_lookup(task['id']) + self.assertEquals('finished', task['status']) + + vms = inst.vms_get_list() + self.assertTrue('kimchi-netboot-vm' in vms) + + inst.vm_start('kimchi-netboot-vm') + + info = inst.vm_lookup('kimchi-netboot-vm') + self.assertEquals('running', info['state']) + + inst.vm_poweroff(u'kimchi-netboot-vm') + vm = inst.vm_lookup(u'kimchi-netboot-vm') + + vms = inst.vms_get_list() + self.assertFalse('kimchi-netboot-vm' in vms) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_vm_disk(self): disk_path = os.path.join(TMP_DIR, 'existent2.iso') open(disk_path, 'w').close() @@ -463,7 +498,8 @@ class ModelTests(unittest.TestCase): inst.task_wait(task_id) vm_name = 'kimchi-cdrom' - params = {'name': 'test', 'disks': [], 'source_media': UBUNTU_ISO} + params = {'name': 'test', 'disks': [], + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') params = {'name': vm_name, @@ -507,7 +543,7 @@ class ModelTests(unittest.TestCase): vm_name = 'kimchi-ide-bus-vm' params = {'name': 'old_distro_template', 'disks': [], - 'source_media': old_distro_iso} + 'source_media': {'type': 'disk', 'path': old_distro_iso}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'old_distro_template') params = { @@ -532,7 +568,8 @@ class ModelTests(unittest.TestCase): inst = model.Model(objstore_loc=self.tmp_store) with RollbackContext() as rollback: vm_name = 'kimchi-cdrom' - params = {'name': 'test', 'disks': [], 'source_media': UBUNTU_ISO} + params = {'name': 'test', 'disks': [], + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') params = {'name': vm_name, @@ -623,7 +660,7 @@ class ModelTests(unittest.TestCase): with RollbackContext() as rollback: params = {'name': 'test', 'disks': [{'size': 1, 'pool': { 'name': '/plugins/kimchi/storagepools/default'}}], - 'source_media': UBUNTU_ISO} + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -683,7 +720,7 @@ class ModelTests(unittest.TestCase): params = {'name': 'test', 'disks': [{'size': 1, 'pool': { 'name': '/plugins/kimchi/storagepools/default'}}], - 'source_media': UBUNTU_ISO} + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -711,7 +748,7 @@ class ModelTests(unittest.TestCase): params = {'name': 'test', 'disks': [{ 'size': 1, 'format': user_vol, 'pool': {'name': '/plugins/kimchi/storagepools/default'}}], - 'source_media': UBUNTU_ISO} + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -737,7 +774,7 @@ class ModelTests(unittest.TestCase): params = {'name': 'test', 'disks': [{'size': 1, 'pool': { 'name': '/plugins/kimchi/storagepools/default'}}], - 'source_media': UBUNTU_ISO} + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -757,7 +794,7 @@ class ModelTests(unittest.TestCase): inst = model.Model(None, objstore_loc=self.tmp_store) orig_params = {'name': 'test', 'memory': {'current': 1024, 'maxmemory': 3072}, - 'source_media': UBUNTU_ISO} + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(orig_params) with RollbackContext() as rollback: @@ -794,7 +831,8 @@ class ModelTests(unittest.TestCase): # only supports this format orig_params = { 'name': 'test', 'memory': {'current': 1024}, - 'cpu_info': {'vcpus': 1}, 'source_media': UBUNTU_ISO, + 'cpu_info': {'vcpus': 1}, + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}, 'disks': [{'size': 1, 'format': 'qcow2', 'pool': { 'name': '/plugins/kimchi/storagepools/default'}}]} inst.templates_create(orig_params) @@ -1033,7 +1071,8 @@ class ModelTests(unittest.TestCase): inst = model.Model(objstore_loc=self.tmp_store) with RollbackContext() as rollback: - params = {'name': u'test', 'disks': [], 'source_media': UBUNTU_ISO} + params = {'name': u'test', 'disks': [], + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -1059,7 +1098,8 @@ class ModelTests(unittest.TestCase): inst = model.Model(objstore_loc=self.tmp_store) with RollbackContext() as rollback: - params = {'name': 'test', 'disks': [], 'source_media': UBUNTU_ISO} + params = {'name': 'test', 'disks': [], + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -1130,7 +1170,7 @@ class ModelTests(unittest.TestCase): with RollbackContext() as rollback: params = { 'name': 'test', - 'source_media': UBUNTU_ISO, + 'source_media': {'type': 'disk', 'path': UBUNTU_ISO}, 'domain': 'test', 'arch': 'i686', 'disks': [] diff --git a/tests/test_rest.py b/tests/test_rest.py index a009ed3..b73d16c 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -106,7 +106,8 @@ class RestTests(unittest.TestCase): self.assertEquals(1, len(vms)) # Create a template as a base for our VMs - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': fake_iso}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -133,7 +134,8 @@ class RestTests(unittest.TestCase): self.assertEquals([], vm['groups']) def test_edit_vm(self): - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': fake_iso}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -290,7 +292,8 @@ class RestTests(unittest.TestCase): def test_vm_lifecycle(self): # Create a Template - req = json.dumps({'name': 'test', 'source_media': fake_iso, + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': fake_iso}, 'disks': DISKS, 'icon': 'plugins/kimchi/images/icon-debian.png'}) resp = self.request('/plugins/kimchi/templates', req, 'POST') @@ -515,9 +518,68 @@ class RestTests(unittest.TestCase): # Verify the volume was deleted self.assertHTTPStatus(404, vol_uri % vm['uuid']) + def test_vm_netboot(self): + # Create a Template + req = json.dumps({'name': 'tnetboot', + 'source_media': {'type': 'netboot'}}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Create a VM + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/tnetboot'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + self.assertEquals(202, resp.status) + + # Verify the VM + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('shutoff', vm['state']) + self.assertEquals('plugins/kimchi/images/icon-vm.png', vm['icon']) + + # verify if poweroff command returns correct status + resp = self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', + 'POST') + self.assertEquals(400, resp.status) + + # verify if shutdown command returns correct status + resp = self.request('/plugins/kimchi/vms/test-vm/shutdown', '{}', + 'POST') + self.assertEquals(400, resp.status) + + # verify if reset command returns correct status + resp = self.request('/plugins/kimchi/vms/test-vm/reset', '{}', 'POST') + self.assertEquals(400, resp.status) + + # Start the VM + resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('running', vm['state']) + + # verify if start command returns correct status + resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') + self.assertEquals(400, resp.status) + + # Force poweroff the VM + resp = self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', + 'POST') + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('shutoff', vm['state']) + + # Delete the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Delete the Template + resp = self.request('/plugins/kimchi/templates/tnetboot', '{}', + 'DELETE') + self.assertEquals(204, resp.status) + def test_vm_graphics(self): # Create a Template - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': fake_iso}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -611,7 +673,9 @@ class RestTests(unittest.TestCase): with RollbackContext() as rollback: # Create a template as a base for our VMs - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', + 'path': fake_iso}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) # Delete the template @@ -784,7 +848,9 @@ class RestTests(unittest.TestCase): with RollbackContext() as rollback: # Create a template as a base for our VMs - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', + 'path': fake_iso}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) # Delete the template @@ -891,7 +957,7 @@ class RestTests(unittest.TestCase): def test_vm_customise_storage(self): # Create a Template req = json.dumps({'name': 'test', 'disks': DISKS, - 'source_media': fake_iso}) + 'source_media': {'type': 'disk', 'path': fake_iso}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -953,7 +1019,8 @@ class RestTests(unittest.TestCase): # Create template fails because SCSI volume is missing tmpl_params = { - 'name': 'test_fc_pool', 'source_media': fake_iso, + 'name': 'test_fc_pool', + 'source_media': {'type': 'disk', 'path': fake_iso}, 'disks': [{'pool': {'name': '/plugins/kimchi/storagepools/scsi_fc_pool'}}]} @@ -998,7 +1065,8 @@ class RestTests(unittest.TestCase): def test_unnamed_vms(self): # Create a Template - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': fake_iso}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -1040,7 +1108,8 @@ class RestTests(unittest.TestCase): # Create a Template mock_base = '/tmp/mock.img' os.system("qemu-img create -f qcow2 %s 10M" % mock_base) - req = json.dumps({'name': 'test', 'source_media': mock_base}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': mock_base}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -1110,7 +1179,8 @@ class RestTests(unittest.TestCase): # In real model os distro/version can be omitted # as we will scan the iso req = json.dumps({'name': 'test', - 'source_media': storagevolume['path'], + 'source_media': {'type': 'disk', + 'path': storagevolume['path']}, 'os_distro': storagevolume['os_distro'], 'os_version': storagevolume['os_version']}) resp = self.request('/plugins/kimchi/templates', req, 'POST') @@ -1148,7 +1218,8 @@ class RestTests(unittest.TestCase): def test_screenshot_refresh(self): # Create a VM - req = json.dumps({'name': 'test', 'source_media': fake_iso}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': fake_iso}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') req = json.dumps({'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}) diff --git a/tests/test_template.py b/tests/test_template.py index f0ef030..5de8393 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -80,8 +80,26 @@ class TemplateTests(unittest.TestCase): resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(400, resp.status) + # Create a netboot template + t = {'name': 'test-netboot', 'source_media': {'type': 'netboot'}} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Verify the netboot template + tmpl = json.loads( + self.request('/plugins/kimchi/templates/test-netboot').read() + ) + self.assertIsNone(tmpl['cdrom']) + + # Delete the netboot template + resp = self.request('/plugins/kimchi/templates/test-netboot', '{}', + 'DELETE') + self.assertEquals(204, resp.status) + # Create a template - t = {'name': 'test', 'source_media': MOCK_ISO} + t = {'name': 'test', + 'source_media': {'type': 'disk', 'path': MOCK_ISO}} req = json.dumps(t) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -93,7 +111,7 @@ class TemplateTests(unittest.TestCase): self.request('/plugins/kimchi/templates/test').read() ) self.assertEquals(sorted(tmpl.keys()), sorted(keys)) - self.assertEquals(t['source_media'], tmpl["cdrom"]) + self.assertEquals(t['source_media']['path'], tmpl["cdrom"]) disk_keys = ['index', 'pool', 'size', 'format'] disk_pool_keys = ['name', 'type'] self.assertEquals(sorted(tmpl['disks'][0].keys()), sorted(disk_keys)) @@ -119,22 +137,25 @@ class TemplateTests(unittest.TestCase): self.assertEquals(204, resp.status) # Create a template with same name fails with 400 - req = json.dumps({'name': 'test', 'source_media': MOCK_ISO}) + req = json.dumps({'name': 'test', + 'source_media': {'type': 'disk', 'path': MOCK_ISO}}) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(400, resp.status) # Create an image based template os.system("qemu-img create -f qcow2 %s 10G" % '/tmp/mock.img') - t = {'name': 'test_img_template', 'source_media': '/tmp/mock.img'} + t = {'name': 'test_img_template', + 'source_media': {'type': 'disk', 'path': '/tmp/mock.img'}} req = json.dumps(t) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) os.remove('/tmp/mock.img') # Test disk format - t = {'name': 'test-format', 'source_media': MOCK_ISO, 'disks': [{ - 'size': 10, 'format': 'vmdk', 'pool': { - 'name': DEFAULT_POOL}}]} + t = {'name': 'test-format', + 'source_media': {'type': 'disk', 'path': MOCK_ISO}, + 'disks': [{'size': 10, 'format': 'vmdk', + 'pool': {'name': DEFAULT_POOL}}]} req = json.dumps(t) resp = self.request('/plugins/kimchi/templates', req, 'POST') @@ -150,7 +171,8 @@ class TemplateTests(unittest.TestCase): else: max_mem = (psutil.TOTAL_PHYMEM >> 10 >> 10) memory = max_mem + 1024 - t = {'name': 'test-maxmem', 'source_media': MOCK_ISO, + t = {'name': 'test-maxmem', + 'source_media': {'type': 'disk', 'path': MOCK_ISO}, 'memory': {'current': memory}} req = json.dumps(t) resp = self.request('/plugins/kimchi/templates', req, 'POST') @@ -159,7 +181,8 @@ class TemplateTests(unittest.TestCase): def test_customized_tmpl(self): # Create a template - t = {'name': 'test', 'source_media': MOCK_ISO} + t = {'name': 'test', + 'source_media': {'type': 'disk', 'path': MOCK_ISO}} req = json.dumps(t) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -333,7 +356,8 @@ class TemplateTests(unittest.TestCase): def test_customized_network(self): # Create a template - t = {'name': 'test', 'source_media': MOCK_ISO} + t = {'name': 'test', + 'source_media': {'type': 'disk', 'path': MOCK_ISO}} req = json.dumps(t) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -369,7 +393,8 @@ class TemplateTests(unittest.TestCase): def test_customized_storagepool(self): # Create a template - t = {'name': 'test', 'source_media': MOCK_ISO} + t = {'name': 'test', + 'source_media': {'type': 'disk', 'path': MOCK_ISO}} req = json.dumps(t) resp = self.request('/plugins/kimchi/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -460,8 +485,10 @@ class TemplateTests(unittest.TestCase): self.request(pool_uri + '/activate', '{}', 'POST') # Create a template using the custom network and pool - t = {'name': 'test', 'source_media': mock_iso2, - 'networks': ['nat-network'], 'disks': [{'pool': { + t = {'name': 'test', + 'source_media': {'type': 'disk', 'path': mock_iso2}, + 'networks': ['nat-network'], + 'disks': [{'pool': { 'name': '/plugins/kimchi/storagepools/dir-pool'}, 'size': 2, 'format': 'qcow2'}]} diff --git a/tests/test_vmtemplate.py b/tests/test_vmtemplate.py index 503d34a..772093e 100644 --- a/tests/test_vmtemplate.py +++ b/tests/test_vmtemplate.py @@ -135,3 +135,21 @@ class VMTemplateTests(unittest.TestCase): self.assertEquals(['foo'], t.info.get('networks')) self.assertEquals(self.iso, t.info.get('cdrom')) self.assertEquals(graphics, t.info.get('graphics')) + + def test_netboot_vmtemplate(self): + disk_bus = get_template_default('old', 'disk_bus') + memory = get_template_default('old', 'memory') + nic_model = get_template_default('old', 'nic_model') + fields = (('name', 'test'), ('os_distro', 'unknown'), + ('os_version', 'unknown'), + ('cpu_info', {'vcpus': 1, 'maxvcpus': 1}), + ('memory', memory), ('networks', ['default']), + ('disk_bus', disk_bus), ('nic_model', nic_model), + ('graphics', {'type': 'vnc', 'listen': '127.0.0.1'})) + + args = {'name': 'test', 'source_media': {'type': 'netboot'}} + t = VMTemplate(args) + for name, val in fields: + self.assertEquals(val, t.info.get(name)) + + self.assertNotIn('cdrom', t.info.keys()) -- 2.5.5

From: Paulo Vital <pvital@linux.vnet.ibm.com> Modified ui/js/src/kimchi.template_add_main.js to reflect the template API changes in source_media field. This is part of solution to Issue #372. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- tests/test_mockmodel.py | 2 +- tests/test_model.py | 1 - ui/js/src/kimchi.template_add_main.js | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_mockmodel.py b/tests/test_mockmodel.py index d5fffb4..45358fe 100644 --- a/tests/test_mockmodel.py +++ b/tests/test_mockmodel.py @@ -118,7 +118,7 @@ class MockModelTests(unittest.TestCase): def test_memory_window_changes(self): model.templates_create({'name': u'test', - 'source_media': {'type': 'disk', + 'source_media': {'type': 'disk', 'path': fake_iso}}) task = model.vms_create({'name': u'test-vm', 'template': '/plugins/kimchi/templates/test'}) diff --git a/tests/test_model.py b/tests/test_model.py index bf5ed28..4af3b2c 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -443,7 +443,6 @@ class ModelTests(unittest.TestCase): self.assertEquals('running', info['state']) inst.vm_poweroff(u'kimchi-netboot-vm') - vm = inst.vm_lookup(u'kimchi-netboot-vm') vms = inst.vms_get_list() self.assertFalse('kimchi-netboot-vm' in vms) diff --git a/ui/js/src/kimchi.template_add_main.js b/ui/js/src/kimchi.template_add_main.js index c3dd014..88d26e2 100644 --- a/ui/js/src/kimchi.template_add_main.js +++ b/ui/js/src/kimchi.template_add_main.js @@ -260,7 +260,7 @@ kimchi.template_add_main = function() { return; } var data = { - "source_media": isoFile + "source_media": {"type": "disk", "path": isoFile} }; addTemplate(data); }); @@ -356,7 +356,7 @@ kimchi.template_add_main = function() { var data = { "os_distro": isoInfo.os_distro, "os_version": isoInfo.os_version, - "source_media": isoInfo.path + "source_media": {"type": "disk", "path": isoInfo.path} }; kimchi.createTemplate(data, function() { successNum++; -- 2.5.5
participants (4)
-
Aline Manera
-
Paulo Ricardo Paz Vital
-
pvital@linux.vnet.ibm.com
-
Ramon Medeiros