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

From: Paulo Vital <pvital@linux.vnet.ibm.com> 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": "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 (3): Add support to create netboot templates. Add support to create guests to netboot. Update test cases to support netboot. API.json | 4 ++-- model/templates.py | 11 ++++++++++- tests/test_template.py | 17 +++++++++++++++++ tests/test_vmtemplate.py | 18 ++++++++++++++++++ vmtemplate.py | 25 ++++++++++++++----------- xmlutils/bootorder.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 14 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 | 4 ++-- model/templates.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/API.json b/API.json index ff505b1..2926620 100644 --- a/API.json +++ b/API.json @@ -469,9 +469,9 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", + "description": "Path for installation media (ISO, disk, remote ISO) or netboot", "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$|(netboot)", "required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index a02099c..043fe49 100644 --- a/model/templates.py +++ b/model/templates.py @@ -65,6 +65,12 @@ class TemplatesModel(object): # get source_media path = params.pop("source_media") + # Check if source_media is 'netboot' + if path == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + # not local image: set as remote ISO if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: @@ -104,7 +110,10 @@ class TemplatesModel(object): def save_template(self, params): # Creates the template class with necessary information - t = LibvirtVMTemplate(params, scan=True, conn=self.conn) + if 'cdrom' not in params.keys(): + t = LibvirtVMTemplate(params, conn=self.conn) + else: + t = LibvirtVMTemplate(params, scan=True, conn=self.conn) # Validate cpu info t.cpuinfo_validate() -- 2.5.5

On 04/15/2016 03:54 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 | 4 ++-- model/templates.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/API.json b/API.json index ff505b1..2926620 100644 --- a/API.json +++ b/API.json @@ -469,9 +469,9 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", + "description": "Path for installation media (ISO, disk, remote ISO) or netboot", "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$|(netboot)",
What happens if my ISO file and image file is named as 'netboot'? It is better to do not mix things. I suggest to have source_media type changed to a dict with path and type values. Example: source_media: {type: disk/netboot, path: <only applicable for disk type} To specify a disk input, use type=disk and require a path value To create a netboot template, specify type=netboot and raise an error if any path is specified.
"required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index a02099c..043fe49 100644 --- a/model/templates.py +++ b/model/templates.py @@ -65,6 +65,12 @@ class TemplatesModel(object): # get source_media path = params.pop("source_media")
+ # Check if source_media is 'netboot' + if path == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + # not local image: set as remote ISO if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: @@ -104,7 +110,10 @@ class TemplatesModel(object): def save_template(self, params):
# Creates the template class with necessary information - t = LibvirtVMTemplate(params, scan=True, conn=self.conn) + if 'cdrom' not in params.keys(): + t = LibvirtVMTemplate(params, conn=self.conn) + else: + t = LibvirtVMTemplate(params, scan=True, conn=self.conn)
# Validate cpu info t.cpuinfo_validate()

On Apr 18 01:09PM, Aline Manera wrote:
On 04/15/2016 03:54 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 | 4 ++-- model/templates.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/API.json b/API.json index ff505b1..2926620 100644 --- a/API.json +++ b/API.json @@ -469,9 +469,9 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", + "description": "Path for installation media (ISO, disk, remote ISO) or netboot", "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$|(netboot)",
What happens if my ISO file and image file is named as 'netboot'?
Code still works in the normal way, just because the regex is clear. Or user inputs (1) a complete file path (starting with '/') or URL link (starting with 'http(s):' or '(t)ftp(s):'); or (2) the word 'netboot'. So, even if a ISO file or image files is named as 'netboot', user needs to provide the full path, matching the beginning of the regex, or it will not work. See my test here: $ curl -k -u test -H "Content-Type: application/json" -H "Accept: application/json" 'https://localhost:8001/plugins/kimchi/templates' -X POST -d '{"source_media": "/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":"/var/lib/libvirt/images/netboot", "networks":[ "default" ], "icon":"plugins/kimchi/images/icon-ubuntu.png", "os_distro":"ubuntu", "name":"ubuntu14.04.1461002267700", "disks":[ { "index":0, "format":"qcow2", "pool":{ "type":"dir", "name":"/plugins/kimchi/storagepools/default" }, "size":10 } ], "invalid":{}, "os_version":"14.04", "memory":{ "current":1024, "maxmemory":1024 }, "folder":[] }
It is better to do not mix things.
I suggest to have source_media type changed to a dict with path and type values.
Example:
source_media: {type: disk/netboot, path: <only applicable for disk type}
To specify a disk input, use type=disk and require a path value To create a netboot template, specify type=netboot and raise an error if any path is specified.
I got your point and this also works, but doesn't this idea move back, let's say half-step, to the point before Ramon's patch to automatically detect the type of media? I mean, implementing your suggestion I'll be moving most part of the user's imput check to the model/templates.py files, instead of let JSON regex works. IMO, the current implementation keeps things simple to read and maintain.
"required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index a02099c..043fe49 100644 --- a/model/templates.py +++ b/model/templates.py @@ -65,6 +65,12 @@ class TemplatesModel(object): # get source_media path = params.pop("source_media")
+ # Check if source_media is 'netboot' + if path == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + # not local image: set as remote ISO if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: @@ -104,7 +110,10 @@ class TemplatesModel(object): def save_template(self, params):
# Creates the template class with necessary information - t = LibvirtVMTemplate(params, scan=True, conn=self.conn) + if 'cdrom' not in params.keys(): + t = LibvirtVMTemplate(params, conn=self.conn) + else: + t = LibvirtVMTemplate(params, scan=True, conn=self.conn)
# Validate cpu info t.cpuinfo_validate()
-- Paulo Ricardo Paz Vital Linux Technology Center, IBM Systems http://www.ibm.com/linux/ltc/

On 04/18/2016 03:12 PM, Paulo Ricardo Paz Vital wrote:
On Apr 18 01:09PM, Aline Manera wrote:
On 04/15/2016 03:54 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 | 4 ++-- model/templates.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/API.json b/API.json index ff505b1..2926620 100644 --- a/API.json +++ b/API.json @@ -469,9 +469,9 @@ }, "memory": { "$ref": "#/kimchitype/memory" }, "source_media": { - "description": "Path for installation media (ISO, disk, remote ISO)", + "description": "Path for installation media (ISO, disk, remote ISO) or netboot", "type" : "string", - "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$|(netboot)", What happens if my ISO file and image file is named as 'netboot'?
Code still works in the normal way, just because the regex is clear. Or user inputs (1) a complete file path (starting with '/') or URL link (starting with 'http(s):' or '(t)ftp(s):'); or (2) the word 'netboot'.
Yeap! I haven't remembered about the path regex.
So, even if a ISO file or image files is named as 'netboot', user needs to provide the full path, matching the beginning of the regex, or it will not work.
See my test here:
$ curl -k -u test -H "Content-Type: application/json" -H "Accept: application/json" 'https://localhost:8001/plugins/kimchi/templates' -X POST -d '{"source_media": "/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":"/var/lib/libvirt/images/netboot", "networks":[ "default" ], "icon":"plugins/kimchi/images/icon-ubuntu.png", "os_distro":"ubuntu", "name":"ubuntu14.04.1461002267700", "disks":[ { "index":0, "format":"qcow2", "pool":{ "type":"dir", "name":"/plugins/kimchi/storagepools/default" }, "size":10 } ], "invalid":{}, "os_version":"14.04", "memory":{ "current":1024, "maxmemory":1024 }, "folder":[] }
It is better to do not mix things.
I suggest to have source_media type changed to a dict with path and type values.
Example:
source_media: {type: disk/netboot, path: <only applicable for disk type}
To specify a disk input, use type=disk and require a path value To create a netboot template, specify type=netboot and raise an error if any path is specified.
I got your point and this also works, but doesn't this idea move back, let's say half-step, to the point before Ramon's patch to automatically detect the type of media?
The user will need to specify netboot or local boot, right? So I am not sure what you meant about that.
I mean, implementing your suggestion I'll be moving most part of the user's imput check to the model/templates.py files, instead of let JSON regex works. IMO, the current implementation keeps things simple to read and maintain.
The regex will keep on JSON schema as it is today but in a different data structure. For example: source_media: {type: object, required: true, properties: {"type": "string", "pattern": "^disk|netboot$", required: true}, {"path": "string", "pattern": "<the same pattern used today>"} The only validation on model will be to make sure a 'path' is set when type=disk. IMO that way we keep the API semantic and it is better to a developer identify what the parameter is for. Let me know your thoughts on it.
"required": true }, "disks": { diff --git a/model/templates.py b/model/templates.py index a02099c..043fe49 100644 --- a/model/templates.py +++ b/model/templates.py @@ -65,6 +65,12 @@ class TemplatesModel(object): # get source_media path = params.pop("source_media")
+ # Check if source_media is 'netboot' + if path == 'netboot': + params['os_distro'] = 'unknown' + params['os_version'] = 'unknown' + return self.save_template(params) + # not local image: set as remote ISO if urlparse.urlparse(path).scheme in ["http", "https", "tftp", "ftp", "ftps"]: @@ -104,7 +110,10 @@ class TemplatesModel(object): def save_template(self, params):
# Creates the template class with necessary information - t = LibvirtVMTemplate(params, scan=True, conn=self.conn) + if 'cdrom' not in params.keys(): + t = LibvirtVMTemplate(params, conn=self.conn) + else: + t = LibvirtVMTemplate(params, scan=True, conn=self.conn)
# Validate cpu info t.cpuinfo_validate()

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 | 25 ++++++++++++++----------- xmlutils/bootorder.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 xmlutils/bootorder.py diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..17f34e5 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 @@ -146,9 +147,6 @@ class VMTemplate(object): d_info = imageinfo.probe_img_info(d['base']) d['size'] = d_info['virtual-size'] - if len(base_imgs) == 0: - raise MissingParameter("KCHTMPL0016E") - return distro, version def _gen_name(self, distro, version): @@ -170,7 +168,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' @@ -350,12 +348,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 + # Add information of CD-ROM device only if template have info about it. + # Also, set up correct boot order. + 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 + params['boot_order'] = get_bootorder_xml() else: - params['cdroms'] = cdrom_xml + params['boot_order'] = get_bootorder_xml(network=True) # Setting maximum number of slots to avoid errors when hotplug memory # Number of slots are the numbers of chunks of 1GB that fit inside @@ -409,8 +413,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..3f364f0 --- /dev/null +++ b/xmlutils/bootorder.py @@ -0,0 +1,45 @@ +# +# 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(network=False): + """ + <boot dev='hd'/> + <boot dev='cdrom'/> + + - For netboot configuration: + + <boot dev='hd'/> + <boot dev='cdrom'/> + <boot dev='network'/> + """ + boot_order = ['hd', 'cdrom'] + + if network: + boot_order.append('network') + + 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

On 04/15/2016 03:54 PM, pvital@linux.vnet.ibm.com wrote:
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 | 25 ++++++++++++++----------- xmlutils/bootorder.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 xmlutils/bootorder.py
diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..17f34e5 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 @@ -146,9 +147,6 @@ class VMTemplate(object): d_info = imageinfo.probe_img_info(d['base']) d['size'] = d_info['virtual-size']
- if len(base_imgs) == 0: - raise MissingParameter("KCHTMPL0016E") -
Why did you remove the above block?
return distro, version
def _gen_name(self, distro, version): @@ -170,7 +168,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' @@ -350,12 +348,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 + # Add information of CD-ROM device only if template have info about it. + # Also, set up correct boot order. + 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 + params['boot_order'] = get_bootorder_xml() else: - params['cdroms'] = cdrom_xml
+ params['boot_order'] = get_bootorder_xml(network=True)
# Setting maximum number of slots to avoid errors when hotplug memory # Number of slots are the numbers of chunks of 1GB that fit inside @@ -409,8 +413,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..3f364f0 --- /dev/null +++ b/xmlutils/bootorder.py @@ -0,0 +1,45 @@ +# +# 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(network=False): + """ + <boot dev='hd'/> + <boot dev='cdrom'/> + + - For netboot configuration: + + <boot dev='hd'/> + <boot dev='cdrom'/> + <boot dev='network'/> + """ + boot_order = ['hd', 'cdrom'] + + if network: + boot_order.append('network') +
Why not always add 'network' option as default?
+ 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

On Apr 18 01:14PM, Aline Manera wrote:
On 04/15/2016 03:54 PM, pvital@linux.vnet.ibm.com wrote:
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 | 25 ++++++++++++++----------- xmlutils/bootorder.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 xmlutils/bootorder.py
diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..17f34e5 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 @@ -146,9 +147,6 @@ class VMTemplate(object): d_info = imageinfo.probe_img_info(d['base']) d['size'] = d_info['virtual-size']
- if len(base_imgs) == 0: - raise MissingParameter("KCHTMPL0016E") -
Why did you remove the above block?
The method of this block is responsible to get the OS info from the given ISO or image file while creating the VMTemplate instance. Since the idea is create a netboot template, I removed the check and raise to always return distro and version as unknow if no file is provided by user. This is also a backend solution to the Issue #931 (while UI is not reflecting the new API changes).
return distro, version
def _gen_name(self, distro, version): @@ -170,7 +168,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' @@ -350,12 +348,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 + # Add information of CD-ROM device only if template have info about it. + # Also, set up correct boot order. + 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 + params['boot_order'] = get_bootorder_xml() else: - params['cdroms'] = cdrom_xml
+ params['boot_order'] = get_bootorder_xml(network=True)
# Setting maximum number of slots to avoid errors when hotplug memory # Number of slots are the numbers of chunks of 1GB that fit inside @@ -409,8 +413,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..3f364f0 --- /dev/null +++ b/xmlutils/bootorder.py @@ -0,0 +1,45 @@ +# +# 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(network=False): + """ + <boot dev='hd'/> + <boot dev='cdrom'/> + + - For netboot configuration: + + <boot dev='hd'/> + <boot dev='cdrom'/> + <boot dev='network'/> + """ + boot_order = ['hd', 'cdrom'] + + if network: + boot_order.append('network') +
Why not always add 'network' option as default?
That's OK to do, since this will not impact with guest has a disk or cdrom set up. Will remove the new file and change vmtemplate.py
+ 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
-- Paulo Ricardo Paz Vital Linux Technology Center, IBM Systems http://www.ibm.com/linux/ltc/

On 04/18/2016 03:30 PM, Paulo Ricardo Paz Vital wrote:
On Apr 18 01:14PM, Aline Manera wrote:
On 04/15/2016 03:54 PM, pvital@linux.vnet.ibm.com wrote:
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 | 25 ++++++++++++++----------- xmlutils/bootorder.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 xmlutils/bootorder.py
diff --git a/vmtemplate.py b/vmtemplate.py index a223beb..17f34e5 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 @@ -146,9 +147,6 @@ class VMTemplate(object): d_info = imageinfo.probe_img_info(d['base']) d['size'] = d_info['virtual-size'] - if len(base_imgs) == 0: - raise MissingParameter("KCHTMPL0016E") - Why did you remove the above block?
The method of this block is responsible to get the OS info from the given ISO or image file while creating the VMTemplate instance. Since the idea is create a netboot template, I removed the check and raise to always return distro and version as unknow if no file is provided by user.
OK. But you need to make sure the template is for netboot, otherwise we should continue to raise the error. Silence the error may lead on invalid template creation.
This is also a backend solution to the Issue #931 (while UI is not reflecting the new API changes).
The root cause of #931 is not related to this patch or this solution. I have discussed with Ramon the Kimchi is not merging the disks information properly.
return distro, version
def _gen_name(self, distro, version): @@ -170,7 +168,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' @@ -350,12 +348,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 + # Add information of CD-ROM device only if template have info about it. + # Also, set up correct boot order. + 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 + params['boot_order'] = get_bootorder_xml() else: - params['cdroms'] = cdrom_xml + params['boot_order'] = get_bootorder_xml(network=True) # Setting maximum number of slots to avoid errors when hotplug memory # Number of slots are the numbers of chunks of 1GB that fit inside @@ -409,8 +413,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..3f364f0 --- /dev/null +++ b/xmlutils/bootorder.py @@ -0,0 +1,45 @@ +# +# 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(network=False): + """ + <boot dev='hd'/> + <boot dev='cdrom'/> + + - For netboot configuration: + + <boot dev='hd'/> + <boot dev='cdrom'/> + <boot dev='network'/> + """ + boot_order = ['hd', 'cdrom'] + + if network: + boot_order.append('network') +
Why not always add 'network' option as default? That's OK to do, since this will not impact with guest has a disk or cdrom set up.
Will remove the new file and change vmtemplate.py
in future, it would be good to have a boot order setup to allow user changes that when needed. There is already an issue open to cover it. So if you want, I am OK to keep this file, but you can receive a list with the boot order parameters and return the XML. That way, we can reuse it in future. get_bootorder_xml([hd, cdrom, network]) What do you think?
+ 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

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_template.py | 17 +++++++++++++++++ tests/test_vmtemplate.py | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/test_template.py b/tests/test_template.py index 158bbeb..b9bb216 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -80,6 +80,23 @@ 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': '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} req = json.dumps(t) diff --git a/tests/test_vmtemplate.py b/tests/test_vmtemplate.py index 503d34a..92af9e7 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': '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

Reviewed-by: Daniel Barboza <dhbarboza82@gmail.com> On 04/15/2016 03:54 PM, pvital@linux.vnet.ibm.com wrote:
From: Paulo Vital <pvital@linux.vnet.ibm.com>
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": "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 (3): Add support to create netboot templates. Add support to create guests to netboot. Update test cases to support netboot.
API.json | 4 ++-- model/templates.py | 11 ++++++++++- tests/test_template.py | 17 +++++++++++++++++ tests/test_vmtemplate.py | 18 ++++++++++++++++++ vmtemplate.py | 25 ++++++++++++++----------- xmlutils/bootorder.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 xmlutils/bootorder.py
-- 2.5.5
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
participants (4)
-
Aline Manera
-
Daniel Henrique Barboza
-
Paulo Ricardo Paz Vital
-
pvital@linux.vnet.ibm.com