Hi, This is a really cool patch.
Given the current work on OS reinstalls, if you recall, disk images can also be a URL, and, as it says in the design doc, Ganeti will be responsible for downloading the images beforehand. Therefore, it might be useful to have a general download infrastructure which can be shared for different images and also across Xen and KVM. Thanks, Jose On Mon, Jan 13, 2014 at 05:51:52AM -0800, [email protected] wrote: > Hello all, > > Here are a couple of patches for ganeti that make it possible to pass a > cdrom_image_path that is an HTTP(s)/FTP(s) url. The original patch was > written by Apollon Oikonomopoulos more than 2 years ago and minor > modifications were made by Christos Stavrakakis in order for the patches to > apply cleanly to 2.7+ versions. There were occasional hiccups when using > this feature with an old kvm version (0.12) but with version 1.1.2+ we > haven't noticed any problems so far. > > We are currently using this functionality on our ganetimgr[1] frontend with > ganeti versions 2.6, 2.7 and 2.9 to give our users the ability to boot > their VMs without an OS and then install a custom ISO of their choice. > > We (at GRNET) have been sitting on this patch for quite a while and we hope > it's time it gets merged upstream. > > Regards, > -- > George Kargiotakis > GRNET NOC > > [1] http://ganetimgr.readthedocs.org/en/wheezy/ > > commit 9fe0df635fb34ad1eb69fbb62bd91061f9154e6a > Author: Christos Stavrakakis <[email protected]> > Date: Tue Oct 29 12:10:54 2013 +0200 > > kvm: check that the ISO image is there if it's a URL > > Perform a simple urllib2 check on ISO images specified as URL before > instance start, so as to work around qemu bug #597575 [1]. > > [1] https://bugs.launchpad.net/qemu/+bug/597575 > > Signed-off-by: Apollon Oikonomopoulos <[email protected]> > Signed-off-by: Christos Stavrakakis <[email protected]> > > Index: ganeti-2.9.2/lib/hypervisor/hv_kvm.py > =================================================================== > --- ganeti-2.9.2.orig/lib/hypervisor/hv_kvm.py 2014-01-09 > 17:27:18.000000000 +0200 > +++ ganeti-2.9.2/lib/hypervisor/hv_kvm.py 2014-01-09 17:27:18.000000000 > +0200 > @@ -34,6 +34,7 @@ > import struct > import fcntl > import shutil > +import urllib2 > import socket > import stat > import StringIO > @@ -164,6 +165,24 @@ > return (ifname, tapfd) > > > +def _CheckUrl(url): > + """Check if a given URL exists on the server > + > + """ > + req = urllib2.Request(url) > + > + # XXX: ugly but true > + req.get_method = lambda: "HEAD" > + > + try: > + resp = urllib2.urlopen(req) > + except urllib2.URLError: > + return False > + > + del resp > + return True > + > + > class QmpMessage: > """QEMU Messaging Protocol (QMP) message. > > @@ -1161,7 +1180,13 @@ > iso_image = hvp[constants.HV_CDROM_IMAGE_PATH] > if iso_image: > options = ",media=cdrom" > - if not re.match(r'(https?|ftps?)://', iso_image): > + if re.match(r'(https?|ftps?)://', iso_image): > + # Check that the iso image is really there > + # See https://bugs.launchpad.net/qemu/+bug/597575 > + if not _CheckUrl(iso_image): > + raise errors.HypervisorError("ISO image %s is not accessible" % > + iso_image) > + else: > options = "%s,format=raw" % options > # set cdrom 'if' type > if boot_cdrom: > commit abfdf963d6727fd031d97864956511a30087dd11 > Author: Christos Stavrakakis <[email protected]> > Date: Tue Oct 29 12:09:33 2013 +0200 > > Allow KVM to boot from HTTP > > New versions of KVM support booting from HTTP-hosted ISO images, via > libcurl. This patch adds a proper check to allow defining either a sane, > absolute path or an HTTP URL as an iso image path. > > Remove "format=raw" from the cdrom device options when iso_image starts > with "(https?|ftps?)://", to allow latest KVM versions (qemu-kvm) to boot > from HTTP-hosted iso images. Added FILE_OR_URL check to allow booting > from HTTP (kvm). > > Signed-off-by: Apollon Oikonomopoulos <[email protected]> > Signed-off-by: Christos Stavrakakis <[email protected]> > > diff --git a/lib/hypervisor/hv_base.py b/lib/hypervisor/hv_base.py > index c723a4d..a6e0b46 100644 > --- a/lib/hypervisor/hv_base.py > +++ b/lib/hypervisor/hv_base.py > @@ -83,6 +83,13 @@ def _IsMultiCpuMaskWellFormed(cpu_mask): > _FILE_CHECK = (utils.IsNormAbsPath, "must be an absolute normalized path", > os.path.isfile, "not found or not a file") > > +# must be a file or a URL > +_FILE_OR_URL_CHECK = (utils.IsNormAbsPathOrURL, > + "must be an absolute normalized path or a URL", > + lambda x: os.path.isfile(x) or > + re.match(r'(https?|ftps?)://', x), > + "not found or not a file or URL") > + > # must be a directory > _DIR_CHECK = (utils.IsNormAbsPath, "must be an absolute normalized path", > os.path.isdir, "not found or not a directory") > @@ -108,6 +115,8 @@ _NONNEGATIVE_INT_CHECK = (lambda x: x >= 0, "cannot be > negative", None, None) > # nice wrappers for users > REQ_FILE_CHECK = (True, ) + _FILE_CHECK > OPT_FILE_CHECK = (False, ) + _FILE_CHECK > +REQ_FILE_OR_URL_CHECK = (True, ) + _FILE_OR_URL_CHECK > +OPT_FILE_OR_URL_CHECK = (False, ) + _FILE_OR_URL_CHECK > REQ_DIR_CHECK = (True, ) + _DIR_CHECK > OPT_DIR_CHECK = (False, ) + _DIR_CHECK > REQ_NET_PORT_CHECK = (True, ) + _NET_PORT_CHECK > diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py > index 54bd557..01a3c52 100644 > --- a/lib/hypervisor/hv_kvm.py > +++ b/lib/hypervisor/hv_kvm.py > @@ -477,7 +477,7 @@ class KVMHypervisor(hv_base.BaseHypervisor): > constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK, > constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK, > constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK, > - constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK, > + constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK, > constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK, > constants.HV_BOOT_ORDER: > hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES), > @@ -1130,7 +1130,9 @@ class KVMHypervisor(hv_base.BaseHypervisor): > > iso_image = hvp[constants.HV_CDROM_IMAGE_PATH] > if iso_image: > - options = ",format=raw,media=cdrom" > + options = ",media=cdrom" > + if not re.match(r'(https?|ftps?)://', iso_image): > + options = "%s,format=raw" % options > # set cdrom 'if' type > if boot_cdrom: > actual_cdrom_type = constants.HT_DISK_IDE > diff --git a/lib/utils/io.py b/lib/utils/io.py > index f9675a8..47c7749 100644 > --- a/lib/utils/io.py > +++ b/lib/utils/io.py > @@ -23,6 +23,7 @@ > """ > > import os > +import re > import logging > import shutil > import tempfile > @@ -667,6 +668,13 @@ def IsBelowDir(root, other_path): > return os.path.commonprefix([prepared_root, norm_other]) == prepared_root > > > +def IsNormAbsPathOrURL(path): > + """Check whether a path is absolute and normalized, or an HTTP URL. > + > + """ > + return IsNormAbsPath(path) or re.match(r'(https?|ftps?)://', path) > + > + > def PathJoin(*args): > """Safe-join a list of path components. > -- Jose Antonio Lopes Ganeti Engineering Google Germany GmbH Dienerstr. 12, 80331, München Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Geschäftsführer: Graham Law, Christine Elizabeth Flores Steuernummer: 48/725/00206 Umsatzsteueridentifikationsnummer: DE813741370
