mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
`xenpvnetboot' supports getting boot images from following locations: - http://host/path - https://host/path - ftp://host/path - file:///path - tftp://host/path - nfs:host:/path - /path - /path/file.iso - /path/filesystem.img - /dev/sda1 - nfs+iso:host:/path/file.iso - nfs+iso:host:/path/filesystem.img To use it, make `xenpvnetboot' as bootloader for PV guest:: bootloader = '/usr/bin/xenpvnetboot' To get boot images from various locations, set the right bootloader arguments, e.g.: bootloarder_args = ['--location=http://192.168.0.1/fedora/x86_64'] bootloarder_args = ['--location=ftp://192.168.0.1/fedora/x86_64'] bootloarder_args = ['--location=file:///fedora/x86_64'] bootloarder_args = ['--location=tftp://192.168.0.1/fedora/x86_64'] bootloarder_args = ['--location=/fedora/x86_64'] bootloarder_args = ['--location=/fedora/Fedora-16-x86_64-DVD.iso'] bootloarder_args = ['--location=nfs:192.168.0.1:/fedora/x86_64'] bootloarder_args = ['--location=nfs+iso:192.168.0.1:/fedora/Fedora-16-x86_64-DVD.iso'] You can use `kernel' and `ramdisk' to specify the relative path of boot kernel and ramdisk. `xenpvnetboot' will join them with the location to find the boot kernel and ramdisk, e.g.: kernel = 'images/pxeboot/vmlinuz' ramdisk = 'images/pxeboot/initrd.img' bootloarder_args = ['--location=http://192.168.0.1/fedora/x86_64'] kernel = 'fedora/x86_64/images/pxeboot/vmlinuz' ramdisk = 'fedora/x86_64/images/pxeboot/initrd.img' bootloarder_args = ['--location=http://192.168.0.1/'] You can also omit the `--location' option and specify the full URL for `kernel' and `ramdisk' directly, e.g.: kernel = 'http://192.168.0.1/fedora/x86_64/images/pxeboot/vmlinuz' ramdisk = 'http://192.168.0.1/fedora/x86_64/images/pxeboot/initrd.img' If only `--location' is specified and `kernel' and `ramdisk' are not specified, `xenpvnetboot' will search the following places for boot images from the location:: ('images/xen/vmlinuz', 'images/xen/initrd.img'), # Fedora <= 10 and OL = 5 ('boot/i386/vmlinuz-xen', 'boot/i386/initrd-xen'), # openSUSE >= 10.2 and SLES >= 10 ('boot/x86_64/vmlinuz-xen', 'boot/x86_64/initrd-xen'), # openSUSE >= 10.2 and SLES >= 10 ('current/images/netboot/xen/vmlinuz', 'current/images/netboot/xen/initrd.gz'), # Debian ('images/pxeboot/vmlinuz', 'images/pxeboot/initrd.img'), # Fedora >=10 and OL >= 6 ('isolinux/vmlinuz', 'isolinux/initrd.img'), # Fedora >= 10 and OL >= 6 `xenpvnetboot' requires python module `urlgrabber' http://urlgrabber.baseurl.org/. Signed-off-by: Zhigang Wang <zhigang.x.wang@oracle.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
294 lines
9.6 KiB
Python
Executable File
294 lines
9.6 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Copyright (C) 2010 Oracle. All rights reserved.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
# Foundation, version 2. This program 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 General
|
|
# Public License for more details. You should have received a copy of the GNU
|
|
# General Public License along with this program; if not, write to the Free
|
|
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307,
|
|
# USA.
|
|
|
|
import sys
|
|
import os
|
|
import stat
|
|
import time
|
|
import string
|
|
import random
|
|
import tempfile
|
|
import commands
|
|
import subprocess
|
|
import urlgrabber
|
|
from optparse import OptionParser
|
|
|
|
|
|
XEN_PATHS = [
|
|
('images/xen/vmlinuz', 'images/xen/initrd.img'), # Fedora <= 10 and OL = 5
|
|
('boot/i386/vmlinuz-xen', 'boot/i386/initrd-xen'), # openSUSE >= 10.2 and SLES >= 10
|
|
('boot/x86_64/vmlinuz-xen', 'boot/x86_64/initrd-xen'), # openSUSE >= 10.2 and SLES >= 10
|
|
('current/images/netboot/xen/vmlinuz', 'current/images/netboot/xen/initrd.gz'), # Debian
|
|
('images/pxeboot/vmlinuz', 'images/pxeboot/initrd.img'), # Fedora >=10 and OL >= 6
|
|
('isolinux/vmlinuz', 'isolinux/initrd.img'), # Fedora >= 10 and OL >= 6
|
|
]
|
|
|
|
|
|
def format_sxp(kernel, ramdisk, args):
|
|
s = 'linux (kernel %s)' % kernel
|
|
if ramdisk:
|
|
s += '(ramdisk %s)' % ramdisk
|
|
if args:
|
|
s += '(args "%s")' % args
|
|
return s
|
|
|
|
|
|
def format_simple(kernel, ramdisk, args, sep):
|
|
s = ('kernel %s' % kernel) + sep
|
|
if ramdisk:
|
|
s += ('ramdisk %s' % ramdisk) + sep
|
|
if args:
|
|
s += ('args %s' % args) + sep
|
|
s += sep
|
|
return s
|
|
|
|
|
|
def mount(dev, path, option=''):
|
|
if os.uname()[0] == 'SunOS':
|
|
mountcmd = '/usr/sbin/mount'
|
|
else:
|
|
mountcmd = '/bin/mount'
|
|
cmd = ' '.join([mountcmd, option, dev, path])
|
|
(status, output) = commands.getstatusoutput(cmd)
|
|
if status != 0:
|
|
raise RuntimeError('Command: (%s) failed: (%s) %s' % (cmd, status, output))
|
|
|
|
|
|
def umount(path):
|
|
if os.uname()[0] == 'SunOS':
|
|
cmd = ['/usr/sbin/umount', path]
|
|
else:
|
|
cmd = ['/bin/umount', path]
|
|
subprocess.call(cmd)
|
|
|
|
|
|
class Fetcher:
|
|
def __init__(self, location, tmpdir):
|
|
self.location = location
|
|
self.tmpdir = tmpdir
|
|
self.srcdir = location
|
|
|
|
def prepare(self):
|
|
if not os.path.exists(self.tmpdir):
|
|
os.makedirs(self.tmpdir, 0750)
|
|
|
|
def cleanup(self):
|
|
pass
|
|
|
|
def get_file(self, filename):
|
|
url = os.path.join(self.srcdir, filename)
|
|
suffix = ''.join(random.sample(string.ascii_letters, 6))
|
|
local_name = os.path.join(self.tmpdir, 'xenpvboot.%s.%s' % (os.path.basename(filename), suffix))
|
|
try:
|
|
return urlgrabber.urlgrab(url, local_name, copy_local=1)
|
|
except Exception, err:
|
|
raise RuntimeError('Cannot get file %s: %s' % (url, err))
|
|
|
|
|
|
class MountedFetcher(Fetcher):
|
|
def prepare(self):
|
|
Fetcher.prepare(self)
|
|
self.srcdir = tempfile.mkdtemp(prefix='xenpvboot.', dir=self.tmpdir)
|
|
if self.location.startswith('nfs:'):
|
|
mount(self.location[4:], self.srcdir, '-o ro')
|
|
else:
|
|
if stat.S_ISBLK(os.stat(self.location)[stat.ST_MODE]):
|
|
option = '-o ro'
|
|
else:
|
|
option = '-o ro,loop'
|
|
if os.uname()[0] == 'SunOS':
|
|
option += ' -F hsfs'
|
|
mount(self.location, self.srcdir, option)
|
|
|
|
def cleanup(self):
|
|
umount(self.srcdir)
|
|
try:
|
|
os.rmdir(self.srcdir)
|
|
except:
|
|
pass
|
|
|
|
|
|
class NFSISOFetcher(MountedFetcher):
|
|
def __init__(self, location, tmpdir):
|
|
self.nfsdir = None
|
|
MountedFetcher.__init__(self, location, tmpdir)
|
|
|
|
def prepare(self):
|
|
Fetcher.prepare(self)
|
|
self.nfsdir = tempfile.mkdtemp(prefix='xenpvboot.', dir=self.tmpdir)
|
|
self.srcdir = tempfile.mkdtemp(prefix='xenpvboot.', dir=self.tmpdir)
|
|
nfs = os.path.dirname(self.location[8:])
|
|
iso = os.path.basename(self.location[8:])
|
|
mount(nfs, self.nfsdir, '-o ro')
|
|
option = '-o ro,loop'
|
|
if os.uname()[0] == 'SunOS':
|
|
option += ' -F hsfs'
|
|
mount(os.path.join(self.nfsdir, iso), self.srcdir, option)
|
|
|
|
def cleanup(self):
|
|
MountedFetcher.cleanup(self)
|
|
time.sleep(1)
|
|
umount(self.nfsdir)
|
|
try:
|
|
os.rmdir(self.nfsdir)
|
|
except:
|
|
pass
|
|
|
|
|
|
class TFTPFetcher(Fetcher):
|
|
def get_file(self, filename):
|
|
if '/' in self.location[7:]:
|
|
host = self.location[7:].split('/', 1)[0].replace(':', ' ')
|
|
basedir = self.location[7:].split('/', 1)[1]
|
|
else:
|
|
host = self.location[7:].replace(':', ' ')
|
|
basedir = ''
|
|
suffix = ''.join(random.sample(string.ascii_letters, 6))
|
|
local_name = os.path.join(self.tmpdir, 'xenpvboot.%s.%s' % (os.path.basename(filename), suffix))
|
|
cmd = '/usr/bin/tftp %s -c get %s %s' % (host, os.path.join(basedir, filename), local_name)
|
|
(status, output) = commands.getstatusoutput(cmd)
|
|
if status != 0:
|
|
raise RuntimeError('Command: (%s) failed: (%s) %s' % (cmd, status, output))
|
|
return local_name
|
|
|
|
|
|
def main():
|
|
usage = '''%prog [option]
|
|
|
|
Get boot images from the given location and prepare for Xen to use.
|
|
|
|
Supported locations:
|
|
|
|
- http://host/path
|
|
- https://host/path
|
|
- ftp://host/path
|
|
- file:///path
|
|
- tftp://host/path
|
|
- nfs:host:/path
|
|
- /path
|
|
- /path/file.iso
|
|
- /path/filesystem.img
|
|
- /dev/sda1
|
|
- nfs+iso:host:/path/file.iso
|
|
- nfs+iso:host:/path/filesystem.img'''
|
|
version = '%prog version 0.1'
|
|
parser = OptionParser(usage=usage, version=version)
|
|
parser.add_option('', '--location',
|
|
help='The base url for kernel and ramdisk files.')
|
|
parser.add_option('', '--kernel',
|
|
help='The kernel image file.')
|
|
parser.add_option('', '--ramdisk',
|
|
help='The initial ramdisk file.')
|
|
parser.add_option('', '--args',
|
|
help='Arguments pass to the kernel.')
|
|
parser.add_option('', '--output',
|
|
help='Redirect output to this file instead of stdout.')
|
|
parser.add_option('', '--output-directory', default='/var/run/libxl',
|
|
help='Output directory.')
|
|
parser.add_option('', '--output-format', default='sxp',
|
|
help='Output format: sxp, simple or simple0.')
|
|
parser.add_option('-q', '--quiet', action='store_true',
|
|
help='Be quiet.')
|
|
(opts, args) = parser.parse_args()
|
|
|
|
if not opts.location and not opts.kernel and not opts.ramdisk:
|
|
if not opts.quiet:
|
|
print >> sys.stderr, 'You should at least specify a location or kernel/ramdisk.'
|
|
parser.print_help(sys.stderr)
|
|
sys.exit(1)
|
|
|
|
if not opts.output or opts.output == '-':
|
|
fd = sys.stdout.fileno()
|
|
else:
|
|
fd = os.open(opts.output, os.O_WRONLY)
|
|
|
|
if opts.location:
|
|
location = opts.location
|
|
else:
|
|
location = ''
|
|
if (location == ''
|
|
or location.startswith('http://') or location.startswith('https://')
|
|
or location.startswith('ftp://') or location.startswith('file://')
|
|
or (os.path.exists(location) and os.path.isdir(location))):
|
|
fetcher = Fetcher(location, opts.output_directory)
|
|
elif location.startswith('nfs:') or (os.path.exists(location) and not os.path.isdir(location)):
|
|
fetcher = MountedFetcher(location, opts.output_directory)
|
|
elif location.startswith('nfs+iso:'):
|
|
fetcher = NFSISOFetcher(location, opts.output_directory)
|
|
elif location.startswith('tftp://'):
|
|
fetcher = TFTPFetcher(location, opts.output_directory)
|
|
else:
|
|
if not opts.quiet:
|
|
print >> sys.stderr, 'Unsupported location: %s' % location
|
|
sys.exit(1)
|
|
|
|
try:
|
|
fetcher.prepare()
|
|
except Exception, err:
|
|
if not opts.quiet:
|
|
print >> sys.stderr, str(err)
|
|
fetcher.cleanup()
|
|
sys.exit(1)
|
|
|
|
try:
|
|
kernel = None
|
|
if opts.kernel:
|
|
kernel = fetcher.get_file(opts.kernel)
|
|
else:
|
|
for (kernel_path, _) in XEN_PATHS:
|
|
try:
|
|
kernel = fetcher.get_file(kernel_path)
|
|
except Exception, err:
|
|
if not opts.quiet:
|
|
print >> sys.stderr, str(err)
|
|
continue
|
|
break
|
|
|
|
if not kernel:
|
|
if not opts.quiet:
|
|
print >> sys.stderr, 'Cannot get kernel from loacation: %s' % location
|
|
sys.exit(1)
|
|
|
|
ramdisk = None
|
|
if opts.ramdisk:
|
|
ramdisk = fetcher.get_file(opts.ramdisk)
|
|
else:
|
|
for (_, ramdisk_path) in XEN_PATHS:
|
|
try:
|
|
ramdisk = fetcher.get_file(ramdisk_path)
|
|
except Exception, err:
|
|
if not opts.quiet:
|
|
print >> sys.stderr, str(err)
|
|
continue
|
|
break
|
|
finally:
|
|
fetcher.cleanup()
|
|
|
|
if opts.output_format == 'sxp':
|
|
output = format_sxp(kernel, ramdisk, opts.args)
|
|
elif opts.output_format == 'simple':
|
|
output = format_simple(kernel, ramdisk, opts.args, '\n')
|
|
elif opts.output_format == 'simple0':
|
|
output = format_simple(kernel, ramdisk, opts.args, '\0')
|
|
else:
|
|
print >> sys.stderr, 'Unknown output format: %s' % opts.output_format
|
|
sys.exit(1)
|
|
|
|
sys.stdout.flush()
|
|
os.write(fd, output)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|