vm-builder-0.12.4+bzr494/AUTHORS0000644000000000000000000000206111372226766014107 0ustar 00000000000000Main author and original conceptor: Soren Hansen These people have also helped make VMBuilder what it is today: * Andreas Heck * Andreas Rütten * Bart Trojanowski * Bitti * Bryan McLellan * Charles Hooper * Chuck Short * Colin Watson * Duncan McGreggor * Eric Hammond * Iain Lowe * Jamie Strandboge * Kees Cook * Kevin McDermott * Loïc Minier * Marcelo Boveto Shima * Markus Korn * Mathias Gug * Michael Vogt * Mike Frisch * Neal McBurnett * Nick Barcet * Scott Moser * Simon Andreas Frimann Lund * Tim Bielawa * Todd Deshane vm-builder-0.12.4+bzr494/MANIFEST.in0000644000000000000000000000024711341325367014572 0ustar 00000000000000include VMBuilder/plugins/*/templates/*.tmpl include AUTHORS include NEWS include examples/* include ubuntu-vm-builder include ubuntu-vm-builder.1 include vmbuilder.1 vm-builder-0.12.4+bzr494/Makefile0000755000000000000000000000055011252764110014466 0ustar 00000000000000#!/usr/bin/make -f test: clean stamp @nosetests --verbose stamp: @touch $@ build: @python setup.py bdist_egg sdist coverage: @nosetests --quiet --with-coverage --cover-package VMBuilder report: @nosetests --quiet --with-coverage --cover-package VMBuilder --cover-html --cover-html-dir coverage-report clean: @rm -rf stamp .coverage coverage-report vm-builder-0.12.4+bzr494/NEWS0000644000000000000000000000467111374476520013544 0ustar 000000000000000.12.4: * Revive firstscripts plugins. This fixes the --firstboot and --firstlogin options, both of which went missing with 0.12. * Make Plugin.install_file work in non-context plugins (plugins that are not Distros or Hypervisors). * Do a slightly better job at cleaning up after ourselves by removing the distro chroot by default and removing the temporary root mount point. * Revive QEMu hypervisor. 0.12.3: * Reworked the way timezones and locales are handled. This fixes an actual problem with /etc/localtime not being set correctly, and fixes a theoretical problem with people not running VMBuilder on Ubuntu. * Resurrect -o (--overwrite) which went missing with 0.12.0. * Resurrect Xen support which went missing with 0.12.0. 0.12.2: * Moved test directory under VMBuilder/ and include it in the tarball. * Revive ubuntu-vm-builder (which rotted during the 0.11 -> 0.12 transition) * Skip tests that need root, if not run as root. * Fix installing onto logical volumes. * Fix --raw handling. * Refresh documenation in disk.py * Improve handling of non-string settings from command line and config files. * A big bunch of cleanups, most thanks to pyflakes. 0.12.1: * Added NEWS file * IntegerSetting.set_value now attempts to convert the given value to an int instead of rejecting it outright. * Bypass blkid cache. * Move initctl out of the way during package installs in Ubuntu plugin. * Update VMWare driver to 0.12 API * Support separate /boot partitions. * Update --part handling to 0.12 API. * Make sure the given MAC is used in the libvirt domain template. * Update libvirt plugin to 0.12 API. * Check for hvm capabilities during preflight check. * Add option to specify a seedfile which will be fed into the debconf database. This enables installing packages like sun-java6-jre which requires the user to accept an EULA. * Correctly handle config keys with dashes in them. * Update postinst plugin to 0.12 API. * If trying to install a file to a nonexisting directory, the directory will be created first. * Refresh the valid_flavours for jaunty, karmic, and Lucid. * Remove lpia from Lucid. * Rewrite $LANG (s/utf8$/UTF-8/) so that locale-gen is happy again. * Bail out early if destdir already exists. * Re-add the option to specify a custom template directory. * Re-add the option to specify a config file. * Default to ext3 for Dapper through Jaunty * Support non-dhcp network configurations. vm-builder-0.12.4+bzr494/VMBuilder/0000755000000000000000000000000011031160536014651 5ustar 00000000000000vm-builder-0.12.4+bzr494/examples/0000755000000000000000000000000011106345705014644 5ustar 00000000000000vm-builder-0.12.4+bzr494/setup.py0000755000000000000000000000171312115223353014540 0ustar 00000000000000#!/usr/bin/env python from distutils.core import setup import VMBuilder.plugins from glob import glob import os.path import subprocess if os.path.exists('.bzr'): try: o = subprocess.Popen(('bzr','version-info', '--python'), stdout=subprocess.PIPE).stdout f = open('VMBuilder/vcsversion.py', 'w') f.write(o.read()) f.close() o.close() except Exception, e: print repr(e) setup(name='VMBuilder', version='0.12.4', description='Uncomplicated VM Builder', author='Soren Hansen', author_email='soren@ubuntu.com', url='http://launchpad.net/vmbuilder/', packages=['VMBuilder', 'VMBuilder.tests', 'VMBuilder.plugins', 'VMBuilder.contrib'] + VMBuilder.plugins.find_plugins(), data_files=[('/etc/vmbuilder/%s' % (pkg,), glob('VMBuilder/plugins/%s/templates/*' % (pkg,))) for pkg in [p.split('.')[-1] for p in VMBuilder.plugins.find_plugins()]], scripts=['vmbuilder'], ) vm-builder-0.12.4+bzr494/ubuntu-vm-builder0000755000000000000000000000144711337605667016364 0ustar 00000000000000#!/usr/bin/python # # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder.contrib.cli import UVB uvb = UVB() uvb.main() vm-builder-0.12.4+bzr494/ubuntu-vm-builder.10000644000000000000000000000063411103136556016500 0ustar 00000000000000.TH UBUNTU-VM-BUILDER 1 "Oct 2008" .SH NAME ubuntu-vm-builder \- builds virtual machines from the command line .SH DESCRIPTION ubuntu-vm-builder is now a wrapper to vmbuilder (part of the python-vm-builder package) and is only maintained for compatibility wih previous scripts. Please see the vmbuilder man page for more information or run .B vmbuilder --help for a full list of options. vm-builder-0.12.4+bzr494/vmbuilder0000755000000000000000000000144711337605667014767 0ustar 00000000000000#!/usr/bin/python # # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder.contrib.cli import CLI cli = CLI() cli.main() vm-builder-0.12.4+bzr494/vmbuilder.10000644000000000000000000001453411534170721015107 0ustar 00000000000000.TH VMBUILDER 1 "Oct 2008" .SH NAME vmbuilder \- builds virtual machines from the command line .SH SYNOPSIS .B vmbuilder [\fIOPTIONS\fR]... .TP Hypervisor image format. Valid options: xen kvm vmw6 vmserver .TP Distribution. Valid options: ubuntu .SH DESCRIPTION This manual page documents the .B vmbuilder command. .B vmbuilder is a program that builds virtual machines from the command line, but can have other interfaces implemented through its plugin mechanism. You can pass command line options to add extra packages, remove packages, choose which version of Ubuntu, which mirror etc. On recent hardware with plenty of RAM, tmpdir in /dev/shm or using a tmpfs, and a local mirror (see apt-proxy or apt-mirror), you can bootstrap a vm in less than a minute. .SH OPTIONS .TP .B NOTE: Only common basic options are described here. Many options can be added through plugins and others, they depends on the hypervisor and distro you specify. Please use .B vmbuilder --help for a full options list. .TP .B \-h, \-\-help Show this help message and exit. .TP .B \-c ALTCONFIG \-\-config Specify the path to an optional configuration file. [default:None]. /etc/vmbuilder.cfg and ~/.vmbuilder.cfg are always read if present. The content of the configuration file is explained at https://help.ubuntu.com/community/JeOSVMBuilder#Using%20configuration%20files. .TP .B \-d DEST, \-\-dest DEST Specify the destination directory. [default:-]. Config option: destdir. .TP .B \-\-debug Show (a lot of) debug information .TP .B \-v, \-\-verbose Show progress information .TP .B \-q, \-\-quiet Silent operation .TP .B \-t TMP, \-\-tmp TMP Use TMP as temporary working space for image generation. Defaults to $TMPDIR if it is defined or /tmp otherwise. [default: /tmp] .TP .B \-\-templates DIR Prepends dir to template search path. See https://help.ubuntu.com/community/JeOSVMBuilder#Modifying%20the%20libvirt%20template%20to%20use%20bridging for an example. .TP .B \-o, \-\-overwrite Force overwrite of destination directory if it already exist. [default: False] .TP .B \-\-in-place Install directly into the filesystem images. This is needed if your $TMPDIR is nodev and/or nosuid, but will result in slightly larger file system images. .TP .B \-\-tmpfs OPTS Use a tmpfs as the working directory, specifying its size or "-" to use tmpfs default (suid,dev,size=1G). .TP .B \-m MEM, \-\-mem MEM Assign MEM megabytes of memory to the guest vm. [default: 128] .TP .B \-\-cpus NUM Assign NUM cpus to the guest vm. [default: 1] .SS Guest partitioning options .TP .B \-\-part PATH Allows to specify a partition table in PATH each line of partfile should specify (root first): .RS .RS mountpoint size (device) (filename) .RE one per line, separated by space, where size is in megabytes. The third and fourth options allow you to specify a device for the filesystem, and a name for the filesystem image, both of which are optional. You can have up to 4 virtual disks, a new disk starts on a line containing only '---'. ie: .RS root 2000 a1 rootfs /boot 512 a2 boot swap 1000 a3 swapfs --- /var 8000 b1 var /var/log 2000 b2 varlog .RE .RE .TP The following three options are not used if --part is specified: .RS .TP .B \-\-rootsize SIZE Size (in MB) of the root filesystem [default: 4096]. Discarded when --part is used. .TP .B \-\-optsize SIZE Size (in MB) of the /opt filesystem. If not set, no /opt filesystem will be added. Discarded when --part is used. .TP .B \-\-swapsize SIZE Size (in MB) of the swap partition [default: 1024]. Discarded when --part is used. .RS .SS Network related options: .TP .B \-\-domain DOMAIN Set DOMAIN as the domain name of the guest. Default: The domain of the machine running this script. .TP .B \-\-ip ADDRESS IP address in dotted form [default: dhcp] .TP Options below are discarded if \-\-ip is not specified .RS .B \-\-mask VALUE IP mask in dotted form [default: based on ip setting]. .TP .B \-\-net ADDRESS IP net address in dotted form [default: based on ip setting]. .TP .B \-\-bcast VALUE IP broadcast in dotted form [default: based on ip setting]. .TP .B \-\-gw ADDRESS Gateway (router) address in dotted form [default: based on ip setting (first valid address in the network)]. .TP .B \-\-dns ADDRESS DNS address in dotted form [default: based on ip setting (first valid address in the network)] .RE .SS Post install actions: .TP .B \-\-copy FILE Read 'source dest' lines from FILE, copying source files from host to dest in the guest's file system. .TP .B \-\-execscript SCRIPT, \-\-exec SCRIPT Run SCRIPT after distro installation finishes. Script will be called with the guest's chroot as first argument, so you can use .B chroot $1 to run code in the virtual machine. .SS libvirt integration: .TP .B \-\-libvirt=URI Add VM to given URI .SS Scripts: .TP .B \-\-firstboot PATH Specify a script that will be copied into the guest and executed the first time the machine boots. This script must not be interactive. .TP .B \-\-firstlogin PATH Specify a script that will be copied into the guest and will be executed the first time the user logs in. This script can be interactive. .SH DEVELOPMENT .B vmbuilder is a python program that offers a very simple mechanism to increase functionalities, interfaces, support other distribution and hypervisors. Feel free to join the project at https://launchpad.net/vmbuilder .SH COMPATIBILTY .B vmbuilder includes a command line interface compatibility with its ancestor .B ubuntu-vm-builder. This compatibility does not include template or configration files which now use a newer format. Programs or script that were relying on ubuntu-vm-builder should continue working without any issues if the do not use templates or configuration files. .SH SUPPORT Feel free to join #ubuntu-virt on freenode to get some help or just say hello. .SH SEE ALSO apt-proxy(8), apt-mirror(8) .TP The vmbuilder tutorial available at https://help.ubuntu.com/community/JeOSVMBuilder .TP The CheetahTemplate documentation for syntax of the template files at http://www.cheetahtemplate.org/docs/users_guide_html/ .SH AUTHOR vmbuilder is Copyright (C) 2007-2008 Canonical Ltd. and written by Soren Hansen with the help of others, see /usr/share/doc/python-vm-builder/AUTHORS for more details. vm-builder-0.12.4+bzr494/VMBuilder/__init__.py0000644000000000000000000001014711374476520017002 0ustar 00000000000000#!/usr/bin/python # # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # The publically exposed bits of VMBuilder # import logging import VMBuilder.log import VMBuilder.plugins from VMBuilder.distro import Distro from VMBuilder.hypervisor import Hypervisor from VMBuilder.plugins import Plugin from VMBuilder.exception import VMBuilderException, VMBuilderUserError # Internal bookkeeping distros = {} hypervisors = {} _distro_plugins = [] _hypervisor_plugins = [] # This is meant to be populated by plugins. It should contain a list of the files that we give back to the user. def register_hypervisor(cls): """ Register a hypervisor class with VMBuilder @type cls: Hypervisor @param cls: The new Hypervisor subclass to be registered with VMBuilder """ hypervisors[cls.arg] = cls def get_hypervisor(name): """ Get Hypervisor subclass by name @type name: string @param name: Name of the Hypervisor subclass (defined by its .arg attribute) """ if name in hypervisors: return hypervisors[name] else: raise VMBuilderUserError('No such hypervisor. Available hypervisors: %s' % (' '.join(hypervisors.keys()))) def register_distro(cls): """ Register a distro class with VMBuilder @type cls: Distro @param cls: The new Distro subclass to be registered with VMBuilder """ distros[cls.arg] = cls def get_distro(name): """ Get Distro subclass by name @type name: string @param name: Name of the Distro subclass (defined by its .arg attribute) """ if name in distros: return distros[name] else: raise VMBuilderUserError('No such distro. Available distros: %s' % (' '.join(distros.keys()))) def register_distro_plugin(cls): """ Register a distro plugin with VMBuilder B{Note}: A "distro plugin" is not a plugin that implements a new Distro. It's a plugin that pertains to Distro's. If you want to register a new Distro, use register_distro. @type cls: Plugin @param cls: The Plugin class to registered as a distro plugin """ _distro_plugins.append(cls) _distro_plugins.sort(key=lambda x: x.priority) def register_hypervisor_plugin(cls): """ Register a hypervisor plugin with VMBuilder B{Note}: A "hypervisor plugin" is not a plugin that implements a new Hypervisor. It's a plugin that pertains to Hypervisor's. If you want to register a new Hypervisor, use register_hypervisor. @type cls: Plugin @param cls: The Plugin class to registered as a hypervisor plugin """ _hypervisor_plugins.append(cls) _hypervisor_plugins.sort(key=lambda x: x.priority) def set_console_loglevel(level): """ Adjust the loglevel that will be sent to the console. @type level: number @param level: See the standard logging module """ VMBuilder.log.console.setLevel(level) def get_version_info(): """ Return a dict containing version information for VMBuilder. @return: A dict with (at least) the following keys: - major: Major version number. - minor: Minor version number. - micro: Micro version number. - revno: The revision number of the current branch or the branch from which the tarball was created. """ import vcsversion info = vcsversion.version_info info['major'] = 0 info['minor'] = 12 info['micro'] = 4 return info logging.debug('Loading plugins') VMBuilder.plugins.load_plugins() vm-builder-0.12.4+bzr494/VMBuilder/contrib/0000755000000000000000000000000011337605667016333 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/disk.py0000644000000000000000000005004512614535475016201 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Virtual disk management import fcntl import logging import os import os.path import re import stat import string import time from VMBuilder.util import run_cmd from VMBuilder.exception import VMBuilderUserError, VMBuilderException from struct import unpack TYPE_EXT2 = 0 TYPE_EXT3 = 1 TYPE_XFS = 2 TYPE_SWAP = 3 TYPE_EXT4 = 4 class Disk(object): """ Virtual disk. @type vm: Hypervisor @param vm: The Hypervisor to which the disk belongs @type filename: string @param filename: filename of the disk image @type size: string or number @param size: The size of the disk image to create (passed to L{parse_size}). If specified and filename already exists, L{VMBuilderUserError} will be raised. Otherwise, a disk image of this size will be created once L{create}() is called. """ def __init__(self, vm, filename, size=None): self.vm = vm "The hypervisor to which the disk belongs." self.filename = filename "The filename of the disk image." self.partitions = [] "The list of partitions on the disk. Is kept in order by L{add_part}." self.preallocated = False "Whether the file existed already (True if it did, False if we had to create it)." self.size = 0 "The size of the disk. For preallocated disks, this is detected." if not os.path.exists(self.filename): if not size: raise VMBuilderUserError('%s does not exist, but no size was given.' % (self.filename)) self.size = parse_size(size) else: if size: raise VMBuilderUserError('%s exists, but size was given.' % (self.filename)) self.preallocated = True self.size = detect_size(self.filename) self.format_type = None "The format type of the disks. Only used for converted disks." def devletters(self): """ @rtype: string @return: the series of letters that ought to correspond to the device inside the VM. E.g. the first disk of a VM would return 'a', while the 702nd would return 'zz' """ return index_to_devname(self.vm.disks.index(self)) def create(self): """ Creates the disk image (if it doesn't already exist). Once this method returns succesfully, L{filename} can be expected to points to point to whatever holds the virtual disk (be it a file, partition, logical volume, etc.). """ if not os.path.exists(self.filename): logging.info('Creating disk image: "%s" of size: %dMB' % (self.filename, self.size)) run_cmd(qemu_img_path(), 'create', '-f', 'raw', self.filename, '%dM' % self.size) def partition(self): """ Partitions the disk image. First adds a partition table and then adds the individual partitions. Should only be called once and only after you've added all partitions. """ logging.info('Adding partition table to disk image: %s' % self.filename) run_cmd('parted', '--script', self.filename, 'mklabel', 'msdos') # Partition the disk for part in self.partitions: part.create(self) def map_partitions(self): """ Create loop devices corresponding to the partitions. Once this has returned succesfully, each partition's map device is set as its L{filename} attribute. Call this after L{partition}. """ logging.info('Creating loop devices corresponding to the created partitions') self.vm.add_clean_cb(lambda : self.unmap(ignore_fail=True)) kpartx_output = run_cmd('kpartx', '-asv', self.filename) parts = [] for line in kpartx_output.split('\n'): if line == "" or line.startswith("gpt:") or line.startswith("dos:"): continue if line.startswith("add"): parts.append(line) continue logging.error('Skipping unknown line in kpartx output (%s)' % line) mapdevs = [] for line in parts: mapdevs.append(line.split(' ')[2]) for (part, mapdev) in zip(self.partitions, mapdevs): part.set_filename('/dev/mapper/%s' % mapdev) def mkfs(self): """ Creates the partitions' filesystems """ logging.info("Creating file systems") for part in self.partitions: part.mkfs() def get_grub_id(self): """ @rtype: string @return: name of the disk as known by grub """ return '(hd%d)' % self.get_index() def get_index(self): """ @rtype: number @return: index of the disk (starting from 0 for the hypervisor's first disk) """ return self.vm.disks.index(self) def unmap(self, ignore_fail=False): """ Destroy all mapping devices Unsets L{Partition}s' and L{Filesystem}s' filename attribute """ # first sleep to give the loopback devices a chance to settle down time.sleep(3) tries = 0 max_tries = 3 while tries < max_tries: try: run_cmd('kpartx', '-d', self.filename, ignore_fail=False) break except: pass tries += 1 time.sleep(3) if tries >= max_tries: # try it one last time logging.info("Could not unmap '%s' after '%d' attempts. Final attempt" % (self.filename, tries)) run_cmd('kpartx', '-d', self.filename, ignore_fail=ignore_fail) for part in self.partitions: logging.debug("Removing partition %s" % part.filename) parted_oldmap=part.filename[len("/dev/mapper/"):-1]+"p"+part.filename[-1] dmsetup_output = run_cmd('dmsetup', 'info', parted_oldmap, ignore_fail=True) for line in dmsetup_output.split('\n'): if line.startswith("State:") and line.endswith("ACTIVE"): logging.debug("Removing parted old map with 'dmsetup remove %s'" % parted_oldmap) dmsetup_output=run_cmd('dmsetup', 'remove', parted_oldmap, ignore_fail=ignore_fail) part.set_filename(None) def add_part(self, begin, length, type, mntpnt): """ Add a partition to the disk @type begin: number @param begin: Start offset of the new partition (in megabytes) @type length: @param length: Size of the new partition (in megabytes) @type type: string @param type: Type of the new partition. Valid options are: ext2 ext3 xfs swap linux-swap @type mntpnt: string @param mntpnt: Intended mountpoint inside the guest of the new partition """ length = parse_size(length) end = begin+length-1 logging.debug("add_part - begin %d, length %d, end %d, type %s, mntpnt %s" % (begin, length, end, type, mntpnt)) for part in self.partitions: if (begin >= part.begin and begin <= part.end) or \ (end >= part.begin and end <= part.end): raise VMBuilderUserError('Partitions are overlapping') if begin < 0 or end > self.size: raise VMBuilderUserError('Partition is out of bounds. start=%d, end=%d, disksize=%d' % (begin,end,self.size)) part = self.Partition(disk=self, begin=begin, end=end, type=str_to_type(type), mntpnt=mntpnt) self.partitions.append(part) # We always keep the partitions in order, so that the output from kpartx matches our understanding self.partitions.sort(cmp=lambda x,y: x.begin - y.begin) def convert(self, destdir, format): """ Convert the disk image @type destdir: string @param destdir: Target location of converted disk image @type format: string @param format: The target format (as understood by qemu-img or vdi) @rtype: string @return: the name of the converted image """ if self.preallocated: # We don't convert preallocated disk images. That would be silly. return self.filename filename = os.path.basename(self.filename) if '.' in filename: filename = filename[:filename.rindex('.')] destfile = '%s/%s.%s' % (destdir, filename, format) logging.info('Converting %s to %s, format %s' % (self.filename, format, destfile)) if format == 'vdi': run_cmd(vbox_manager_path(), 'convertfromraw', '-format', 'VDI', self.filename, destfile) else: run_cmd(qemu_img_path(), 'convert', '-O', format, self.filename, destfile) os.unlink(self.filename) self.filename = os.path.abspath(destfile) self.format_type = format return destfile class Partition(object): def __init__(self, disk, begin, end, type, mntpnt): self.disk = disk "The disk on which this Partition resides." self.begin = begin "The start of the partition" self.end = end "The end of the partition" self.type = type "The partition type" self.mntpnt = mntpnt "The destined mount point" self.filename = None "The filename of this partition (the map device)" self.fs = Filesystem(vm=self.disk.vm, type=self.type, mntpnt=self.mntpnt) "The enclosed filesystem" def set_filename(self, filename): self.filename = filename self.fs.filename = filename def parted_fstype(self): """ @rtype: string @return: the filesystem type of the partition suitable for passing to parted """ return { TYPE_EXT2: 'ext2', TYPE_EXT3: 'ext2', TYPE_EXT4: 'ext2', TYPE_XFS: 'ext2', TYPE_SWAP: 'linux-swap(new)' }[self.type] def create(self, disk): """Adds partition to the disk image (does not mkfs or anything like that)""" logging.info('Adding type %d partition to disk image: %s' % (self.type, disk.filename)) if self.begin == 0: logging.info('Partition at beginning of disk - reserving first cylinder') partition_start = "63s" else: partition_start = self.begin run_cmd('parted', '--script', '--', disk.filename, 'mkpart', 'primary', self.parted_fstype(), partition_start, self.end) def mkfs(self): """Adds Filesystem object""" self.fs.mkfs() def get_grub_id(self): """The name of the partition as known by grub""" return '(hd%d,%d)' % (self.disk.get_index(), self.get_index()) def get_suffix(self): """Returns 'a4' for a device that would be called /dev/sda4 in the guest. This allows other parts of VMBuilder to set the prefix to something suitable.""" return '%s%d' % (self.disk.devletters(), self.get_index() + 1) def get_index(self): """Index of the disk (starting from 0)""" return self.disk.partitions.index(self) def set_type(self, type): try: if int(type) == type: self.type = type else: self.type = str_to_type(type) except ValueError: self.type = str_to_type(type) class Filesystem(object): def __init__(self, vm=None, size=0, type=None, mntpnt=None, filename=None, devletter='a', device='', dummy=False): self.vm = vm self.filename = filename self.size = parse_size(size) self.devletter = devletter self.device = device self.dummy = dummy self.set_type(type) self.mntpnt = mntpnt self.preallocated = False "Whether the file existed already (True if it did, False if we had to create it)." def create(self): logging.info('Creating filesystem: %s, size: %d, dummy: %s' % (self.mntpnt, self.size, repr(self.dummy))) if not os.path.exists(self.filename): logging.info('Not preallocated, so we create it.') if not self.filename: if self.mntpnt: self.filename = re.sub('[^\w\s/]', '', self.mntpnt).strip().lower() self.filename = re.sub('[\w/]', '_', self.filename) if self.filename == '_': self.filename = 'root' elif self.type == TYPE_SWAP: self.filename = 'swap' else: raise VMBuilderException('mntpnt not set') self.filename = '%s/%s' % (self.vm.workdir, self.filename) while os.path.exists('%s.img' % self.filename): self.filename += '_' self.filename += '.img' logging.info('A name wasn\'t specified either, so we make one up: %s' % self.filename) run_cmd(qemu_img_path(), 'create', '-f', 'raw', self.filename, '%dM' % self.size) self.mkfs() def mkfs(self): if not self.filename: raise VMBuilderException('We can\'t mkfs if filename is not set. Did you forget to call .create()?') if not self.dummy: cmd = self.mkfs_fstype() + [self.filename] run_cmd(*cmd) # Let udev have a chance to extract the UUID for us run_cmd('udevadm', 'settle') if os.path.exists("/sbin/vol_id"): self.uuid = run_cmd('vol_id', '--uuid', self.filename).rstrip() elif os.path.exists("/sbin/blkid"): self.uuid = run_cmd('blkid', '-c', '/dev/null', '-sUUID', '-ovalue', self.filename).rstrip() def mkfs_fstype(self): map = { TYPE_EXT2: ['mkfs.ext2', '-F'], TYPE_EXT3: ['mkfs.ext3', '-F'], TYPE_EXT4: ['mkfs.ext4', '-F'], TYPE_XFS: ['mkfs.xfs'], TYPE_SWAP: ['mkswap'] } if not self.vm.distro.has_256_bit_inode_ext3_support(): map[TYPE_EXT3] = ['mkfs.ext3', '-I 128', '-F'] return map[self.type] def fstab_fstype(self): return { TYPE_EXT2: 'ext2', TYPE_EXT3: 'ext3', TYPE_EXT4: 'ext4', TYPE_XFS: 'xfs', TYPE_SWAP: 'swap' }[self.type] def fstab_options(self): return 'defaults' def mount(self, rootmnt): if (self.type != TYPE_SWAP) and not self.dummy: logging.debug('Mounting %s', self.mntpnt) self.mntpath = '%s%s' % (rootmnt, self.mntpnt) if not os.path.exists(self.mntpath): os.makedirs(self.mntpath) run_cmd('mount', '-o', 'loop', self.filename, self.mntpath) self.vm.add_clean_cb(self.umount) def umount(self): self.vm.cancel_cleanup(self.umount) if (self.type != TYPE_SWAP) and not self.dummy: logging.debug('Unmounting %s', self.mntpath) run_cmd('umount', self.mntpath) def get_suffix(self): """Returns 'a4' for a device that would be called /dev/sda4 in the guest.. This allows other parts of VMBuilder to set the prefix to something suitable.""" if self.device: return self.device else: return '%s%d' % (self.devletters(), self.get_index() + 1) def devletters(self): """ @rtype: string @return: the series of letters that ought to correspond to the device inside the VM. E.g. the first filesystem of a VM would return 'a', while the 702nd would return 'zz' """ return self.devletter def get_index(self): """Index of the disk (starting from 0)""" return self.vm.filesystems.index(self) def set_type(self, type): try: if int(type) == type: self.type = type else: self.type = str_to_type(type) except ValueError: self.type = str_to_type(type) def parse_size(size_str): """Takes a size like qemu-img would accept it and returns the size in MB""" try: return int(size_str) except ValueError: pass try: num = int(size_str[:-1]) except ValueError: raise VMBuilderUserError("Invalid size: %s" % size_str) if size_str[-1:] == 'g' or size_str[-1:] == 'G': return num * 1024 if size_str[-1:] == 'm' or size_str[-1:] == 'M': return num if size_str[-1:] == 'k' or size_str[-1:] == 'K': return num / 1024 str_to_type_map = { 'ext2': TYPE_EXT2, 'ext3': TYPE_EXT3, 'ext4': TYPE_EXT4, 'xfs': TYPE_XFS, 'swap': TYPE_SWAP, 'linux-swap': TYPE_SWAP } def str_to_type(type): try: return str_to_type_map[type] except KeyError: raise Exception('Unknown partition type: %s' % type) def rootpart(disks): """Returns the partition which contains the root dir""" return path_to_partition(disks, '/') def bootpart(disks): """Returns the partition which contains /boot""" return path_to_partition(disks, '/boot/foo') def path_to_partition(disks, path): parts = get_ordered_partitions(disks) parts.reverse() for part in parts: if path.startswith(part.mntpnt): return part raise VMBuilderException("Couldn't find partition path %s belongs to" % path) def create_filesystems(vm): for filesystem in vm.filesystems: filesystem.create() def create_partitions(vm): for disk in vm.disks: disk.create(vm.workdir) def get_ordered_filesystems(vm): """Returns filesystems (self hosted as well as contained in partitions in an order suitable for mounting them""" fss = list(vm.filesystems) for disk in vm.disks: fss += [part.fs for part in disk.partitions] fss.sort(lambda x,y: len(x.mntpnt or '')-len(y.mntpnt or '')) return fss def get_ordered_partitions(disks): """Returns partitions from disks in an order suitable for mounting them""" parts = [] for disk in disks: parts += disk.partitions parts.sort(lambda x,y: len(x.mntpnt or '')-len(y.mntpnt or '')) return parts def devname_to_index(devname): return devname_to_index_rec(devname) - 1 def devname_to_index_rec(devname): if not devname: return 0 return 26 * devname_to_index_rec(devname[:-1]) + (string.ascii_lowercase.index(devname[-1]) + 1) def index_to_devname(index, suffix=''): if index < 0: return suffix return index_to_devname(index / 26 -1, string.ascii_lowercase[index % 26]) + suffix def detect_size(filename): st = os.stat(filename) if stat.S_ISREG(st.st_mode): return st.st_size / 1024*1024 elif stat.S_ISBLK(st.st_mode): # I really wish someone would make these available in Python BLKGETSIZE64 = 2148012658 fp = open(filename, 'r') fd = fp.fileno() s = fcntl.ioctl(fd, BLKGETSIZE64, ' '*8) return unpack('L', s)[0] / 1024*1024 raise VMBuilderException('No idea how to find the size of %s' % filename) def qemu_img_path(): exes = ['kvm-img', 'qemu-img'] for dir in os.environ['PATH'].split(os.path.pathsep): for exe in exes: path = '%s%s%s' % (dir, os.path.sep, exe) if os.access(path, os.X_OK): return path def vbox_manager_path(): exe = 'VBoxManage' for dir in os.environ['PATH'].split(os.path.pathsep): path = '%s%s%s' % (dir, os.path.sep, exe) if os.access(path, os.X_OK): return path vm-builder-0.12.4+bzr494/VMBuilder/distro.py0000644000000000000000000000633411564301136016541 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Distro super class import logging import os from VMBuilder.util import run_cmd, call_hooks import VMBuilder.plugins class Context(VMBuilder.plugins.Plugin): def __init__(self): self._config = {} super(Context, self).__init__(self) self.plugins = [plugin_class(self) for plugin_class in self.plugin_classes] self.plugins.sort(key=lambda x:x.priority) self._cleanup_cbs = [] self.hooks = {} self.template_dirs = [os.path.expanduser('~/.vmbuilder/%s'), os.path.dirname(__file__) + '/plugins/%s/templates', '/etc/vmbuilder/%s'] self.overwrite = False # Cleanup def cleanup(self): logging.info("Cleaning up") while len(self._cleanup_cbs) > 0: self._cleanup_cbs.pop(0)() def add_clean_cb(self, cb): self._cleanup_cbs.insert(0, cb) def add_clean_cmd(self, *argv, **kwargs): cb = lambda : run_cmd(*argv, **kwargs) self.add_clean_cb(cb) return cb def cancel_cleanup(self, cb): try: self._cleanup_cbs.remove(cb) except ValueError: # Wasn't in there. No worries. pass # Hooks def register_hook(self, hook_name, func): self.hooks[hook_name] = self.hooks.get(hook_name, []) + [func] def call_hooks(self, *args, **kwargs): try: call_hooks(self, *args, **kwargs) except Exception: self.cleanup() raise class Distro(Context): def __init__(self): self.plugin_classes = VMBuilder._distro_plugins super(Distro, self).__init__() def set_chroot_dir(self, chroot_dir): self.chroot_dir = chroot_dir def build_chroot(self): self.call_hooks('preflight_check') self.call_hooks('set_defaults') self.call_hooks('bootstrap') self.call_hooks('configure_os') self.cleanup() def has_xen_support(self): """Install the distro into destdir""" raise NotImplemented('Distro subclasses need to implement the has_xen_support method') def install(self, destdir): """Install the distro into destdir""" raise NotImplemented('Distro subclasses need to implement the install method') def post_mount(self, fs): """Called each time a filesystem is mounted to let the distro add things to the filesystem""" def install_vmbuilder_log(self, logfile): """Let the distro copy the install logfile to the guest""" vm-builder-0.12.4+bzr494/VMBuilder/exception.py0000644000000000000000000000165511337261313017234 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Our very own exception class VMBuilderException(Exception): """Something failed inside VMBuilder""" pass class VMBuilderUserError(VMBuilderException): """The user did something silly.""" pass vm-builder-0.12.4+bzr494/VMBuilder/frontend.py0000644000000000000000000000336211337261313017052 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Frontend interface and classes import VMBuilder.plugins class Frontend(VMBuilder.plugins.Plugin): def __init__(self): self._setting_groups = [] self._config = {} self.context = self # self.settings = [] # def setting_group(self, help=None): # return self.SettingsGroup(help) # # def add_setting_group(self, group): # self.settings.append(group) # # def add_setting(self, **kwargs): # self.settings.append(Setting(**kwargs)) # # setting_types = ['store', 'store'] # class Setting(object): # def __init__(self, **kwargs): # self.shortarg = kwargs.get('shortarg', None) # self.longarg = kwargs.get('shortarg', None) # self.default = kwargs.get('default', None) # self.help = kwargs.get('help', None) # type = kwargs.get('type', 'store') # if type not in setting_types: # raise VMBuilderException("Invalid option type: %s" % type) # # class SettingsGroup(Setting): # pass vm-builder-0.12.4+bzr494/VMBuilder/hypervisor.py0000644000000000000000000001034612432655772017462 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Hypervisor super class import logging import os import VMBuilder.distro import VMBuilder.disk from VMBuilder.util import run_cmd, tmpdir STORAGE_DISK_IMAGE = 0 STORAGE_FS_IMAGE = 1 class Hypervisor(VMBuilder.distro.Context): preferred_storage = STORAGE_DISK_IMAGE def __init__(self, distro): self.plugin_classes = VMBuilder._hypervisor_plugins super(Hypervisor, self).__init__() self.plugins += [distro] self.distro = distro self.filesystems = [] self.disks = [] self.nics = [] def add_filesystem(self, *args, **kwargs): """Adds a filesystem to the virtual machine""" from VMBuilder.disk import Filesystem fs = Filesystem(self, *args, **kwargs) self.filesystems.append(fs) return fs def add_disk(self, *args, **kwargs): """Adds a disk image to the virtual machine""" from VMBuilder.disk import Disk disk = Disk(self, *args, **kwargs) self.disks.append(disk) return disk def install_os(self): self.nics = [self.NIC()] self.call_hooks('preflight_check') self.call_hooks('configure_networking', self.nics) self.call_hooks('create_partitions') self.call_hooks('configure_mounting', self.disks, self.filesystems) self.chroot_dir = tmpdir() self.call_hooks('mount_partitions', self.chroot_dir) run_cmd('rsync', '-aHA', '%s/' % self.distro.chroot_dir, self.chroot_dir) self.distro.set_chroot_dir(self.chroot_dir) if self.needs_bootloader: self.call_hooks('install_bootloader', self.chroot_dir, self.disks) self.call_hooks('install_kernel', self.chroot_dir) self.distro.call_hooks('post_install') self.call_hooks('unmount_partitions') os.rmdir(self.chroot_dir) def finalise(self, destdir): self.call_hooks('convert', self.preferred_storage == STORAGE_DISK_IMAGE and self.disks or self.filesystems, destdir) self.call_hooks('deploy', destdir) def create_partitions(self): """Creates all the vms partitions and formats them """ for fs in self.filesystems: fs.create() fs.mkfs() for disk in self.disks: disk.create() disk.partition() disk.map_partitions() disk.mkfs() def mount_partitions(self, mntdir): """Mounts all the vm's partitions and filesystems below .rootmnt""" logging.info('Mounting target filesystems') fss = VMBuilder.disk.get_ordered_filesystems(self) for fs in fss: fs.mount(mntdir) self.distro.post_mount(fs) def unmount_partitions(self): """Unmounts all the vm's partitions and filesystems""" logging.info('Unmounting target filesystem') fss = VMBuilder.disk.get_ordered_filesystems(self) fss.reverse() for fs in fss: fs.umount() for disk in self.disks: disk.unmap() def convert_disks(self, disks, destdir): for disk in disks: disk.convert(destdir, self.filetype) class NIC(object): def __init__(self, type='dhcp', ip=None, network=None, netmask=None, broadcast=None, dns=None, gateway=None): self.type = type self.ip = ip self.network = network self.netmask = netmask self.broadcast = broadcast self.dns = dns self.gateway = gateway vm-builder-0.12.4+bzr494/VMBuilder/log.py0000644000000000000000000000232212115571360016010 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Logging import logging import os import tempfile format = '%(asctime)s %(levelname)-8s: %(message)s' fd, logfile = tempfile.mkstemp() # Log everything to the logfile logging.basicConfig(format=format, level=logging.DEBUG, datefmt='%Y-%m-%d %H:%M', stream=os.fdopen(fd, 'a+'), filemode='w') console = logging.StreamHandler() console.setLevel(logging.INFO) console.setFormatter(logging.Formatter(format)) logging.getLogger('').addHandler(console) logging.info("logging to file: {}".format(logfile)) vm-builder-0.12.4+bzr494/VMBuilder/plugins/0000755000000000000000000000000011031160536016332 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/tests/0000755000000000000000000000000011341762327016025 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/util.py0000644000000000000000000001753312115731247016220 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Various utility functions import ConfigParser import errno import fcntl import logging import os.path import select import subprocess import tempfile from exception import VMBuilderException, VMBuilderUserError class NonBlockingFile(object): def __init__(self, fp, logfunc): self.file = fp self.set_non_blocking() self.buf = '' self.logbuf = '' self.logfunc = logfunc def set_non_blocking(self): flags = fcntl.fcntl(self.file, fcntl.F_GETFL) flags = flags | os.O_NONBLOCK fcntl.fcntl(self.file, fcntl.F_SETFL, flags) def __getattr__(self, attr): if attr == 'closed': return self.file.closed else: raise AttributeError() def process_input(self): data = self.file.read() if data == '': self.file.close() if self.logbuf: self.logfunc(self.logbuf) else: self.buf += data self.logbuf += data while '\n' in self.logbuf: line, self.logbuf = self.logbuf.split('\n', 1) self.logfunc(line) def run_cmd(*argv, **kwargs): """ Runs a command. Locale is reset to C to make parsing error messages possible. @type stdin: string @param stdin: input to provide to the process on stdin. If None, process' stdin will be attached to /dev/null @type ignore_fail: boolean @param ignore_fail: If True, a non-zero exit code from the command will not cause an exception to be raised. @type env: dict @param env: Dictionary of extra environment variables to set in the new process @rtype: string @return: string containing the stdout of the process """ env = kwargs.get('env', {}) stdin = kwargs.get('stdin', None) ignore_fail = kwargs.get('ignore_fail', False) args = [str(arg) for arg in argv] logging.debug(args.__repr__()) if stdin: logging.debug('stdin was set and it was a string: %s' % (stdin,)) stdin_arg = subprocess.PIPE else: stdin_arg = file('/dev/null', 'r') proc_env = dict(os.environ) proc_env['LANG'] = 'C' proc_env['LC_ALL'] = 'C' proc_env.update(env) try: proc = subprocess.Popen(args, stdin=stdin_arg, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env=proc_env) except OSError, error: if error.errno == errno.ENOENT: raise VMBuilderUserError, "Couldn't find the program '%s' on your system" % (argv[0]) else: raise VMBuilderUserError, "Couldn't launch the program '%s': %s" % (argv[0], error) if stdin: proc.stdin.write(stdin) proc.stdin.close() mystdout = NonBlockingFile(proc.stdout, logfunc=logging.debug) mystderr = NonBlockingFile(proc.stderr, logfunc=(ignore_fail and logging.debug or logging.info)) while not (mystdout.closed and mystderr.closed): # Block until either of them has something to offer fds = select.select([x.file for x in [mystdout, mystderr] if not x.closed], [], [])[0] for fp in [mystderr, mystdout]: if fp.file in fds: fp.process_input() status = proc.wait() if not ignore_fail and status != 0: raise VMBuilderException, "Process (%s) returned %d. stdout: %s, stderr: %s" % (args.__repr__(), status, mystdout.buf, mystderr.buf) return mystdout.buf def checkroot(): """ Check if we're running as root, and bail out if we're not. """ if os.geteuid() != 0: raise VMBuilderUserError("This script must be run as root (e.g. via sudo)") def render_template(plugin, context, tmplname, extra_context=None): # Import here to avoid having to build-dep on python-cheetah from Cheetah.Template import Template searchList = [] if context: searchList.append(extra_context) searchList.append(context) # tmpldirs.insert(0,'%s/%%s' % vm.templates) tmpldirs = [dir % plugin for dir in context.template_dirs] for dir in tmpldirs: tmplfile = '%s/%s.tmpl' % (dir, tmplname) if os.path.exists(tmplfile): t = Template(file=tmplfile, searchList=searchList) output = t.respond() logging.debug('Output from template \'%s\': %s' % (tmplfile, output)) return output raise VMBuilderException('Template %s.tmpl not found in any of %s' % (tmplname, ', '.join(tmpldirs))) def call_hooks(context, func, *args, **kwargs): logging.info('Calling hook: %s' % func) logging.debug('(args=%r, kwargs=%r)' % (args, kwargs)) for plugin in context.plugins: logging.debug('Calling %s method in %s plugin.' % (func, plugin.__module__)) try: getattr(plugin, func)(*args, **kwargs) except AttributeError as e: logging.debug('No such method ({}) in context plugin ({})'.format( func, plugin.__module__)) for f in context.hooks.get(func, []): logging.debug('Calling %r.' % (f,)) f(*args, **kwargs) logging.debug('Calling %s method in context plugin %s.' % (func, context.__module__)) try: getattr(context, func)(*args, **kwargs) except AttributeError as e: logging.debug('No such method ({}) in context plugin ({})'.format( func, plugin.__module__)) def tmp_filename(suffix='', tmp_root=None): # There is a risk in using tempfile.mktemp(): it's not recommended # to run vmbuilder on machines with untrusted users. return tempfile.mktemp(suffix=suffix, dir=tmp_root) def tmpdir(suffix='', tmp_root=None): return tempfile.mkdtemp(suffix=suffix, dir=tmp_root) def set_up_tmpfs(tmp_root=None, size=1024): """Sets up a tmpfs storage under `tmp_root` with the size of `size` MB. `tmp_root` defaults to tempfile.gettempdir(). """ mount_point = tmpdir('tmpfs', tmp_root) mount_cmd = ["mount", "-t", "tmpfs", "-o", "size=%dM,mode=0770" % int(size), "tmpfs", mount_point ] logging.info('Mounting tmpfs under %s' % mount_point) logging.debug('Executing: %s' % mount_cmd) run_cmd(*mount_cmd) return mount_point def clean_up_tmpfs(mount_point): """Unmounts a tmpfs storage under `mount_point`.""" umount_cmd = ["umount", "-t", "tmpfs", mount_point ] logging.info('Unmounting tmpfs from %s' % mount_point) logging.debug('Executing: %s' % umount_cmd) run_cmd(*umount_cmd) def get_conf_value(context, confparser, key): confvalue = None try: confvalue = confparser.get('DEFAULT', key) except ConfigParser.NoSectionError: pass except ConfigParser.NoOptionError: pass if confparser.has_option(context.arg, key): confvalue = confparser.get(context.arg, key) logging.debug('Returning value %s for configuration key %s' % (repr(confvalue), key)) return confvalue def apply_config_files_to_context(config_files, context): confparser = ConfigParser.SafeConfigParser() confparser.read(config_files) for (key, setting) in context._config.iteritems(): confvalue = get_conf_value(context, confparser, key) if confvalue: setting.set_value_fuzzy(confvalue) vm-builder-0.12.4+bzr494/VMBuilder/vcsversion.py0000644000000000000000000000116511674657633017455 0ustar 00000000000000#!/usr/bin/env python """This file is automatically generated by generate_version_info It uses the current working tree to determine the revision. So don't edit it. :) """ version_info = {'branch_nick': u'vmbuilder', 'build_date': '2011-12-22 10:49:13 -0600', 'clean': None, 'date': '2011-12-22 10:11:20 -0600', 'revision_id': 'serge.hallyn@canonical.com-20111222161120-73vtdj1lh029ax92', 'revno': '475'} revisions = {} file_revisions = {} if __name__ == '__main__': print 'revision: %(revno)s' % version_info print 'nick: %(branch_nick)s' % version_info print 'revision id: %(revision_id)s' % version_info vm-builder-0.12.4+bzr494/VMBuilder/vm.py0000644000000000000000000002437211372226766015675 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # The VM class import ConfigParser from gettext import gettext import logging import os import optparse import textwrap import urllib import VMBuilder import VMBuilder.util as util import VMBuilder.log as log import VMBuilder.disk as disk from VMBuilder.disk import Disk, Filesystem from VMBuilder.exception import VMBuilderException, VMBuilderUserError _ = gettext class VM(object): """The VM object has the following attributes of relevance to plugins: distro: A distro object, representing the distro running in the vm disks: The disk images for the vm. filesystems: The filesystem images for the vm. result_files: A list of the files that make up the entire vm. The ownership of these files will be fixed up. optparser: Will be of interest mostly to frontends. Any sort of option a plugin accepts will be represented in the optparser. """ def __init__(self, conf=None): self.hypervisor = None #: hypervisor object, representing the hypervisor the vm is destined for self.distro = None self.disks = [] self.filesystems = [] self.result_files = [] self.plugins = [] self._cleanup_cbs = [] #: final destination for the disk images self.destdir = None #: tempdir where we do all the work self.workdir = None #: mount point where the disk images will be mounted self.rootmnt = None #: directory where we build up the guest filesystem self.tmproot = None self.fsmounted = False self.optparser = _MyOptParser(epilog="ubuntu-vm-builder is Copyright (C) 2007-2009 Canonical Ltd. and written by Soren Hansen .", usage='%prog hypervisor distro [options]') self.optparser.arg_help = (('hypervisor', self.hypervisor_help), ('distro', self.distro_help)) self.confparser = ConfigParser.SafeConfigParser() if conf: if not(os.path.isfile(conf)): raise VMBuilderUserError('The path to the configuration file is not valid: %s.' % conf) else: conf = '' self.confparser.read(['/etc/vmbuilder.cfg', os.path.expanduser('~/.vmbuilder.cfg'), conf]) self._register_base_settings() self.add_clean_cmd('rm', log.logfile) def distro_help(self): return 'Distro. Valid options: %s' % " ".join(VMBuilder.distros.keys()) def hypervisor_help(self): return 'Hypervisor. Valid options: %s' % " ".join(VMBuilder.hypervisors.keys()) def register_setting(self, *args, **kwargs): return self.optparser.add_option(*args, **kwargs) def register_setting_group(self, group): return self.optparser.add_option_group(group) def setting_group(self, *args, **kwargs): return optparse.OptionGroup(self.optparser, *args, **kwargs) def _register_base_settings(self): self.register_setting('-d', '--dest', dest='destdir', help='Specify the destination directory. [default: -].') self.register_setting('-c', '--config', type='string', help='Specify a additional configuration file') self.register_setting('--debug', action='callback', callback=log.set_verbosity, help='Show debug information') self.register_setting('-v', '--verbose', action='callback', callback=log.set_verbosity, help='Show progress information') self.register_setting('-q', '--quiet', action='callback', callback=log.set_verbosity, help='Silent operation') self.register_setting('-t', '--tmp', default=os.environ.get('TMPDIR', '/tmp'), help='Use TMP as temporary working space for image generation. Defaults to $TMPDIR if it is defined or /tmp otherwise. [default: %default]') self.register_setting('--templates', metavar='DIR', help='Prepend DIR to template search path.') self.register_setting('-o', '--overwrite', action='store_true', default=False, help='Force overwrite of destination directory if it already exist. [default: %default]') self.register_setting('--in-place', action='store_true', default=False, help='Install directly into the filesystem images. This is needed if your $TMPDIR is nodev and/or nosuid, but will result in slightly larger file system images.') self.register_setting('--tmpfs', metavar="OPTS", help='Use a tmpfs as the working directory, specifying its size or "-" to use tmpfs default (suid,dev,size=1G).') self.register_setting('-m', '--mem', type='int', default=128, help='Assign MEM megabytes of memory to the guest vm. [default: %default]') def add_disk(self, *args, **kwargs): """Adds a disk image to the virtual machine""" disk = Disk(self, *args, **kwargs) self.disks.append(disk) return disk def add_filesystem(self, *args, **kwargs): """Adds a filesystem to the virtual machine""" fs = Filesystem(self, *args, **kwargs) self.filesystems.append(fs) return fs def call_hooks(self, func): for plugin in self.plugins: getattr(plugin, func)() getattr(self.hypervisor, func)() getattr(self.distro, func)() def preflight_check(self): for opt in sum([self.confparser.options(section) for section in self.confparser.sections()], []) + [k for (k,v) in self.confparser.defaults().iteritems()]: if '-' in opt: raise VMBuilderUserError('You specified a "%s" config option in a config file, but that is not valid. Perhaps you meant "%s"?' % (opt, opt.replace('-', '_'))) self.call_hooks('preflight_check') # Check repository availability if self.mirror: testurl = self.mirror else: testurl = 'http://archive.ubuntu.com/' try: logging.debug('Testing access to %s' % testurl) testnet = urllib.urlopen(testurl) except IOError: raise VMBuilderUserError('Could not connect to %s. Please check your connectivity and try again.' % testurl) testnet.close() def create(self): """ The core vm creation method The VM creation happens in the following steps: A series of preliminary checks are performed: - We check if we're being run as root, since the filesystem handling requires root priv's - Each plugin's preflight_check method is called. See L{VMBuilder.plugins.Plugin} documentation for details - L{create_directory_structure} is called - VMBuilder.disk.create_partitions is called - VMBuilder.disk.create_filesystems is called - .mount_partitions is called - .install is called """ util.checkroot() finished = False try: self.preflight_check() self.create_directory_structure() disk.create_partitions(self) disk.create_filesystems(self) self.mount_partitions() self.install() self.umount_partitions() self.hypervisor.finalize() self.deploy() util.fix_ownership(self.result_files) finished = True except VMBuilderException: raise finally: if not finished: logging.debug("Oh, dear, an exception occurred") self.cleanup() if not finished: return(1) return(0) class _MyOptParser(optparse.OptionParser): def format_arg_help(self, formatter): result = [] for arg in self.arg_help: result.append(self.format_arg(formatter, arg)) return "".join(result) def format_arg(self, formatter, arg): result = [] arghelp = arg[1]() arg = arg[0] width = formatter.help_position - formatter.current_indent - 2 if len(arg) > width: arg = "%*s%s\n" % (self.current_indent, "", arg) indent_first = formatter.help_position else: # start help on same line as opts arg = "%*s%-*s " % (formatter.current_indent, "", width, arg) indent_first = 0 result.append(arg) help_lines = textwrap.wrap(arghelp, formatter.help_width) result.append("%*s%s\n" % (indent_first, "", help_lines[0])) result.extend(["%*s%s\n" % (formatter.help_position, "", line) for line in help_lines[1:]]) return "".join(result) def format_option_help(self, formatter=None): if formatter is None: formatter = self.formatter formatter.store_option_strings(self) result = [] if self.arg_help: result.append(formatter.format_heading(_("Arguments"))) formatter.indent() result.append(self.format_arg_help(formatter)) result.append("\n") result.append("*** Use vmbuilder --help to get more options. Hypervisor, distro, and plugins specific help is only available when the first two arguments are supplied.\n") result.append("\n") formatter.dedent() result.append(formatter.format_heading(_("Options"))) formatter.indent() if self.option_list: result.append(optparse.OptionContainer.format_option_help(self, formatter)) result.append("\n") for group in self.option_groups: result.append(group.format_help(formatter)) result.append("\n") formatter.dedent() # Drop the last "\n", or the header if no options or option groups: return "".join(result[:-1]) vm-builder-0.12.4+bzr494/VMBuilder/contrib/__init__.py0000644000000000000000000000000011337605667020432 0ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/contrib/cli.py0000644000000000000000000005241512115716334017450 0ustar 00000000000000# Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # CLI plugin import logging import optparse import os import pwd import shutil import sys import tempfile import VMBuilder import VMBuilder.util as util from VMBuilder.disk import parse_size import VMBuilder.hypervisor from VMBuilder.exception import VMBuilderUserError, VMBuilderException class CLI(object): arg = 'cli' def main(self): tmpfs_mount_point = None try: optparser = optparse.OptionParser() self.set_usage(optparser) optparser.add_option('--version', action='callback', callback=self.versioninfo, help='Show version information') group = optparse.OptionGroup(optparser, 'Build options') group.add_option('--debug', action='callback', callback=self.set_verbosity, help='Show debug information') group.add_option('--verbose', '-v', action='callback', callback=self.set_verbosity, help='Show progress information') group.add_option('--quiet', '-q', action='callback', callback=self.set_verbosity, help='Silent operation') group.add_option('--overwrite', '-o', action='store_true', help='Remove destination directory before starting build') group.add_option('--config', '-c', type='str', help='Configuration file') group.add_option('--templates', metavar='DIR', help='Prepend DIR to template search path.') group.add_option('--destdir', '-d', type='str', help='Destination directory') group.add_option('--only-chroot', action='store_true', help=("Only build the chroot. Don't install it " "on disk images or anything.")) group.add_option('--chroot-dir', help="Build the chroot in directory.") group.add_option('--existing-chroot', help="Use existing chroot.") group.add_option('--tmp', '-t', metavar='DIR', dest='tmp_root', default=tempfile.gettempdir(), help=('Use TMP as temporary working space for ' 'image generation. Defaults to $TMPDIR if ' 'it is defined or /tmp otherwise. ' '[default: %default]')) group.add_option('--tmpfs', metavar="SIZE", help=('Use a tmpfs as the working directory, ' 'specifying its size or "-" to use tmpfs ' 'default (suid,dev,size=1G).')) optparser.add_option_group(group) group = optparse.OptionGroup(optparser, 'Disk') group.add_option('--rootsize', metavar='SIZE', default=4096, help=('Size (in MB) of the root filesystem ' '[default: %default]')) group.add_option('--optsize', metavar='SIZE', default=0, help=('Size (in MB) of the /opt filesystem. If not' ' set, no /opt filesystem will be added.')) group.add_option('--swapsize', metavar='SIZE', default=1024, help=('Size (in MB) of the swap partition ' '[default: %default]')) group.add_option('--raw', metavar='PATH', type='str', action='append', help=("Specify a file (or block device) to use as " "first disk image (can be specified multiple" " times).")) group.add_option('--part', metavar='PATH', type='str', help=("Specify a partition table in PATH. Each " "line of partfile should specify (root " "first): \n mountpoint size \none per " "line, separated by space, where size is " "in megabytes. You can have up to 4 " "virtual disks, a new disk starts on a " "line containing only '---'. ie: \n root " "2000 \n /boot 512 \n swap 1000 \n " "--- \n /var 8000 \n /var/log 2000")) optparser.add_option_group(group) optparser.disable_interspersed_args() (dummy, args) = optparser.parse_args(sys.argv[1:]) optparser.enable_interspersed_args() hypervisor, distro = self.handle_args(optparser, args) self.add_settings_from_context(optparser, distro) self.add_settings_from_context(optparser, hypervisor) hypervisor.register_hook('fix_ownership', self.fix_ownership) config_files = ['/etc/vmbuilder.cfg', os.path.expanduser('~/.vmbuilder.cfg')] (self.options, args) = optparser.parse_args(sys.argv[2:]) if os.geteuid() != 0: raise VMBuilderUserError('Must run as root') logging.debug("Launch directory: {}".format(os.getcwd())) distro.overwrite = hypervisor.overwrite = self.options.overwrite destdir = self.options.destdir or ('%s-%s' % (distro.arg, hypervisor.arg)) logging.debug("Output destdir: {}".format(destdir)) if self.options.tmpfs and self.options.chroot_dir: raise VMBuilderUserError('--chroot-dir and --tmpfs can not be used together.') if os.path.exists(destdir): if os.path.realpath(destdir) == os.getcwd(): raise VMBuilderUserError('Current working directory cannot be used as a destination directory') if self.options.overwrite: logging.debug('%s existed, but -o was specified. ' 'Nuking it.' % destdir) shutil.rmtree(destdir) else: raise VMBuilderUserError('%s already exists' % destdir) if self.options.config: config_files.append(self.options.config) util.apply_config_files_to_context(config_files, distro) util.apply_config_files_to_context(config_files, hypervisor) if self.options.templates: distro.template_dirs.insert(0, '%s/%%s' % self.options.templates) hypervisor.template_dirs.insert(0, '%s/%%s' % self.options.templates) for option in dir(self.options): if option.startswith('_') or option in ['ensure_value', 'read_module', 'read_file']: continue val = getattr(self.options, option) option = option.replace('_', '-') if val: if (distro.has_setting(option) and distro.get_setting_default(option) != val): distro.set_setting_fuzzy(option, val) elif (hypervisor.has_setting(option) and hypervisor.get_setting_default(option) != val): hypervisor.set_setting_fuzzy(option, val) chroot_dir = None if self.options.existing_chroot: distro.set_chroot_dir(self.options.existing_chroot) distro.call_hooks('preflight_check') else: if self.options.tmpfs is not None: if str(self.options.tmpfs) == '-': tmpfs_size = 1024 else: tmpfs_size = int(self.options.tmpfs) tmpfs_mount_point = util.set_up_tmpfs( tmp_root=self.options.tmp_root, size=tmpfs_size) chroot_dir = tmpfs_mount_point elif self.options.chroot_dir: os.mkdir(self.options.chroot_dir) chroot_dir = self.options.chroot_dir else: chroot_dir = util.tmpdir(tmp_root=self.options.tmp_root) distro.set_chroot_dir(chroot_dir) distro.build_chroot() if self.options.only_chroot: print 'Chroot can be found in %s' % distro.chroot_dir sys.exit(0) self.set_disk_layout(optparser, hypervisor) hypervisor.install_os() os.mkdir(destdir) self.fix_ownership(destdir) hypervisor.finalise(destdir) # If chroot_dir is not None, it means we created it, # and if we reach here, it means the user didn't pass # --only-chroot. Hence, we need to remove it to clean # up after ourselves. if chroot_dir is not None and tmpfs_mount_point is None: util.run_cmd('rm', '-rf', '--one-file-system', chroot_dir) except VMBuilderException, e: logging.error(e) raise finally: if tmpfs_mount_point is not None: util.clean_up_tmpfs(tmpfs_mount_point) util.run_cmd('rmdir', tmpfs_mount_point) def fix_ownership(self, filename): """ Change ownership of file to $SUDO_USER. @type path: string @param path: file or directory to give to $SUDO_USER """ if 'SUDO_USER' in os.environ: logging.debug('Changing ownership of %s to %s' % (filename, os.environ['SUDO_USER'])) (uid, gid) = pwd.getpwnam(os.environ['SUDO_USER'])[2:4] os.chown(filename, uid, gid) def add_settings_from_context(self, optparser, context): setting_groups = set([setting.setting_group for setting in context._config.values()]) for setting_group in setting_groups: optgroup = optparse.OptionGroup(optparser, setting_group.name) for setting in setting_group._settings: args = ['--%s' % setting.name] args += setting.extra_args kwargs = {} if setting.help: kwargs['help'] = setting.help if len(setting.extra_args) > 0: setting.help += " Config option: %s" % setting.name if setting.metavar: kwargs['metavar'] = setting.metavar if setting.get_default(): kwargs['default'] = setting.get_default() if type(setting) == VMBuilder.plugins.Plugin.BooleanSetting: kwargs['action'] = 'store_true' if type(setting) == VMBuilder.plugins.Plugin.ListSetting: kwargs['action'] = 'append' optgroup.add_option(*args, **kwargs) optparser.add_option_group(optgroup) def versioninfo(self, option, opt, value, parser): print ('%(major)d.%(minor)d.%(micro)s' % VMBuilder.get_version_info()) sys.exit(0) def set_usage(self, optparser): optparser.set_usage('%prog hypervisor distro [options]') # optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('distro', vm.distro_help)) def handle_args(self, optparser, args): if len(args) < 2: optparser.error("You need to specify at least the hypervisor type " "and the distro") distro = VMBuilder.get_distro(args[1])() hypervisor = VMBuilder.get_hypervisor(args[0])(distro) return hypervisor, distro def set_verbosity(self, option, opt_str, value, parser): if opt_str == '--debug': VMBuilder.set_console_loglevel(logging.DEBUG) elif opt_str == '--verbose': VMBuilder.set_console_loglevel(logging.INFO) elif opt_str == '--quiet': VMBuilder.set_console_loglevel(logging.CRITICAL) def set_disk_layout(self, optparser, hypervisor): default_filesystem = hypervisor.distro.preferred_filesystem() if not self.options.part: rootsize = parse_size(self.options.rootsize) swapsize = parse_size(self.options.swapsize) optsize = parse_size(self.options.optsize) if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root) hypervisor.add_filesystem(filename=tmpfile, size='%dM' % rootsize, type='ext3', mntpnt='/') if swapsize > 0: tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root) hypervisor.add_filesystem(filename=tmpfile, size='%dM' % swapsize, type='swap', mntpnt=None) if optsize > 0: tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root) hypervisor.add_filesystem(filename=tmpfile, size='%dM' % optsize, type='ext3', mntpnt='/opt') else: if self.options.raw: for raw_disk in self.options.raw: hypervisor.add_disk(filename=raw_disk) disk = hypervisor.disks[0] else: size = rootsize + swapsize + optsize tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root) disk = hypervisor.add_disk(tmpfile, size='%dM' % size) offset = 0 disk.add_part(offset, rootsize, default_filesystem, '/') offset += rootsize if swapsize > 0: disk.add_part(offset, swapsize, 'swap', 'swap') offset += swapsize if optsize > 0: disk.add_part(offset, optsize, default_filesystem, '/opt') else: # We need to parse the file specified if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: try: for line in file(self.options.part): elements = line.strip().split(' ') if len(elements) < 4: tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root) else: tmpfile = elements[3] if elements[0] == 'root': hypervisor.add_filesystem(elements[1], default_filesystem, filename=tmpfile, mntpnt='/') elif elements[0] == 'swap': hypervisor.add_filesystem(elements[1], type='swap', filename=tmpfile, mntpnt=None) elif elements[0] == '---': # We just ignore the user's attempt to specify multiple disks pass elif len(elements) == 3: hypervisor.add_filesystem(elements[1], type=default_filesystem, filename=tmpfile, mntpnt=elements[0], devletter='', device=elements[2], dummy=(int(elements[1]) == 0)) else: hypervisor.add_filesystem(elements[1], type=default_filesystem, filename=tmpfile, mntpnt=elements[0]) except IOError, (errno, strerror): optparser.error("%s parsing --part option: %s" % (errno, strerror)) else: try: curdisk = list() size = 0 disk_idx = 0 for line in file(self.options.part): pair = line.strip().split(' ',1) if pair[0] == '---': self.do_disk(hypervisor, curdisk, size, disk_idx) curdisk = list() size = 0 disk_idx += 1 elif pair[0] != '': logging.debug("part: %s, size: %d" % (pair[0], int(pair[1]))) curdisk.append((pair[0], pair[1])) size += int(pair[1]) self.do_disk(hypervisor, curdisk, size, disk_idx) except IOError, (errno, strerror): optparser.error("%s parsing --part option: %s" % (errno, strerror)) def do_disk(self, hypervisor, curdisk, size, disk_idx): default_filesystem = hypervisor.distro.preferred_filesystem() if self.options.raw: disk = hypervisor.add_disk(filename=self.options.raw[disk_idx]) else: disk = hypervisor.add_disk( util.tmp_filename(tmp_root=self.options.tmp_root), size+1) logging.debug("do_disk #%i - size: %d" % (disk_idx, size)) offset = 0 for pair in curdisk: logging.debug("do_disk #%i - part: %s, size: %s, offset: %d" % (disk_idx, pair[0], pair[1], offset)) if pair[0] == 'root': disk.add_part(offset, int(pair[1]), default_filesystem, '/') elif pair[0] == 'swap': disk.add_part(offset, int(pair[1]), pair[0], pair[0]) else: disk.add_part(offset, int(pair[1]), default_filesystem, pair[0]) offset += int(pair[1]) class UVB(CLI): arg = 'ubuntu-vm-builder' def set_usage(self, optparser): optparser.set_usage('%prog hypervisor suite [options]') # optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('suite', self.suite_help)) def suite_help(self): return ('Suite. Valid options: %s' % " ".join(VMBuilder.plugins.ubuntu.distro.Ubuntu.suites)) def handle_args(self, optparser, args): if len(args) < 2: optparser.error("You need to specify at least the hypervisor type " "and the series") distro = VMBuilder.get_distro('ubuntu')() hypervisor = VMBuilder.get_hypervisor(args[0])(distro) distro.set_setting('suite', args[1]) return hypervisor, distro vm-builder-0.12.4+bzr494/VMBuilder/plugins/__init__.py0000644000000000000000000003016711370761104020456 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import os import re import shutil import VMBuilder import VMBuilder.util as util from VMBuilder.exception import VMBuilderException def load_plugins(): for plugin in find_plugins(): exec "import %s" % plugin def find_plugins(): retval = [] for plugin_dir in __path__: for p in os.listdir(plugin_dir): path = '%s/%s' % (plugin_dir, p) if os.path.isdir(path) and os.path.isfile('%s/__init__.py' % path): retval.append("VMBuilder.plugins.%s" % p) return retval class Plugin(object): priority = 10 def __init__(self, context): self.context = context self._setting_groups = [] self.register_options() def register_options(self): pass def set_defaults(self): pass def preflight_check(self): """ Override this method with checks for anything that might cause the VM creation to fail raise an exception if you can see already that this won't work """ pass def post_install(self): """ This is called just after the distro is installed, before it gets copied to the fs images. """ pass def install_file(self, path, contents=None, source=None, mode=None): fullpath = '%s%s' % (self.context.chroot_dir, path) if not os.path.isdir(os.path.dirname(fullpath)): os.makedirs(os.path.dirname(fullpath)) if source and not contents: shutil.copy(source, fullpath) else: fp = open(fullpath, 'w') fp.write(contents) fp.close() if mode: os.chmod(fullpath, mode) return fullpath def install_from_template(self, path, tmplname, context=None, mode=None): return self.install_file(path, VMBuilder.util.render_template(self.__module__.split('.')[2], self.context, tmplname, context), mode=mode) def run_in_target(self, *args, **kwargs): return util.run_cmd('chroot', self.chroot_dir, *args, **kwargs) def call_hooks(self, *args, **kwargs): return util.call_hooks(self.context, *args, **kwargs) # Settings class SettingGroup(object): def __init__(self, plugin, context, name): # The plugin that owns this setting self.plugin = plugin # The VM object self.context = context # Name of the Setting Group self.name = name # A list of Setting objects self._settings = [] def add_setting(self, *args, **kwargs): # kwarg['type'] is used to determine which type of Setting object to create # but we don't want to pass it on to its __init__. if 'type' in kwargs: type = kwargs['type'] del kwargs['type'] else: type = 'str' if type == 'str': setting = self.plugin.StringSetting(self, *args, **kwargs) elif type == 'bool': setting = self.plugin.BooleanSetting(self, *args, **kwargs) elif type == 'list': setting = self.plugin.ListSetting(self, *args, **kwargs) elif type == 'int': setting = self.plugin.IntSetting(self, *args, **kwargs) else: raise VMBuilderException("Unknown setting type: '%s' (Plugin: '%s', Setting group: '%s', Setting: '%s')" % (type, self.plugin.__module__, self.name, args[0])) self._settings.append(setting) class Setting(object): default = None def __init__(self, setting_group, name, metavar=None, help=None, extra_args=None, valid_options=None, action=None, **kwargs): # The Setting Group object that owns this Setting self.setting_group = setting_group # The name if the setting name_regex = '[a-z0-9-]+$' if not re.match(name_regex, name): raise VMBuilderException('Invalid name for Setting: %s. Must match regex: %s' % (name, name_regex)) else: self.name = name self.default = kwargs.get('default', self.default) self.help = help # Alternate names (for the CLI) self.extra_args = extra_args or [] self.metavar = metavar self.value = None self.value_set = False self.valid_options = valid_options if self.name in self.setting_group.context._config: raise VMBuilderException("Setting named %s already exists. Previous definition in %s/%s/%s." % (self.name, self.setting_group.plugin.__name__, self.setting_group.plugin._config[self.name].setting_group.name, self.setting_group.plugin._config[self.name].name)) self.setting_group.context._config[self.name] = self def get_value(self): """ If a value has previously been set, return it. If not, return the default value. """ if self.value_set: return self.value else: return self.default def do_check_value(self, value): """ Checks the value's validity. """ if self.valid_options is not None: if value not in self.valid_options: raise VMBuilderException('%r is not a valid option for %s. Valid options are: %s' % (value, self.name, ' '.join(self.valid_options))) else: return self.check_value(value) def get_valid_options(self): return self.valid_options def set_valid_options(self, valid_options): """ Set the list of valid options for this setting. """ if not type(valid_options) == list and valid_options is not None: raise VMBuilderException('set_valid_options only accepts lists or None') if valid_options: for option in valid_options: self.check_value(option) self.valid_options = valid_options def get_default(self): """ Return the default value. """ return self.default def set_default(self, value): """ Set a new default value. """ value = self.do_check_value(value) self.default = value def set_value_fuzzy(self, value): """ Set new value. Contrary to L{set_value}, L{set_value_fuzzy} will attempt to turn L{value} into the target type. E.g. turning '10' into 10, "main,universe,multiverse" into ['main', 'universe', 'multiverse'] """ return self.set_value(value) def set_value(self, value): """ Set a new value. """ value = self.do_check_value(value) self.value = value self.value_set = True class ListSetting(Setting): def __init__(self, *args, **kwargs): self.default = [] super(Plugin.ListSetting, self).__init__(*args, **kwargs) def set_value_fuzzy(self, value): if len(value) == 1 and type(value[0]) == str: value = value[0] if type(value) == str: if value == '': return self.set_value([]) for sep in [':', ',']: if sep in value: split_regex = re.compile("\s*%s\s*" % sep) return self.set_value(split_regex.split(value)) value = [value] self.set_value(value) return self.set_value(value) def check_value(self, value): if not type(value) == list: raise VMBuilderException('%r is type %s, expected list.' % (value, type(value))) return value class IntSetting(Setting): def set_value_fuzzy(self, value): if type(value) != int: try: value = int(value) except ValueError: raise VMBuilderException('Could not interpret %r as an int.' % (value,)) return self.set_value(value) def check_value(self, value): if not type(value) == int: raise VMBuilderException('%r is type %s, expected int.' % (value, type(value))) return value class BooleanSetting(Setting): def set_value_fuzzy(self, value): if type(value) == str: if value.lower() in ['no', 'false', 'off', '0']: value = False elif value.lower() in ['yes', 'true', 'on', '1']: value = True else: raise VMBuilderException('Could not interpret %r as a boolean value.' % (value,)) return self.set_value(value) def check_value(self, value): if not type(value) == bool: raise VMBuilderException('%r is type %s, expected bool.' % (value, type(value))) return value class StringSetting(Setting): def check_value(self, value): if not type(value) == str: raise VMBuilderException('%r is type %s, expected str.' % (value, type(value))) return value def setting_group(self, name): setting_group = self.SettingGroup(self, self.context, name) self._setting_groups.append(setting_group) return setting_group def has_setting(self, name): return name in self.context._config def get_setting(self, name): if not name in self.context._config: raise VMBuilderException('Unknown config key: %s' % name) return self.context._config[name].get_value() def set_setting_fuzzy(self, name, value): if not name in self.context._config: raise VMBuilderException('Unknown config key: %s' % name) # print 'fuzzy setting of %s: %r' % (name, value) self.context._config[name].set_value_fuzzy(value) def set_setting(self, name, value): if not name in self.context._config: raise VMBuilderException('Unknown config key: %s' % name) self.context._config[name].set_value(value) def set_setting_default(self, name, value): if not name in self.context._config: raise VMBuilderException('Unknown config key: %s' % name) self.context._config[name].set_default(value) def get_setting_default(self, name): if not name in self.context._config: raise VMBuilderException('Unknown config key: %s' % name) return self.context._config[name].get_default() def get_setting_valid_options(self, name): if not name in self.context._config: raise VMBuilderException('Unknown config key: %s' % name) return self.context._config[name].get_valid_options() def set_setting_valid_options(self, name, valid_options): if not name in self.context._config: raise VMBuilderException('Unknown config key: %s' % name) self.context._config[name].set_valid_options(valid_options) vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/0000755000000000000000000000000012613023706017560 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/ec2/0000755000000000000000000000000011062476061017012 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/firstscripts/0000755000000000000000000000000011067771743021112 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/kvm/0000755000000000000000000000000011031160536017127 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/libvirt/0000755000000000000000000000000011057103556020014 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/network/0000755000000000000000000000000011332043203020016 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/postinst/0000755000000000000000000000000011071214045020214 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/0000755000000000000000000000000011031160536017654 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/virtualbox/0000755000000000000000000000000011137376102020536 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/vmware/0000755000000000000000000000000011061500023017623 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/xen/0000755000000000000000000000000011050540540017122 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/__init__.py0000644000000000000000000000134412613023706021673 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import distro vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/distro.py0000644000000000000000000003342112613023706021441 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import logging import os import shutil import stat import VMBuilder from VMBuilder import register_distro, Distro from VMBuilder.util import run_cmd from VMBuilder.exception import VMBuilderUserError, VMBuilderException class Debian(Distro): name = 'Debian' arg = 'debian' suites = ['potato', 'woody', 'sarge', 'etch', 'lenny', 'squeeze', 'wheezy', 'jessie', 'stretch' ] # Maps host arch to valid guest archs valid_archs = { 'amd64' : ['amd64', 'i386' ], 'i386' : [ 'i386' ] } xen_kernel = '' def register_options(self): group = self.setting_group('Package options') group.add_setting('addpkg', type='list', metavar='PKG', help='Install PKG into the guest (can be specified multiple times).') group.add_setting('removepkg', type='list', metavar='PKG', help='Remove PKG from the guest (can be specified multiple times)') group.add_setting('seedfile', metavar="SEEDFILE", help='Seed the debconf database with the contents of this seed file before installing packages') group = self.setting_group('General OS options') self.host_arch = run_cmd('dpkg', '--print-architecture').rstrip() group.add_setting('arch', extra_args=['-a'], default=self.host_arch, help='Specify the target architecture. Valid options: amd64 i386 (defaults to host arch)') group.add_setting('hostname', default='debian', help='Set NAME as the hostname of the guest. Default: debian. Also uses this name as the VM name.') group = self.setting_group('Installation options') group.add_setting('suite', default='jessie', help='Suite to install. Valid options: %s [default: %%default]' % ' '.join(self.suites)) group.add_setting('flavour', extra_args=['--kernel-flavour'], help='Kernel flavour to use. Default and valid options depend on architecture and suite') group.add_setting('variant', metavar='VARIANT', help='Passed to debootstrap --variant flag; use minbase, buildd, or fakechroot.') group.add_setting('debootstrap-tarball', metavar='FILE', help='Passed to debootstrap --unpack-tarball flag.') group.add_setting('iso', metavar='PATH', help='Use an iso image as the source for installation of file. Full path to the iso must be provided. If --mirror is also provided, it will be used in the final sources.list of the vm. This requires suite and kernel parameter to match what is available on the iso, obviously.') group.add_setting('mirror', metavar='URL', help='Use Debian mirror at URL instead of the default, which is http://ftp.debian.org/debian for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise') group.add_setting('proxy', metavar='URL', help='Use proxy at URL for cached packages') group.add_setting('install-mirror', metavar='URL', help='Use Debian mirror at URL for the installation only. Apt\'s sources.list will still use default or URL set by --mirror') group.add_setting('security-mirror', metavar='URL', help='Use Debian security mirror at URL instead of the default, which is http://security.debian.org/debian-security.') group.add_setting('install-security-mirror', metavar='URL', help='Use the security mirror at URL for installation only. Apt\'s sources.list will still use default or URL set by --security-mirror') group.add_setting('components', type='list', metavar='COMPS', help='A comma seperated list of distro components to include (e.g. main,universe).') group.add_setting('lang', metavar='LANG', default=get_locale(), help='Set the locale to LANG [default: %default]') group.add_setting('timezone', metavar='TZ', default='UTC', help='Set the timezone to TZ in the vm. [default: %default]') group = self.setting_group('Settings for the initial user') group.add_setting('user', default='debian', help='Username of initial user [default: %default]') group.add_setting('name', default='Debian', help='Full name of initial user [default: %default]') group.add_setting('pass', default='debian', help='Password of initial user [default: %default]') group.add_setting('rootpass', help='Initial root password (WARNING: this has strong security implications).') group.add_setting('uid', type='int', help='Initial UID value.') group.add_setting('gid', help='Initial GID value.') group.add_setting('lock-user', type='bool', default=False, help='Lock the initial user [default: %default]') group = self.setting_group('Other options') group.add_setting('ssh-key', metavar='PATH', help='Add PATH to root\'s ~/.ssh/authorized_keys (WARNING: this has strong security implications).') group.add_setting('ssh-user-key', help='Add PATH to the user\'s ~/.ssh/authorized_keys.') group.add_setting('manifest', metavar='PATH', help='If passed, a manifest will be written to PATH') def set_defaults(self): self.set_setting_default('mirror', 'http://ftp.debian.org/debian') self.set_setting_default('security-mirror', 'http://security.debian.org/debian-security') self.set_setting_default('components', ['main']) def preflight_check(self): """While not all of these are strictly checks, their failure would inevitably lead to failure, and since we can check them before we start setting up disk and whatnot, we might as well go ahead an do this now.""" suite = self.get_setting('suite') if not suite in self.suites: raise VMBuilderUserError('Invalid suite: "%s". Valid suites are: %s' % (suite, ' '.join(self.suites))) modname = 'VMBuilder.plugins.debian.%s' % (suite, ) mod = __import__(modname, fromlist=[suite]) self.suite = getattr(mod, suite.capitalize())(self) arch = self.get_setting('arch') if arch not in self.valid_archs[self.host_arch] or \ not self.suite.check_arch_validity(arch): raise VMBuilderUserError('%s is not a valid architecture. Valid architectures are: %s' % (arch, ' '.join(self.valid_archs[self.host_arch]))) components = self.get_setting('components') if not components: self.set_config_value_list = ['main', 'contrib'] else: if type(components) is str: self.vm.components = self.vm.components.split(',') self.context.virtio_net = self.use_virtio_net() # check if the seedfile exists if one is to be used seedfile = self.context.get_setting('seedfile') if seedfile and not os.path.exists(seedfile): raise VMBuilderUserError("Seedfile '%s' does not exist" % seedfile) lang = self.get_setting('lang') # FIXME # if getattr(self.vm, 'ec2', False): # self.get_ec2_kernel() # self.get_ec2_ramdisk() # self.apply_ec2_settings() def bootstrap(self): self.suite.debootstrap() self.suite.pre_install() def configure_os(self): self.suite.install_apt_proxy() self.suite.install_sources_list() self.suite.create_devices() self.suite.prevent_daemons_starting() self.suite.mount_dev_proc() self.suite.install_extras() self.suite.create_initial_user() self.suite.install_authorized_keys() self.suite.set_timezone() self.suite.set_locale() self.suite.update() self.suite.install_sources_list(final=True) self.suite.run_in_target('apt-get', 'clean'); self.suite.unmount_volatile() self.suite.unmount_proc() self.suite.unmount_dev_pts() self.suite.unmount_dev() self.suite.unprevent_daemons_starting() self.suite.create_manifest() def configure_networking(self, nics): self.suite.config_host_and_domainname() self.suite.config_interfaces(nics) def configure_mounting(self, disks, filesystems): self.suite.install_fstab(disks, filesystems) def install(self, destdir): self.destdir = destdir self.suite.install(destdir) def install_vmbuilder_log(self, logfile, rootdir): self.suite.install_vmbuilder_log(logfile, rootdir) def post_mount(self, fs): self.suite.post_mount(fs) def use_virtio_net(self): return self.suite.virtio_net def install_bootloader_cleanup(self, chroot_dir): self.context.cancel_cleanup(self.install_bootloader_cleanup) tmpdir = '%s/tmp/vmbuilder-grub' % chroot_dir for disk in os.listdir(tmpdir): if disk != 'device.map': run_cmd('umount', os.path.join(tmpdir, disk)) shutil.rmtree(tmpdir) def install_kernel(self, destdir): self.suite.install_kernel(destdir) def install_bootloader(self, chroot_dir, disks): root_dev = VMBuilder.disk.bootpart(disks).get_grub_id() tmpdir = '/tmp/vmbuilder-grub' os.makedirs('%s%s' % (chroot_dir, tmpdir)) self.context.add_clean_cb(self.install_bootloader_cleanup) devmapfile = os.path.join(tmpdir, 'device.map') devmap = open('%s%s' % (chroot_dir, devmapfile), 'w') for (disk, id) in zip(disks, range(len(disks))): new_filename = os.path.join(tmpdir, os.path.basename(disk.filename)) open('%s%s' % (chroot_dir, new_filename), 'w').close() run_cmd('mount', '--bind', disk.filename, '%s%s' % (chroot_dir, new_filename)) st = os.stat(disk.filename) if stat.S_ISBLK(st.st_mode): for (part, part_id) in zip(disk.partitions, range(len(disk.partitions))): part_mountpnt = '%s%s%d' % (chroot_dir, new_filename, part_id+1) open(part_mountpnt, 'w').close() run_cmd('mount', '--bind', part.filename, part_mountpnt) devmap.write("(hd%d) %s\n" % (id, new_filename)) devmap.close() run_cmd('cat', '%s%s' % (chroot_dir, devmapfile)) self.suite.install_grub(chroot_dir) self.run_in_target('grub', '--device-map=%s' % devmapfile, '--batch', stdin='''root %s setup (hd0) EOT''' % root_dev) self.suite.install_menu_lst(disks) self.install_bootloader_cleanup(chroot_dir) def xen_kernel_version(self): if self.suite.xen_kernel_flavour: # if this is ec2, do not call rmadison. # this could be replaced with a method to get most recent # stable kernel, but really, this is not used at all for ec2 if hasattr(self.context, 'ec2') and self.context.ec2: logging.debug("selecting ec2 kernel") self.xen_kernel = "2.6.ec2-kernel" return self.xen_kernel if not self.xen_kernel: rmad = run_cmd('rmadison', 'linux-image-%s' % self.suite.xen_kernel_flavour) version = ['0', '0','0', '0'] for line in rmad.splitlines(): sline = line.split('|') if sline[2].strip().startswith(self.context.get_setting('suite')): vt = sline[1].strip().split('.') for i in range(4): if int(vt[i]) > int(version[i]): version = vt break if version[0] == '0': raise VMBuilderException('Something is wrong, no valid xen kernel for the suite %s found by rmadison' % self.context.suite) self.xen_kernel = '%s.%s.%s-%s' % (version[0],version[1],version[2],version[3]) return self.xen_kernel else: raise VMBuilderUserError('There is no valid xen kernel for the suite selected.') def xen_kernel_initrd_path(self, which): path = '/boot/%s-%s-%s' % (which, self.xen_kernel_version(), self.suite.xen_kernel_flavour) return path def xen_kernel_path(self): return self.xen_kernel_initrd_path('kernel') def xen_ramdisk_path(self): return self.xen_kernel_initrd_path('ramdisk') def get_ec2_kernel(self): if self.suite.ec2_kernel_info: return self.suite.ec2_kernel_info[self.context.arch] else: raise VMBuilderUserError('EC2 is not supported for the suite selected') def get_ec2_ramdisk(self): if self.suite.ec2_ramdisk_info: return self.suite.ec2_ramdisk_info[self.context.arch] else: raise VMBuilderUserError('EC2 is not supported for the suite selected') def disable_hwclock_access(self): return self.suite.disable_hwclock_access() def apply_ec2_settings(self): return self.suite.apply_ec2_settings() def has_256_bit_inode_ext3_support(self): return self.suite.has_256_bit_inode_ext3_support() def preferred_filesystem(self): return self.suite.preferred_filesystem def get_locale(): lang = os.getenv('LANG') if lang is None: return 'C' # People's $LANG looks different since lucid, but locale-gen still # wants the old format. if lang.endswith('utf8'): return lang[:-4] + 'UTF-8' return lang register_distro(Debian) vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/etch.py0000644000000000000000000000145412613023706021061 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.debian.sarge import Sarge class Etch(Sarge): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/jessie.py0000644000000000000000000000146112613023706021416 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.debian.wheezy import Wheezy class Jessie(Wheezy): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/lenny.py0000644000000000000000000000147012613023706021261 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.debian.etch import Etch class Lenny(Etch): disk_prefix = 'sd' vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/potato.py0000644000000000000000000004033512613023706021445 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import glob import logging import os import suite import shutil import tempfile import VMBuilder.disk as disk from VMBuilder.util import run_cmd from VMBuilder.exception import VMBuilderException class Potato(suite.Suite): updategrub = "/usr/sbin/update-grub" grubroot = "/usr/lib/grub" valid_flavours = { 'i386' : ['486', '586', '686-pae'], 'amd64' : ['amd64']} default_flavour = { 'i386' : '686-pae', 'amd64' : 'amd64' } disk_prefix = 'hd' xen_kernel_flavour = None virtio_net = False chpasswd_cmd = [ 'chpasswd', '--md5' ] preferred_filesystem = 'ext3' def pre_install(self): pass def check_kernel_flavour(self, arch, flavour): return flavour in self.valid_flavours[arch] def check_arch_validity(self, arch): return arch in self.valid_flavours.keys() def install(self, destdir): raise VMBuilderException('Do not call this method!') # These are still missing after the refactoring. logging.debug("Creating device.map") self.install_device_map() logging.debug("Copy host settings") self.copy_settings() if hasattr(self.context, 'ec2') and self.context.ec2: logging.debug("Configuring for ec2") self.install_ec2() def create_manifest(self): manifest = self.context.get_setting('manifest') if manifest: logging.debug("Creating manifest") manifest_contents = self.run_in_target('dpkg-query', '-W', '--showformat=${Package} ${Version}\n') fp = open(manifest, 'w') fp.write(manifest_contents) fp.close self.call_hook('fix_ownership', manifest) def update(self): self.run_in_target('apt-get', '-y', '--force-yes', 'dist-upgrade', env={ 'DEBIAN_FRONTEND' : 'noninteractive' }) def install_authorized_keys(self): ssh_key = self.context.get_setting('ssh-key') if ssh_key: os.mkdir('%s/root/.ssh' % self.context.chroot_dir, 0700) shutil.copy(ssh_key, '%s/root/.ssh/authorized_keys' % self.context.chroot_dir) os.chmod('%s/root/.ssh/authorized_keys' % self.context.chroot_dir, 0644) user = self.context.get_setting('user') ssh_user_key = self.context.get_setting('ssh-user-key') if ssh_user_key: os.mkdir('%s/home/%s/.ssh' % (self.context.chroot_dir, user), 0700) shutil.copy(ssh_user_key, '%s/home/%s/.ssh/authorized_keys' % (self.context.chroot_dir, user)) os.chmod('%s/home/%s/.ssh/authorized_keys' % (self.context.chroot_dir, user), 0644) self.run_in_target('chown', '-R', '%s:%s' % ((user,)*2), '/home/%s/.ssh/' % (user)) if ssh_user_key or ssh_key: addpkg = self.context.get_setting('addpkg') addpkg += ['openssh-server'] self.context.set_setting('addpkg', addpkg) def mount_dev_proc(self): run_cmd('mount', '--bind', '/dev', '%s/dev' % self.context.chroot_dir) self.context.add_clean_cb(self.unmount_dev) run_cmd('mount', '--bind', '/dev/pts', '%s/dev/pts' % self.context.chroot_dir) self.context.add_clean_cb(self.unmount_dev_pts) self.run_in_target('mount', '-t', 'proc', 'proc', '/proc') self.context.add_clean_cb(self.unmount_proc) def unmount_proc(self): self.context.cancel_cleanup(self.unmount_proc) run_cmd('umount', '%s/proc' % self.context.chroot_dir) def unmount_dev_pts(self): self.context.cancel_cleanup(self.unmount_dev_pts) run_cmd('umount', '%s/dev/pts' % self.context.chroot_dir) def unmount_dev(self): self.context.cancel_cleanup(self.unmount_dev) run_cmd('umount', '%s/dev' % self.context.chroot_dir) def update_passwords(self): # Set the user password, using md5 user = self.context.get_setting('user') passwd = self.context.get_setting('pass') self.run_in_target(stdin=('%s:%s\n' % (user, passwd)), *self.chpasswd_cmd) # Lock root account only if we didn't set the root password rootpass = self.context.get_setting('rootpass') if rootpass: self.run_in_target(stdin=('%s:%s\n' % ('root', rootpass)), *self.chpasswd_cmd) else: self.run_in_target('usermod', '-L', 'root') lock_user = self.context.get_setting('lock-user') if lock_user: logging.info('Locking %s' % (user, )) self.run_in_target('usermod', '-L', user) def create_initial_user(self): uid = self.context.get_setting('uid') name = self.context.get_setting('name') user = self.context.get_setting('user') if uid: self.run_in_target('adduser', '--disabled-password', '--uid', uid, '--gecos', name, user) else: self.run_in_target('adduser', '--disabled-password', '--gecos', name, user) self.run_in_target('addgroup', '--system', 'admin') self.run_in_target('adduser', user, 'admin') self.install_from_template('/etc/sudoers', 'sudoers') for group in ['adm', 'audio', 'cdrom', 'dialout', 'floppy', 'video', 'plugdev', 'dip', 'netdev', 'powerdev', 'lpadmin', 'scanner']: self.run_in_target('adduser', user, group, ignore_fail=True) self.update_passwords() def kernel_name(self): flavour = self.context.get_setting('flavour') arch = self.context.get_setting('arch') return 'linux-image-%s' % (flavour or self.default_flavour[arch],) def config_host_and_domainname(self): hostname = self.context.get_setting('hostname') domain = self.context.get_setting('domain') self.context.install_file('/etc/hostname', hostname) self.install_from_template('/etc/hosts', 'etc_hosts', { 'hostname' : hostname, 'domain' : domain }) def config_interfaces(self, nics): self.install_from_template('/etc/network/interfaces', 'interfaces', { 'ip' : nics[0].type == 'dhcp' and 'dhcp' or nics[0].ip, 'mask' : nics[0].netmask, 'net' : nics[0].network, 'bcast' : nics[0].broadcast, 'gw' : nics[0].gateway, 'dns' : nics[0].dns, 'domain' : self.context.get_setting('domain') }) def unprevent_daemons_starting(self): os.unlink('%s/usr/sbin/policy-rc.d' % self.context.chroot_dir) def prevent_daemons_starting(self): os.chmod(self.install_from_template('/usr/sbin/policy-rc.d', 'nostart-policy-rc.d'), 0755) def seed(self, seedfile): """Seed debconf with the contents of a seedfile""" logging.info('Seeding with "%s"' % seedfile) self.run_in_target('debconf-set-selections', stdin=open(seedfile, 'r').read()) def install_extras(self): seedfile = self.context.get_setting('seedfile') if seedfile: self.seed(seedfile) addpkg = self.context.get_setting('addpkg') removepkg = self.context.get_setting('removepkg') if not addpkg and not removepkg: return cmd = ['apt-get', 'install', '-y', '--force-yes'] cmd += addpkg or [] cmd += ['%s-' % pkg for pkg in removepkg or []] self.run_in_target(env={ 'DEBIAN_FRONTEND' : 'noninteractive' }, *cmd) def unmount_volatile(self): for mntpnt in glob.glob('%s/lib/modules/*/volatile' % self.context.chroot_dir): logging.debug("Unmounting %s" % mntpnt) run_cmd('sleep', '10') run_cmd('umount', mntpnt) def install_menu_lst(self, disks): self.run_in_target(self.updategrub, '-y') self.mangle_grub_menu_lst(disks) self.run_in_target(self.updategrub) self.run_in_target('grub-set-default', '0') def mangle_grub_menu_lst(self, disks): rootdev = disk.rootpart(disks) bootdev = disk.bootpart(disks) run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=UUID=%s rw/g' % rootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.context.chroot_dir) run_cmd('sed', '-ie', 's/^# groot.*/# groot=(hd0,0)/g', '%s/boot/grub/menu.lst' % self.context.chroot_dir) run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.context.chroot_dir) def install_sources_list(self, final=False): if final: mirror = updates_mirror = self.context.get_setting('mirror') security_mirror = self.context.get_setting('security-mirror') else: mirror, updates_mirror, security_mirror = self.install_mirrors() components = self.context.get_setting('components') suite = self.context.get_setting('suite') self.install_from_template('/etc/apt/sources.list', 'sources.list', { 'mirror' : mirror, 'security_mirror' : security_mirror, 'updates_mirror' : updates_mirror, 'components' : components, 'suite' : suite }) # If setting up the final mirror, allow apt-get update to fail # (since we might be on a complete different network than the # final vm is going to be on). self.run_in_target('apt-get', 'update', ignore_fail=final) def install_apt_proxy(self): proxy = self.context.get_setting('proxy') if proxy is not None: self.context.install_file('/etc/apt/apt.conf', '// Proxy added by vmbuilder\nAcquire::http { Proxy "%s"; };' % proxy) def fstab(self): retval = '''# /etc/fstab: static file system information. # # proc /proc proc defaults 0 0 ''' parts = disk.get_ordered_partitions(self.context.disks) for part in parts: retval += "UUID=%-40s %15s %7s %15s %d %d\n" % (part.fs.uuid, part.fs.mntpnt, part.fs.fstab_fstype(), part.fs.fstab_options(), 0, 0) return retval def install_device_map(self): self.install_from_template('/boot/grub/device.map', 'devicemap', { 'prefix' : self.disk_prefix }) def debootstrap(self): arch = self.context.get_setting('arch') cmd = ['/usr/sbin/debootstrap', '--arch=%s' % arch] variant = self.context.get_setting('variant') if variant: cmd += ['--variant=%s' % variant] debootstrap_tarball = self.context.get_setting('debootstrap-tarball') if debootstrap_tarball: cmd += ['--unpack-tarball=%s' % debootstrap_tarball] suite = self.context.get_setting('suite') cmd += [suite, self.context.chroot_dir, self.debootstrap_mirror()] kwargs = { 'env' : { 'DEBIAN_FRONTEND' : 'noninteractive' } } proxy = self.context.get_setting('proxy') if proxy: kwargs['env']['http_proxy'] = proxy run_cmd(*cmd, **kwargs) def debootstrap_mirror(self): iso = self.context.get_setting('iso') if iso: isodir = tempfile.mkdtemp() self.context.add_clean_cb(lambda:os.rmdir(isodir)) run_cmd('mount', '-o', 'loop', '-t', 'iso9660', iso, isodir) self.context.add_clean_cmd('umount', isodir) self.iso_mounted = True return 'file://%s' % isodir else: return self.install_mirrors()[0] def install_mirrors(self): install_mirror = self.context.get_setting('install-mirror') if install_mirror: mirror = install_mirror else: mirror = self.context.get_setting('mirror') updates_mirror = mirror install_security_mirror = self.context.get_setting('install-security-mirror') if install_security_mirror: security_mirror = install_security_mirror else: security_mirror = self.context.get_setting('security-mirror') return (mirror, updates_mirror, security_mirror) def install_kernel(self, destdir): run_cmd('chroot', destdir, 'apt-get', '--force-yes', '-y', 'install', self.kernel_name(), env={ 'DEBIAN_FRONTEND' : 'noninteractive' }) def install_grub(self, chroot_dir): self.install_from_template('/etc/kernel-img.conf', 'kernelimg', { 'updategrub' : self.updategrub }) arch = self.context.get_setting('arch') self.run_in_target('apt-get', '--force-yes', '-y', 'install', 'grub', env={ 'DEBIAN_FRONTEND' : 'noninteractive' }) run_cmd('rsync', '-a', '%s%s/%s/' % (chroot_dir, self.grubroot, arch == 'amd64' and 'x86_64-pc' or 'i386-pc'), '%s/boot/grub/' % chroot_dir) def create_devices(self): pass # FIXME # import VMBuilder.plugins.xen # if isinstance(self.context.hypervisor, VMBuilder.plugins.xen.Xen): # self.run_in_target('mknod', '/dev/xvda', 'b', '202', '0') # self.run_in_target('mknod', '/dev/xvda1', 'b', '202', '1') # self.run_in_target('mknod', '/dev/xvda2', 'b', '202', '2') # self.run_in_target('mknod', '/dev/xvda3', 'b', '202', '3') # self.run_in_target('mknod', '/dev/xvc0', 'c', '204', '191') def install_from_template(self, *args, **kwargs): return self.context.install_from_template(*args, **kwargs) def run_in_target(self, *args, **kwargs): return self.context.run_in_target(*args, **kwargs) def copy_to_target(self, infile, destpath): logging.debug("Copying %s on host to %s in guest" % (infile, destpath)) dir = '%s/%s' % (self.destdir, os.path.dirname(destpath)) if not os.path.isdir(dir): os.makedirs(dir) if os.path.isdir(infile): shutil.copytree(infile, '%s/%s' % (self.destdir, destpath)) else: shutil.copy(infile, '%s/%s' % (self.destdir, destpath)) def post_mount(self, fs): if fs.mntpnt == '/': logging.debug("Creating /var/run in root filesystem") os.makedirs('%s/var/run' % fs.mntpath) logging.debug("Creating /var/lock in root filesystem") os.makedirs('%s/var/lock' % fs.mntpath) def set_locale(self): lang = self.context.get_setting('lang') if lang: self.install_from_template('/etc/default/locale', 'locale', { 'lang' : lang }) if lang != "C": self.run_in_target('locale-gen', lang) self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'libc6') self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'locales') def install_vmbuilder_log(self, logfile, rootdir): shutil.copy(logfile, '%s/var/log/vmbuilder-install.log' % (rootdir,)) def set_timezone(self): timezone = self.context.get_setting('timezone') if timezone: self.install_from_template('/etc/timezone', 'timezone', { 'timezone' : timezone }) self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'locales') def install_ec2(self): if self.context.ec2: logging.debug('This suite does not support ec2') def disable_hwclock_access(self): fp = open('%s/etc/default/rcS' % self.destdir, 'a') fp.write('HWCLOCKACCESS=no') fp.close() def has_256_bit_inode_ext3_support(self): return False vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/sarge.py0000644000000000000000000000145512613023706021240 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.debian.woody import Woody class Sarge(Woody): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/squeeze.py0000644000000000000000000000145712613023706021622 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.debian.lenny import Lenny class Squeeze(Lenny): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/stretch.py0000644000000000000000000000146212613023706021611 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.debian.jessie import Jessie class Stretch(Jessie): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/suite.py0000644000000000000000000000211512613023706021262 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # class Suite(object): def __init__(self, context): self.context = context self.isodir = '/media/vmbuilder_inst_image' self.iso_mounted = False def check_arch_validity(self, arch): """Checks whether the given arch is valid for this suite""" raise NotImplemented('Suite subclasses need to implement the check_arch_validity method') vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/0000755000000000000000000000000012613023706021556 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/wheezy.py0000644000000000000000000000146412613023706021452 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.debian.squeeze import Squeeze class Wheezy(Squeeze): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/woody.py0000644000000000000000000000146012613023706021274 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.debian.potato import Potato class Woody(Potato): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/devicemap.tmpl0000644000000000000000000000012112613023706024403 0ustar 00000000000000#for $disk in $disks $disk.get_grub_id() /dev/$prefix$disk.devletters() #end for vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/etc_hosts.tmpl0000644000000000000000000000040312613023706024444 0ustar 00000000000000127.0.0.1 localhost 127.0.1.1 $hostname.$domain $hostname # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/initctl-stub.tmpl0000644000000000000000000000010212613023706025066 0ustar 00000000000000#!/bin/sh echo echo "Warning: Fake initctl called, doing nothing" vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/interfaces.tmpl0000644000000000000000000000107112613023706024576 0ustar 00000000000000# This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). # The loopback network interface auto lo iface lo inet loopback # The primary network interface auto eth0 #if $ip == 'dhcp' iface eth0 inet dhcp #else iface eth0 inet static address $ip netmask $mask network $net broadcast $bcast gateway $gw # dns-* options are implemented by the resolvconf package, if installed dns-nameservers $dns dns-search $domain #end if vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/is-compat-env.tmpl0000644000000000000000000000014512613023706025136 0ustar 00000000000000# this is read by ec2-is-compat-env to determine if this is an # ec2 compatible environment compat=1 vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/kernelimg.tmpl0000644000000000000000000000024512613023706024432 0ustar 00000000000000do_symlinks = yes relative_links = yes do_bootfloppy = no do_initrd = yes link_in_boot = no postinst_hook = $updategrub postrm_hook = $updategrub do_bootloader = no vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/locale.tmpl0000644000000000000000000000001512613023706023707 0ustar 00000000000000LANG="$lang" vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/nostart-policy-rc.d.tmpl0000644000000000000000000000037612613023706026275 0ustar 00000000000000#!/bin/sh while true; do case "$1" in -*) shift ;; makedev) exit 0 ;; x11-common) exit 0 ;; *) exit 101 ;; esac done vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/sources.list.tmpl0000644000000000000000000000030512613023706025107 0ustar 00000000000000deb $mirror $suite #slurp #echo ' '.join($components) deb $updates_mirror $suite-updates #slurp #echo ' '.join($components) deb $security_mirror $suite/updates #slurp #echo ' '.join($components) vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/sudoers.tmpl0000644000000000000000000000076012613023706024143 0ustar 00000000000000# /etc/sudoers # # This file MUST be edited with the 'visudo' command as root. # # See the man page for details on how to write a sudoers file. # Defaults Defaults !lecture,tty_tickets,!fqdn # Uncomment to allow members of group sudo to not need a password # %sudo ALL=NOPASSWD: ALL # Host alias specification # User alias specification # Cmnd alias specification # User privilege specification root ALL=(ALL) ALL # Members of the admin group may gain root privileges %admin ALL=(ALL) ALL vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/timezone.tmpl0000644000000000000000000000001212613023706024277 0ustar 00000000000000$timezone vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/upstart.tmpl0000644000000000000000000000047612613023706024165 0ustar 00000000000000# $console - getty # # This service maintains a getty on $console from the point the system is # started until it is shut down again. start on stopped rc2 start on stopped rc3 start on stopped rc4 start on stopped rc5 stop on runlevel 0 stop on runlevel 1 stop on runlevel 6 respawn exec /sbin/getty 38400 $console vm-builder-0.12.4+bzr494/VMBuilder/plugins/debian/templates/xen-ld-so-conf.tmpl0000644000000000000000000000002112613023706025176 0ustar 00000000000000hwcap 0 nosegneg vm-builder-0.12.4+bzr494/VMBuilder/plugins/ec2/__init__.py0000644000000000000000000001702411337261313021124 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import VMBuilder from VMBuilder import register_distro_plugin, register_hypervisor_plugin, Plugin, VMBuilderUserError, VMBuilderException from VMBuilder.util import run_cmd import logging import os class EC2(Plugin): name = 'EC2 integration' def register_options(self): # Don't pretend like we can do EC2 if not isinstance(self.context.hypervisor, VMBuilder.plugins.xen.Xen): return group = self.context.setting_group('EC2 integation') group.add_option('--ec2', action='store_true', help='Build for EC2') group.add_option('--ec2-name','--ec2-prefix', metavar='EC2_NAME', help='Name for the EC2 image.') group.add_option('--ec2-cert', metavar='CERTFILE', help='PEM encoded public certificate for EC2.') group.add_option('--ec2-key', metavar='KEYFILE', help='PEM encoded private key for EC2.') group.add_option('--ec2-user', metavar='AWS_ACCOUNT', help='EC2 user ID (a.k.a. AWS account number, not AWS access key ID).') group.add_option('--ec2-bucket', metavar='BUCKET', help='S3 bucket to hold the AMI.') group.add_option('--ec2-access-key', metavar='ACCESS_ID', help='AWS access key ID.') group.add_option('--ec2-secret-key', metavar='SECRET_ID', help='AWS secret access key.') group.add_option('--ec2-kernel','--ec2-aki', metavar='AKI', help='EC2 AKI (kernel) to use.') group.add_option('--ec2-ramdisk','--ec2-ari', metavar='ARI', help='EC2 ARI (ramdisk) to use.') group.add_option('--ec2-version', metavar='EC2_VER', help='Specify the EC2 image version.') group.add_option('--ec2-landscape', action='store_true', help='Install landscape client support') group.add_option('--ec2-bundle', action='store_true', help='Bundle the instance') group.add_option('--ec2-upload', action='store_true', help='Upload the instance') group.add_option('--ec2-register', action='store_true', help='Register the instance') self.context.register_setting_group(group) def preflight_check(self): if not getattr(self.vm, 'ec2', False): return True if not self.context.hypervisor.name == 'Xen': raise VMBuilderUserError('When building for EC2 you must use the xen hypervisor.') if self.context.ec2_bundle: try: run_cmd('ec2-ami-tools-version') except VMBuilderException, e: raise VMBuilderUserError('You need to have the Amazon EC2 AMI tools installed') if not self.context.ec2_name: raise VMBuilderUserError('When building for EC2 you must supply the name for the image.') if not self.context.ec2_cert: if "EC2_CERT" in os.environ: self.context.ec2_cert = os.environ["EC2_CERT"] else: raise VMBuilderUserError('When building for EC2 you must provide your PEM encoded public key certificate') if not self.context.ec2_key: if "EC2_PRIVATE_KEY" in os.environ: self.context.ec2_key = os.environ["EC2_PRIVATE_KEY"] else: raise VMBuilderUserError('When building for EC2 you must provide your PEM encoded private key file') if not self.context.ec2_user: raise VMBuilderUserError('When building for EC2 you must provide your EC2 user ID (your AWS account number, not your AWS access key ID)') if not self.context.ec2_kernel: self.context.ec2_kernel = self.vm.distro.get_ec2_kernel() logging.debug('%s - to be used for AKI.' %(self.context.ec2_kernel)) if not self.context.ec2_ramdisk: self.context.ec2_ramdisk = self.vm.distro.ec2_ramdisk_id() logging.debug('%s - to be use for the ARI.' %(self.context.ec2_ramdisk)) if self.context.ec2_upload: if not self.context.ec2_bucket: raise VMBuilderUserError('When building for EC2 you must provide an S3 bucket to hold the AMI') if not self.context.ec2_access_key: raise VMBuilderUserError('When building for EC2 you must provide your AWS access key ID.') if not self.context.ec2_secret_key: raise VMBuilderUserError('When building for EC2 you must provide your AWS secret access key.') if not self.context.ec2_version: raise VMBuilderUserError('When building for EC2 you must provide version info.') if not self.context.addpkg: self.context.addpkg = [] if self.context.ec2_landscape: logging.info('Installing landscape support') self.context.addpkg += ['landscape-client'] def post_install(self): if not getattr(self.vm, 'ec2', False): return logging.info("Running ec2 postinstall") self.install_from_template('/etc/ec2_version', 'ec2_version', { 'version' : self.context.ec2_version } ) self.install_from_template('/etc/ssh/sshd_config', 'sshd_config') self.install_from_template('/etc/sudoers', 'sudoers') if self.context.ec2_landscape: self.install_from_template('/etc/default/landscape-client', 'landscape_client') self.context.distro.disable_hwclock_access() def deploy(self): if not getattr(self.vm, 'ec2', False): return False if self.context.ec2_bundle: logging.info("Building EC2 bundle") bundle_cmdline = ['ec2-bundle-image', '--image', self.context.filesystems[0].filename, '--cert', self.vm.ec2_cert, '--privatekey', self.vm.ec2_key, '--user', self.vm.ec2_user, '--prefix', self.vm.ec2_name, '-r', ['i386', 'x86_64'][self.vm.arch == 'amd64'], '-d', self.vm.workdir, '--kernel', self.vm.ec2_kernel, '--ramdisk', self.vm.ec2_ramdisk] run_cmd(*bundle_cmdline) manifest = '%s/%s.manifest.xml' % (self.context.workdir, self.vm.ec2_name) if self.context.ec2_upload: logging.info("Uploading EC2 bundle") upload_cmdline = ['ec2-upload-bundle', '--retry', '--manifest', manifest, '--bucket', self.context.ec2_bucket, '--access-key', self.vm.ec2_access_key, '--secret-key', self.vm.ec2_secret_key] run_cmd(*upload_cmdline) if self.context.ec2_register: from boto.ec2.connection import EC2Connection conn = EC2Connection(self.context.ec2_access_key, self.vm.ec2_secret_key) amiid = conn.register_image('%s/%s.manifest.xml' % (self.context.ec2_bucket, self.vm.ec2_name)) print 'Image registered as %s' % amiid else: self.context.result_files.append(manifest) else: self.context.result_files.append(self.vm.filesystems[0].filename) return True #register_plugin(EC2) vm-builder-0.12.4+bzr494/VMBuilder/plugins/ec2/templates/0000755000000000000000000000000011106347351021006 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/ec2/templates/ec2_version.tmpl0000644000000000000000000000001111202346500024102 0ustar 00000000000000$version vm-builder-0.12.4+bzr494/VMBuilder/plugins/ec2/templates/landscape_client.tmpl0000644000000000000000000000001011207512367025166 0ustar 00000000000000CLOUD=1 vm-builder-0.12.4+bzr494/VMBuilder/plugins/ec2/templates/sshd_config.tmpl0000644000000000000000000000352011202350111024153 0ustar 00000000000000# Package generated configuration file # See the sshd(8) manpage for details # What ports, IPs and protocols we listen for Port 22 # Use these options to restrict which interfaces/protocols sshd will bind to #ListenAddress :: #ListenAddress 0.0.0.0 Protocol 2 # HostKeys for protocol version 2 HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_dsa_key #Privilege Separation is turned on for security UsePrivilegeSeparation yes # Lifetime and size of ephemeral version 1 server key KeyRegenerationInterval 3600 ServerKeyBits 768 # Logging SyslogFacility AUTH LogLevel INFO # Authentication: LoginGraceTime 120 PermitRootLogin yes StrictModes yes RSAAuthentication yes PubkeyAuthentication yes #AuthorizedKeysFile %h/.ssh/authorized_keys # Don't read the user's ~/.rhosts and ~/.shosts files IgnoreRhosts yes # For this to work you will also need host keys in /etc/ssh_known_hosts RhostsRSAAuthentication no # similar for protocol version 2 HostbasedAuthentication no # Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication #IgnoreUserKnownHosts yes # To enable empty passwords, change to yes (NOT RECOMMENDED) PermitEmptyPasswords no # Change to yes to enable challenge-response passwords (beware issues with # some PAM modules and threads) ChallengeResponseAuthentication no # Change to no to disable tunnelled clear text passwords PasswordAuthentication no # Kerberos options #KerberosAuthentication no #KerberosGetAFSToken no #KerberosOrLocalPasswd yes #KerberosTicketCleanup yes # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes X11Forwarding yes X11DisplayOffset 10 PrintMotd no PrintLastLog yes TCPKeepAlive yes #UseLogin no #MaxStartups 10:30:60 #Banner /etc/issue.net # Allow client to pass locale environment variables AcceptEnv LANG LC_* Subsystem sftp /usr/lib/openssh/sftp-server UsePAM yes vm-builder-0.12.4+bzr494/VMBuilder/plugins/ec2/templates/sudoers.tmpl0000644000000000000000000000125011256442650023372 0ustar 00000000000000# /etc/sudoers # # This file MUST be edited with the 'visudo' command as root. # # See the man page for details on how to write a sudoers file. # Defaults env_reset # Host alias specification # User alias specification # Cmnd alias specification # User privilege specification root ALL=(ALL) ALL # Uncomment to allow members of group sudo to not need a password # (Note that later entries override this, so you might need to move # it further down) # %sudo ALL=NOPASSWD: ALL # Members of the admin group may gain root privileges %admin ALL=(ALL) ALL # ubuntu user is default user in ec2-images. # It needs passwordless sudo functionality. ubuntu ALL=(ALL) NOPASSWD:ALL vm-builder-0.12.4+bzr494/VMBuilder/plugins/firstscripts/__init__.py0000644000000000000000000000626511370770221023217 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder import register_distro_plugin, Plugin, VMBuilderUserError import logging import os class Firstscripts(Plugin): """ Plugin to provide --firstboot and --firstlogin scripts capabilities """ name = 'First-Scripts plugin' def register_options(self): group = self.setting_group('Scripts') group.add_setting('firstboot', metavar='PATH', help='Specify a script that will be copied into the guest and executed the first time the machine boots. This script must not be interactive.') group.add_setting('firstlogin', metavar='PATH', help='Specify a script that will be copied into the guest and will be executed the first time the user logs in. This script can be interactive.') def preflight_check(self): firstboot = self.context.get_setting('firstboot') if firstboot: logging.debug("Checking if firstboot script %s exists" % (firstboot,)) if not(os.path.isfile(firstboot) and firstboot.startswith('/')): raise VMBuilderUserError('The path to the first-boot script is invalid: %s. Make sure you are providing a full path.' % firstboot) firstlogin = self.context.get_setting('firstlogin') if firstlogin: logging.debug("Checking if first login script %s exists" % (firstlogin,)) if not(os.path.isfile(firstlogin) and firstlogin.startswith('/')): raise VMBuilderUserError('The path to the first-login script is invalid: %s. Make sure you are providing a full path.' % firstlogin) def post_install(self): firstboot = self.context.get_setting('firstboot') if firstboot: logging.debug("Installing firstboot script %s" % (firstboot,)) self.context.install_file('/root/firstboot.sh', source=firstboot, mode=0700) os.rename('%s/etc/rc.local' % self.context.chroot_dir, '%s/etc/rc.local.orig' % self.context.chroot_dir) self.install_from_template('/etc/rc.local', 'firstbootrc', mode=0755) firstlogin = self.context.get_setting('firstlogin') if firstlogin: logging.debug("Installing first login script %s" % (firstlogin,)) self.context.install_file('/root/firstlogin.sh', source=firstlogin, mode=0755) os.rename('%s/etc/bash.bashrc' % self.context.chroot_dir, '%s/etc/bash.bashrc.orig' % self.context.chroot_dir) self.install_from_template('/etc/bash.bashrc', 'firstloginrc') return True register_distro_plugin(Firstscripts) vm-builder-0.12.4+bzr494/VMBuilder/plugins/firstscripts/templates/0000755000000000000000000000000011070007023023061 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/firstscripts/templates/firstbootrc.tmpl0000644000000000000000000000030711070007023026317 0ustar 00000000000000#!/bin/sh -e #execute firstboot.sh only once if [ ! -e /root/firstboot_done ]; then if [ -e /root/firstboot.sh ]; then /root/firstboot.sh fi touch /root/firstboot_done fi exit 0 vm-builder-0.12.4+bzr494/VMBuilder/plugins/firstscripts/templates/firstloginrc.tmpl0000644000000000000000000000047511071147606026507 0ustar 00000000000000#!/bin/sh -e #execute firstlogin.sh only once if [ ! -e /root/firstlogin_done ]; then if [ -e /root/firstlogin.sh ]; then /root/firstlogin.sh fi # This part should not be necessary any more # sudo dpkg-reconfigure -p critical console-setup &> /dev/null sudo touch /root/firstlogin_done fi vm-builder-0.12.4+bzr494/VMBuilder/plugins/kvm/__init__.py0000644000000000000000000000134011213733731021243 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import vm vm-builder-0.12.4+bzr494/VMBuilder/plugins/kvm/vm.py0000644000000000000000000000476011447111021020126 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder import register_hypervisor, Hypervisor import VMBuilder import os import stat class KVM(Hypervisor): name = 'KVM' arg = 'kvm' filetype = 'qcow2' preferred_storage = VMBuilder.hypervisor.STORAGE_DISK_IMAGE needs_bootloader = True def register_options(self): group = self.setting_group('VM settings') group.add_setting('mem', extra_args=['-m'], type='int', default=128, help='Assign MEM megabytes of memory to the guest vm. [default: %default]') group.add_setting('cpus', type='int', default=1, help='Assign NUM cpus to the guest vm. [default: %default]') def convert(self, disks, destdir): self.imgs = [] self.cmdline = ['kvm', '-m', str(self.context.get_setting('mem'))] self.cmdline += ['-smp', str(self.context.get_setting('cpus'))] for disk in disks: img_path = disk.convert(destdir, self.filetype) self.imgs.append(img_path) self.call_hooks('fix_ownership', img_path) self.cmdline += ['-drive', 'file=%s' % os.path.basename(img_path)] self.cmdline += ['"$@"'] def deploy(self, destdir): # No need create run script if vm is registered with libvirt if self.context.get_setting('libvirt'): return script = '%s/run.sh' % destdir fp = open(script, 'w') fp.write("#!/bin/sh\n\nexec %s\n" % ' '.join(self.cmdline)) fp.close() os.chmod(script, stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH) self.call_hooks('fix_ownership', script) def libvirt_domain_type_name(self): return 'kvm' class QEMu(KVM): name = 'QEMu' arg = 'qemu' def libvirt_domain_type_name(self): return 'qemu' register_hypervisor(KVM) register_hypervisor(QEMu) vm-builder-0.12.4+bzr494/VMBuilder/plugins/libvirt/__init__.py0000644000000000000000000000755211600670020022123 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder import register_hypervisor_plugin, Plugin, VMBuilderUserError import VMBuilder.util class Libvirt(Plugin): name = 'libvirt integration' def register_options(self): group = self.setting_group('libvirt integration') group.add_setting('libvirt', metavar='URI', help='Add VM to given URI') group.add_setting('bridge', metavar="BRIDGE", help='Set up bridged network connected to BRIDGE.') group.add_setting('network', metavar='NETWORK', default='default', help='Set up a network connection to virtual network NETWORK.') def all_domains(self): # This does not seem to work when any domain is already running return self.conn.listDefinedDomains() + [self.conn.lookupByID(id).name() for id in self.conn.listDomainsID()] def preflight_check(self): libvirt_uri = self.get_setting('libvirt') if not libvirt_uri: return True if not self.context.name == 'KVM' and not self.context.name == 'QEMu': raise VMBuilderUserError('The libvirt plugin is only equiped to work with KVM and QEMu at the moment.') import libvirt import xml.etree.ElementTree self.conn = libvirt.open(libvirt_uri) e = xml.etree.ElementTree.fromstring(self.conn.getCapabilities()) if not 'hvm' in [x.text for x in e.getiterator('os_type')]: raise VMBuilderUserError('libvirt does not seem to want to accept hvm domains') hostname = self.context.distro.get_setting('hostname') if hostname in self.all_domains() and not self.context.overwrite: raise VMBuilderUserError('Domain %s already exists at %s' % (hostname, libvirt_uri)) def deploy(self, destdir): libvirt_uri = self.get_setting('libvirt') if not libvirt_uri: # Not for us return False hostname = self.context.distro.get_setting('hostname') tmpl_ctxt = { 'mem': self.context.get_setting('mem'), 'cpus': self.context.get_setting('cpus'), 'bridge' : self.context.get_setting('bridge'), 'mac' : self.context.get_setting('mac'), 'network' : self.context.get_setting('network'), 'mac' : self.context.get_setting('mac'), 'virtio_net' : self.context.distro.use_virtio_net(), 'disks' : self.context.disks, 'filesystems' : self.context.filesystems, 'hostname' : hostname, 'domain_type' : self.context.libvirt_domain_type_name() } if self.context.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: vmxml = VMBuilder.util.render_template('libvirt', self.context, 'libvirtxml_fsimage', tmpl_ctxt) else: vmxml = VMBuilder.util.render_template('libvirt', self.context, 'libvirtxml', tmpl_ctxt) if hostname in self.all_domains() and not self.context.overwrite: raise VMBuilderUserError('Domain %s already exists at %s' % (hostname, libvirt_uri)) else: self.conn.defineXML(vmxml) return True register_hypervisor_plugin(Libvirt) vm-builder-0.12.4+bzr494/VMBuilder/plugins/libvirt/templates/0000755000000000000000000000000011064415455022014 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/libvirt/templates/libvirtxml.tmpl0000644000000000000000000000200512162120012025061 0ustar 00000000000000 $hostname #echo int($mem) * 1024 # $cpus hvm destroy restart destroy /usr/bin/kvm #if $bridge #else #end if #if $mac #end if #if $virtio_net #end if #for $disk in $disks #if $disk.format_type != None #end if #end for vm-builder-0.12.4+bzr494/VMBuilder/plugins/libvirt/templates/libvirtxml_fsimage.tmpl0000644000000000000000000000146711475652530026614 0ustar 00000000000000 $hostname #echo $mem * 1024 # $cpus hvm destroy restart destroy /usr/bin/kvm #for $fs in $filesystems #if $fs.format_type != None #end if #end for vm-builder-0.12.4+bzr494/VMBuilder/plugins/network/__init__.py0000644000000000000000000001467011341435560022152 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Virtual network management import logging import re import struct import socket from VMBuilder import register_hypervisor_plugin, register_distro_plugin from VMBuilder.plugins import Plugin from VMBuilder.exception import VMBuilderUserError def validate_mac(mac): valid_mac_address = re.compile("^([0-9a-f]{2}:){5}([0-9a-f]{2})$", re.IGNORECASE) if not valid_mac_address.match(mac): return False else: return True def numeric_to_dotted_ip(numeric_ip): return socket.inet_ntoa(struct.pack('I', numeric_ip)) def dotted_to_numeric_ip(dotted_ip): try: return struct.unpack('I', socket.inet_aton(dotted_ip))[0] except socket.error: raise VMBuilderUserError('%s is not a valid ip address' % dotted_ip) def guess_mask_from_ip(numip): first_octet = numip & 0xFF if (first_octet > 0) and (first_octet <= 127): return 0xFF elif (first_octet > 128) and (first_octet < 192): return 0xFFFF elif (first_octet < 224): return 0xFFFFFF else: raise VMBuilderUserError('Could not guess network class of: %s' % numeric_to_dotted_ip(numip)) def calculate_net_address_from_ip_and_netmask(ip, netmask): return ip & netmask def calculate_broadcast_address_from_ip_and_netmask(net, mask): return net + (mask ^ 0xFFFFFFFF) def guess_gw_from_ip(ip): return ip + 0x01000000 class NetworkDistroPlugin(Plugin): def register_options(self): group = self.setting_group('Network') domainname = '.'.join(socket.gethostbyname_ex(socket.gethostname())[0].split('.')[1:]) or "defaultdomain" group.add_setting('domain', metavar='DOMAIN', default=domainname, help='Set DOMAIN as the domain name of the guest [default: %default].') def preflight_check(self): domain = self.context.get_setting('domain') if domain == '': raise VMBuilderUserError('Domain is undefined and host has no domain set.') class NetworkHypervisorPlugin(Plugin): def register_options(self): group = self.setting_group('Network') group.add_setting('ip', metavar='ADDRESS', default='dhcp', help='IP address in dotted form [default: %default].') group.add_setting('mac', metavar='MAC', help='MAC address of the guest [default: random].') group.add_setting('mask', metavar='VALUE', help='IP mask in dotted form [default: based on ip setting]. Ignored if ip is not specified.') group.add_setting('net', metavar='ADDRESS', help='IP net address in dotted form [default: based on ip setting]. Ignored if ip is not specified.') group.add_setting('bcast', metavar='VALUE', help='IP broadcast in dotted form [default: based on ip setting]. Ignored if ip is not specified.') group.add_setting('gw', metavar='ADDRESS', help='Gateway (router) address in dotted form [default: based on ip setting (first valid address in the network)]. Ignored if ip is not specified.') group.add_setting('dns', metavar='ADDRESS', help='DNS address in dotted form [default: based on ip setting (first valid address in the network)] Ignored if ip is not specified.') def preflight_check(self): """ Validate the ip configuration given and set defaults """ ip = self.context.get_setting('ip') logging.debug("ip: %s" % ip) mac = self.context.get_setting('mac') if mac: if not validate_mac(mac): raise VMBuilderUserError("Malformed MAC address entered: %s" % mac) if ip != 'dhcp': # num* are numeric representations numip = dotted_to_numeric_ip(ip) mask = self.context.get_setting('mask') if not mask: nummask = guess_mask_from_ip(numip) else: nummask = dotted_to_numeric_ip(mask) numnet = calculate_net_address_from_ip_and_netmask(numip, nummask) net = self.context.get_setting('net') if not net: self.context.set_setting_default('net', numeric_to_dotted_ip(numnet)) bcast = self.context.get_setting('bcast') if not bcast: numbcast = calculate_broadcast_address_from_ip_and_netmask(numnet, nummask) self.context.set_setting_default('bcast', numeric_to_dotted_ip(numbcast)) gw = self.context.get_setting('gw') if not gw: numgw = guess_gw_from_ip(numip) self.context.set_setting_default('gw', numeric_to_dotted_ip(numgw)) dns = self.context.get_setting('dns') if not dns: self.context.set_setting_default('dns', self.context.get_setting('gw')) self.context.set_setting_default('mask', numeric_to_dotted_ip(nummask)) logging.debug("net: %s" % self.context.get_setting('net')) logging.debug("netmask: %s" % self.context.get_setting('mask')) logging.debug("broadcast: %s" % self.context.get_setting('bcast')) logging.debug("gateway: %s" % self.context.get_setting('gw')) logging.debug("dns: %s" % self.context.get_setting('dns')) def configure_networking(self, nics): if len(nics) > 0: nic = nics[0] ip = self.get_setting('ip') if ip == 'dhcp': nic.type = 'dhcp' else: nic.type = 'static' nic.ip = ip nic.network = self.context.get_setting('net') nic.netmask = self.context.get_setting('mask') nic.broadcast = self.context.get_setting('bcast') nic.gateway = self.context.get_setting('gw') nic.dns = self.context.get_setting('dns') register_distro_plugin(NetworkDistroPlugin) register_hypervisor_plugin(NetworkHypervisorPlugin) vm-builder-0.12.4+bzr494/VMBuilder/plugins/postinst/__init__.py0000644000000000000000000000704711341435560022344 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder import register_distro_plugin, Plugin, VMBuilderUserError import logging import os import VMBuilder.util as util class postinst(Plugin): """ Plugin to provide --exec and --copy post install capabilities """ name ='Post install plugin' def register_options(self): group = self.setting_group('Post install actions') group.add_setting('copy', metavar='FILE', help="Read 'source dest' lines from FILE, copying source files from host to dest in the guest's file system.") group.add_setting('execscript', extra_args=['--exec'], metavar='SCRIPT', help="Run SCRIPT after distro installation finishes. Script will be called with the guest's chroot as first argument, so you can use 'chroot $1 ' to run code in the virtual machine.") def preflight_check(self): copy = self.context.get_setting('copy') if copy: logging.debug("Checking if copy PATH exists: %s" % copy) if not(os.path.isfile(copy)): raise VMBuilderUserError('The path to the copy directive is invalid: %s. Make sure you are providing a full path.' % copy) execscript = self.context.get_setting('execscript') if execscript: logging.debug("Checking if exec PATH exists: %s" % execscript) if not(os.path.isfile(execscript)): raise VMBuilderUserError('The path to the execscript file is invalid: %s. Make sure you are providing a full path.' % execscript) logging.debug("Checking permissions of exec PATH: %s" % execscript) if not os.access(execscript, os.X_OK|os.R_OK): raise VMBuilderUserError('The path to the execscript file has invalid permissions: %s. Make sure the path is readable and executable.' % execscript) def post_install(self): copy = self.context.get_setting('copy') execscript = self.context.get_setting('execscript') if copy: logging.info("Copying files specified by copy in: %s" % copy) try: for line in file(copy): pair = line.strip().split(' ') if len(pair) < 2: # skip blank and incomplete lines continue directory = '%s%s' % (self.context.chroot_dir, os.path.dirname(pair[1])) if not os.path.exists(directory): os.makedirs(directory) util.run_cmd('cp', '-LpR', pair[0], '%s%s' % (self.context.chroot_dir, pair[1])) except IOError, (errno, strerror): raise VMBuilderUserError("%s executing copy directives: %s" % (errno, strerror)) if execscript: logging.info("Executing script: %s" % execscript) util.run_cmd(execscript, self.context.chroot_dir) return True register_distro_plugin(postinst) vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/__init__.py0000644000000000000000000000134411213733731021774 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import distro vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/dapper.py0000644000000000000000000004010112432643240021501 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import glob import logging import os import suite import shutil import tempfile import VMBuilder.disk as disk from VMBuilder.util import run_cmd from VMBuilder.exception import VMBuilderException class Dapper(suite.Suite): updategrub = "/sbin/update-grub" grubroot = "/lib/grub" valid_flavours = { 'i386' : ['386', '686', '686-smp', 'k7', 'k7-smp', 'server', 'server-bigiron'], 'amd64' : ['amd64-generic', 'amd64-k8', 'amd64-k8-smp', 'amd64-server', 'amd64-xeon']} default_flavour = { 'i386' : 'server', 'amd64' : 'amd64-server' } disk_prefix = 'hd' xen_kernel_flavour = None virtio_net = False chpasswd_cmd = [ 'chpasswd', '--md5' ] preferred_filesystem = 'ext3' def pre_install(self): pass def check_kernel_flavour(self, arch, flavour): return flavour in self.valid_flavours[arch] def check_arch_validity(self, arch): return arch in self.valid_flavours.keys() def install(self, destdir): raise VMBuilderException('Do not call this method!') # These are still missing after the refactoring. logging.debug("Creating device.map") self.install_device_map() logging.debug("Copy host settings") self.copy_settings() if hasattr(self.context, 'ec2') and self.context.ec2: logging.debug("Configuring for ec2") self.install_ec2() def create_manifest(self): manifest = self.context.get_setting('manifest') if manifest: logging.debug("Creating manifest") manifest_contents = self.run_in_target('dpkg-query', '-W', '--showformat=${Package} ${Version}\n') fp = open(manifest, 'w') fp.write(manifest_contents) fp.close self.call_hook('fix_ownership', manifest) def update(self): self.run_in_target('apt-get', '-y', '--force-yes', 'dist-upgrade', env={ 'DEBIAN_FRONTEND' : 'noninteractive' }) def install_authorized_keys(self): ssh_key = self.context.get_setting('ssh-key') if ssh_key: os.mkdir('%s/root/.ssh' % self.context.chroot_dir, 0700) shutil.copy(ssh_key, '%s/root/.ssh/authorized_keys' % self.context.chroot_dir) os.chmod('%s/root/.ssh/authorized_keys' % self.context.chroot_dir, 0644) user = self.context.get_setting('user') ssh_user_key = self.context.get_setting('ssh-user-key') if ssh_user_key: os.mkdir('%s/home/%s/.ssh' % (self.context.chroot_dir, user), 0700) shutil.copy(ssh_user_key, '%s/home/%s/.ssh/authorized_keys' % (self.context.chroot_dir, user)) os.chmod('%s/home/%s/.ssh/authorized_keys' % (self.context.chroot_dir, user), 0644) self.run_in_target('chown', '-R', '%s:%s' % ((user,)*2), '/home/%s/.ssh/' % (user)) if ssh_user_key or ssh_key: addpkg = self.context.get_setting('addpkg') addpkg += ['openssh-server'] self.context.set_setting('addpkg', addpkg) def mount_dev_proc(self): run_cmd('mount', '--bind', '/dev', '%s/dev' % self.context.chroot_dir) self.context.add_clean_cb(self.unmount_dev) run_cmd('mount', '--bind', '/dev/pts', '%s/dev/pts' % self.context.chroot_dir) self.context.add_clean_cb(self.unmount_dev_pts) self.run_in_target('mount', '-t', 'proc', 'proc', '/proc') self.context.add_clean_cb(self.unmount_proc) def unmount_proc(self): self.context.cancel_cleanup(self.unmount_proc) run_cmd('umount', '%s/proc' % self.context.chroot_dir) def unmount_dev_pts(self): self.context.cancel_cleanup(self.unmount_dev_pts) run_cmd('umount', '%s/dev/pts' % self.context.chroot_dir) def unmount_dev(self): self.context.cancel_cleanup(self.unmount_dev) run_cmd('umount', '%s/dev' % self.context.chroot_dir) def update_passwords(self): # Set the user password, using md5 user = self.context.get_setting('user') passwd = self.context.get_setting('pass') self.run_in_target(stdin=('%s:%s\n' % (user, passwd)), *self.chpasswd_cmd) # Lock root account only if we didn't set the root password rootpass = self.context.get_setting('rootpass') if rootpass: self.run_in_target(stdin=('%s:%s\n' % ('root', rootpass)), *self.chpasswd_cmd) else: self.run_in_target('usermod', '-L', 'root') lock_user = self.context.get_setting('lock-user') if lock_user: logging.info('Locking %s' % (user, )) self.run_in_target('usermod', '-L', user) def create_initial_user(self): uid = self.context.get_setting('uid') name = self.context.get_setting('name') user = self.context.get_setting('user') if uid: self.run_in_target('adduser', '--disabled-password', '--uid', uid, '--gecos', name, user) else: self.run_in_target('adduser', '--disabled-password', '--gecos', name, user) self.run_in_target('addgroup', '--system', 'admin') self.run_in_target('adduser', user, 'admin') self.install_from_template('/etc/sudoers', 'sudoers') for group in ['adm', 'audio', 'cdrom', 'dialout', 'floppy', 'video', 'plugdev', 'dip', 'netdev', 'powerdev', 'lpadmin', 'scanner']: self.run_in_target('adduser', user, group, ignore_fail=True) self.update_passwords() def kernel_name(self): flavour = self.context.get_setting('flavour') arch = self.context.get_setting('arch') return 'linux-image-%s' % (flavour or self.default_flavour[arch],) def config_host_and_domainname(self): hostname = self.context.get_setting('hostname') domain = self.context.get_setting('domain') self.context.install_file('/etc/hostname', hostname) self.install_from_template('/etc/hosts', 'etc_hosts', { 'hostname' : hostname, 'domain' : domain }) def config_interfaces(self, nics): self.install_from_template('/etc/network/interfaces', 'interfaces', { 'ip' : nics[0].type == 'dhcp' and 'dhcp' or nics[0].ip, 'mask' : nics[0].netmask, 'net' : nics[0].network, 'bcast' : nics[0].broadcast, 'gw' : nics[0].gateway, 'dns' : nics[0].dns, 'domain' : self.context.get_setting('domain') }) def unprevent_daemons_starting(self): os.unlink('%s/usr/sbin/policy-rc.d' % self.context.chroot_dir) def prevent_daemons_starting(self): os.chmod(self.install_from_template('/usr/sbin/policy-rc.d', 'nostart-policy-rc.d'), 0755) def seed(self, seedfile): """Seed debconf with the contents of a seedfile""" logging.info('Seeding with "%s"' % seedfile) self.run_in_target('debconf-set-selections', stdin=open(seedfile, 'r').read()) def install_extras(self): seedfile = self.context.get_setting('seedfile') if seedfile: self.seed(seedfile) addpkg = self.context.get_setting('addpkg') removepkg = self.context.get_setting('removepkg') if not addpkg and not removepkg: return cmd = ['apt-get', 'install', '-y', '--force-yes'] cmd += addpkg or [] cmd += ['%s-' % pkg for pkg in removepkg or []] self.run_in_target(env={ 'DEBIAN_FRONTEND' : 'noninteractive' }, *cmd) def unmount_volatile(self): for mntpnt in glob.glob('%s/lib/modules/*/volatile' % self.context.chroot_dir): logging.debug("Unmounting %s" % mntpnt) run_cmd('umount', mntpnt) def install_menu_lst(self, disks): self.run_in_target(self.updategrub, '-y') self.mangle_grub_menu_lst(disks) self.run_in_target(self.updategrub) self.run_in_target('grub-set-default', '0') def mangle_grub_menu_lst(self, disks): bootdev = disk.bootpart(disks) run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=\/dev\/hd%s%d\\2/g' % (bootdev.disk.devletters(), bootdev.get_index()+1), '%s/boot/grub/menu.lst' % self.context.chroot_dir) run_cmd('sed', '-ie', 's/^# groot.*/# groot %s/g' % bootdev.get_grub_id(), '%s/boot/grub/menu.lst' % self.context.chroot_dir) run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.context.chroot_dir) def install_sources_list(self, final=False): if final: mirror = updates_mirror = self.context.get_setting('mirror') security_mirror = self.context.get_setting('security-mirror') else: mirror, updates_mirror, security_mirror = self.install_mirrors() components = self.context.get_setting('components') ppa = self.context.get_setting('ppa') suite = self.context.get_setting('suite') self.install_from_template('/etc/apt/sources.list', 'sources.list', { 'mirror' : mirror, 'security_mirror' : security_mirror, 'updates_mirror' : updates_mirror, 'components' : components, 'ppa' : ppa, 'suite' : suite }) # If setting up the final mirror, allow apt-get update to fail # (since we might be on a complete different network than the # final vm is going to be on). self.run_in_target('apt-get', 'update', ignore_fail=final) def install_apt_proxy(self): proxy = self.context.get_setting('proxy') if proxy is not None: self.context.install_file('/etc/apt/apt.conf', '// Proxy added by vmbuilder\nAcquire::http { Proxy "%s"; };' % proxy) def install_fstab(self, disks, filesystems): self.install_from_template('/etc/fstab', 'dapper_fstab', { 'parts' : disk.get_ordered_partitions(disks) }) def install_device_map(self): self.install_from_template('/boot/grub/device.map', 'devicemap', { 'prefix' : self.disk_prefix }) def debootstrap(self): arch = self.context.get_setting('arch') cmd = ['/usr/sbin/debootstrap', '--arch=%s' % arch] variant = self.context.get_setting('variant') if variant: cmd += ['--variant=%s' % variant] debootstrap_tarball = self.context.get_setting('debootstrap-tarball') if debootstrap_tarball: cmd += ['--unpack-tarball=%s' % debootstrap_tarball] suite = self.context.get_setting('suite') cmd += [suite, self.context.chroot_dir, self.debootstrap_mirror()] kwargs = { 'env' : { 'DEBIAN_FRONTEND' : 'noninteractive' } } proxy = self.context.get_setting('proxy') if proxy: kwargs['env']['http_proxy'] = proxy run_cmd(*cmd, **kwargs) def debootstrap_mirror(self): iso = self.context.get_setting('iso') if iso: isodir = tempfile.mkdtemp() self.context.add_clean_cb(lambda:os.rmdir(isodir)) run_cmd('mount', '-o', 'loop', '-t', 'iso9660', iso, isodir) self.context.add_clean_cmd('umount', isodir) self.iso_mounted = True return 'file://%s' % isodir else: return self.install_mirrors()[0] def install_mirrors(self): install_mirror = self.context.get_setting('install-mirror') if install_mirror: mirror = install_mirror else: mirror = self.context.get_setting('mirror') updates_mirror = mirror install_security_mirror = self.context.get_setting('install-security-mirror') if install_security_mirror: security_mirror = install_security_mirror else: security_mirror = self.context.get_setting('security-mirror') return (mirror, updates_mirror, security_mirror) def install_kernel(self, destdir): run_cmd('chroot', destdir, 'apt-get', '--force-yes', '-y', 'install', self.kernel_name(), env={ 'DEBIAN_FRONTEND' : 'noninteractive' }) def install_grub(self, chroot_dir): self.install_from_template('/etc/kernel-img.conf', 'kernelimg', { 'updategrub' : self.updategrub }) arch = self.context.get_setting('arch') self.run_in_target('apt-get', '--force-yes', '-y', 'install', 'grub', env={ 'DEBIAN_FRONTEND' : 'noninteractive' }) run_cmd('rsync', '-a', '%s%s/%s/' % (chroot_dir, self.grubroot, arch == 'amd64' and 'x86_64-pc' or 'i386-pc'), '%s/boot/grub/' % chroot_dir) def create_devices(self): pass # FIXME # import VMBuilder.plugins.xen # if isinstance(self.context.hypervisor, VMBuilder.plugins.xen.Xen): # self.run_in_target('mknod', '/dev/xvda', 'b', '202', '0') # self.run_in_target('mknod', '/dev/xvda1', 'b', '202', '1') # self.run_in_target('mknod', '/dev/xvda2', 'b', '202', '2') # self.run_in_target('mknod', '/dev/xvda3', 'b', '202', '3') # self.run_in_target('mknod', '/dev/xvc0', 'c', '204', '191') def install_from_template(self, *args, **kwargs): return self.context.install_from_template(*args, **kwargs) def run_in_target(self, *args, **kwargs): return self.context.run_in_target(*args, **kwargs) def copy_to_target(self, infile, destpath): logging.debug("Copying %s on host to %s in guest" % (infile, destpath)) dir = '%s/%s' % (self.destdir, os.path.dirname(destpath)) if not os.path.isdir(dir): os.makedirs(dir) if os.path.isdir(infile): shutil.copytree(infile, '%s/%s' % (self.destdir, destpath)) else: shutil.copy(infile, '%s/%s' % (self.destdir, destpath)) def post_mount(self, fs): if fs.mntpnt == '/': logging.debug("Creating /var/run in root filesystem") os.makedirs('%s/var/run' % fs.mntpath) logging.debug("Creating /var/lock in root filesystem") os.makedirs('%s/var/lock' % fs.mntpath) def set_locale(self): lang = self.context.get_setting('lang') if lang: self.install_from_template('/etc/default/locale', 'locale', { 'lang' : lang }) if lang != "C": self.run_in_target('locale-gen', lang) self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'libc6') self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'locales') def install_vmbuilder_log(self, logfile, rootdir): shutil.copy(logfile, '%s/var/log/vmbuilder-install.log' % (rootdir,)) def set_timezone(self): timezone = self.context.get_setting('timezone') if timezone: self.install_from_template('/etc/timezone', 'timezone', { 'timezone' : timezone }) self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'locales') def install_ec2(self): if self.context.ec2: logging.debug('This suite does not support ec2') def disable_hwclock_access(self): fp = open('%s/etc/default/rcS' % self.destdir, 'a') fp.write('HWCLOCKACCESS=no') fp.close() def has_256_bit_inode_ext3_support(self): return False vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/distro.py0000644000000000000000000003472712614545200021552 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2015 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import logging import os import shutil import stat import VMBuilder from VMBuilder import register_distro, Distro from VMBuilder.util import run_cmd from VMBuilder.exception import VMBuilderUserError, VMBuilderException class Ubuntu(Distro): name = 'Ubuntu' arg = 'ubuntu' suites = ['dapper', 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid', 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy', 'trusty', 'utopic', 'vivid', 'wily', 'xenial', ] # Maps host arch to valid guest archs valid_archs = { 'amd64' : ['amd64', 'i386', 'lpia' ], 'i386' : [ 'i386', 'lpia' ], 'lpia' : [ 'i386', 'lpia' ] } xen_kernel = '' def register_options(self): group = self.setting_group('Package options') group.add_setting('addpkg', type='list', metavar='PKG', help='Install PKG into the guest (can be specified multiple times).') group.add_setting('removepkg', type='list', metavar='PKG', help='Remove PKG from the guest (can be specified multiple times)') group.add_setting('seedfile', metavar="SEEDFILE", help='Seed the debconf database with the contents of this seed file before installing packages') group = self.setting_group('General OS options') self.host_arch = run_cmd('dpkg', '--print-architecture').rstrip() group.add_setting('arch', extra_args=['-a'], default=self.host_arch, help='Specify the target architecture. Valid options: amd64 i386 lpia (defaults to host arch)') group.add_setting('hostname', default='ubuntu', help='Set NAME as the hostname of the guest. Default: ubuntu. Also uses this name as the VM name.') group = self.setting_group('Installation options') group.add_setting('suite', default='lucid', help='Suite to install. Valid options: %s [default: %%default]' % ' '.join(self.suites)) group.add_setting('flavour', extra_args=['--kernel-flavour'], help='Kernel flavour to use. Default and valid options depend on architecture and suite') group.add_setting('variant', metavar='VARIANT', help='Passed to debootstrap --variant flag; use minbase, buildd, or fakechroot.') group.add_setting('debootstrap-tarball', metavar='FILE', help='Passed to debootstrap --unpack-tarball flag.') group.add_setting('iso', metavar='PATH', help='Use an iso image as the source for installation of file. Full path to the iso must be provided. If --mirror is also provided, it will be used in the final sources.list of the vm. This requires suite and kernel parameter to match what is available on the iso, obviously.') group.add_setting('mirror', metavar='URL', help='Use Ubuntu mirror at URL instead of the default, which is http://archive.ubuntu.com/ubuntu for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise') group.add_setting('proxy', metavar='URL', help='Use proxy at URL for cached packages') group.add_setting('install-mirror', metavar='URL', help='Use Ubuntu mirror at URL for the installation only. Apt\'s sources.list will still use default or URL set by --mirror') group.add_setting('security-mirror', metavar='URL', help='Use Ubuntu security mirror at URL instead of the default, which is http://security.ubuntu.com/ubuntu for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise.') group.add_setting('install-security-mirror', metavar='URL', help='Use the security mirror at URL for installation only. Apt\'s sources.list will still use default or URL set by --security-mirror') group.add_setting('components', type='list', metavar='COMPS', help='A comma seperated list of distro components to include (e.g. main,universe).') group.add_setting('ppa', metavar='PPA', type='list', help='Add ppa belonging to PPA to the vm\'s sources.list.') group.add_setting('lang', metavar='LANG', default=get_locale(), help='Set the locale to LANG [default: %default]') group.add_setting('timezone', metavar='TZ', default='UTC', help='Set the timezone to TZ in the vm. [default: %default]') group = self.setting_group('Settings for the initial user') group.add_setting('user', default='ubuntu', help='Username of initial user [default: %default]') group.add_setting('name', default='Ubuntu', help='Full name of initial user [default: %default]') group.add_setting('pass', default='ubuntu', help='Password of initial user [default: %default]') group.add_setting('rootpass', help='Initial root password (WARNING: this has strong security implications).') group.add_setting('uid', type='int', help='Initial UID value.') group.add_setting('gid', help='Initial GID value.') group.add_setting('lock-user', type='bool', default=False, help='Lock the initial user [default: %default]') group = self.setting_group('Other options') group.add_setting('ssh-key', metavar='PATH', help='Add PATH to root\'s ~/.ssh/authorized_keys (WARNING: this has strong security implications).') group.add_setting('ssh-user-key', help='Add PATH to the user\'s ~/.ssh/authorized_keys.') group.add_setting('manifest', metavar='PATH', help='If passed, a manifest will be written to PATH') def set_defaults(self): arch = self.get_setting('arch') if arch == 'lpia': self.set_setting_default('mirror', 'http://ports.ubuntu.com/ubuntu-ports') self.set_setting_default('security-mirror', 'http://ports.ubuntu.com/ubuntu-ports') else: self.set_setting_default('mirror', 'http://archive.ubuntu.com/ubuntu') self.set_setting_default('security-mirror', 'http://security.ubuntu.com/ubuntu') self.set_setting_default('components', ['main', 'restricted', 'universe']) def preflight_check(self): """While not all of these are strictly checks, their failure would inevitably lead to failure, and since we can check them before we start setting up disk and whatnot, we might as well go ahead an do this now.""" suite = self.get_setting('suite') if not suite in self.suites: raise VMBuilderUserError('Invalid suite: "%s". Valid suites are: %s' % (suite, ' '.join(self.suites))) modname = 'VMBuilder.plugins.ubuntu.%s' % (suite, ) mod = __import__(modname, fromlist=[suite]) self.suite = getattr(mod, suite.capitalize())(self) arch = self.get_setting('arch') if arch not in self.valid_archs[self.host_arch] or \ not self.suite.check_arch_validity(arch): raise VMBuilderUserError('%s is not a valid architecture. Valid architectures are: %s' % (arch, ' '.join(self.valid_archs[self.host_arch]))) components = self.get_setting('components') if not components: self.set_config_value_list = ['main', 'restricted', 'universe'] else: if type(components) is str: self.vm.components = self.vm.components.split(',') self.context.virtio_net = self.use_virtio_net() # check if the seedfile exists if one is to be used seedfile = self.context.get_setting('seedfile') if seedfile and not os.path.exists(seedfile): raise VMBuilderUserError("Seedfile '%s' does not exist" % seedfile) lang = self.get_setting('lang') # FIXME # if getattr(self.vm, 'ec2', False): # self.get_ec2_kernel() # self.get_ec2_ramdisk() # self.apply_ec2_settings() def bootstrap(self): self.suite.debootstrap() self.suite.pre_install() def configure_os(self): self.suite.install_apt_proxy() self.suite.install_sources_list() self.suite.create_devices() self.suite.prevent_daemons_starting() self.suite.mount_dev_proc() self.suite.install_extras() self.suite.create_initial_user() self.suite.install_authorized_keys() self.suite.set_timezone() self.suite.set_locale() self.suite.update() self.suite.install_sources_list(final=True) self.suite.run_in_target('apt-get', 'clean'); self.suite.unmount_volatile() self.suite.unmount_proc() self.suite.unmount_dev_pts() self.suite.unmount_dev() self.suite.unprevent_daemons_starting() self.suite.create_manifest() def configure_networking(self, nics): self.suite.config_host_and_domainname() self.suite.config_interfaces(nics) def configure_mounting(self, disks, filesystems): self.suite.install_fstab(disks, filesystems) def install(self, destdir): self.destdir = destdir self.suite.install(destdir) def install_vmbuilder_log(self, logfile, rootdir): self.suite.install_vmbuilder_log(logfile, rootdir) def post_mount(self, fs): self.suite.post_mount(fs) def use_virtio_net(self): return self.suite.virtio_net def install_bootloader_cleanup(self, chroot_dir): self.context.cancel_cleanup(self.install_bootloader_cleanup) tmpdir = '%s/tmp/vmbuilder-grub' % chroot_dir for disk in os.listdir(tmpdir): if disk != 'device.map': run_cmd('umount', os.path.join(tmpdir, disk)) shutil.rmtree(tmpdir) def install_kernel(self, destdir): self.suite.install_kernel(destdir) def install_bootloader(self, chroot_dir, disks): root_dev = VMBuilder.disk.bootpart(disks).get_grub_id() tmpdir = '/tmp/vmbuilder-grub' os.makedirs('%s%s' % (chroot_dir, tmpdir)) self.context.add_clean_cb(self.install_bootloader_cleanup) devmapfile = os.path.join(tmpdir, 'device.map') devmap = open('%s%s' % (chroot_dir, devmapfile), 'w') for (disk, id) in zip(disks, range(len(disks))): new_filename = os.path.join(tmpdir, os.path.basename(disk.filename)) open('%s%s' % (chroot_dir, new_filename), 'w').close() run_cmd('mount', '--bind', disk.filename, '%s%s' % (chroot_dir, new_filename)) st = os.stat(disk.filename) if stat.S_ISBLK(st.st_mode): for (part, part_id) in zip(disk.partitions, range(len(disk.partitions))): part_mountpnt = '%s%s%d' % (chroot_dir, new_filename, part_id+1) open(part_mountpnt, 'w').close() run_cmd('mount', '--bind', part.filename, part_mountpnt) devmap.write("(hd%d) %s\n" % (id, new_filename)) devmap.close() run_cmd('cat', '%s%s' % (chroot_dir, devmapfile)) self.suite.install_grub(chroot_dir) self.run_in_target('grub', '--device-map=%s' % devmapfile, '--batch', stdin='''root %s setup (hd0) EOT''' % root_dev) self.suite.install_menu_lst(disks) self.install_bootloader_cleanup(chroot_dir) def xen_kernel_version(self): if self.suite.xen_kernel_flavour: # if this is ec2, do not call rmadison. # this could be replaced with a method to get most recent # stable kernel, but really, this is not used at all for ec2 if hasattr(self.context, 'ec2') and self.context.ec2: logging.debug("selecting ec2 kernel") self.xen_kernel = "2.6.ec2-kernel" return self.xen_kernel if not self.xen_kernel: rmad = run_cmd('rmadison', 'linux-image-%s' % self.suite.xen_kernel_flavour) version = ['0', '0','0', '0'] for line in rmad.splitlines(): sline = line.split('|') if sline[2].strip().startswith(self.context.get_setting('suite')): vt = sline[1].strip().split('.') for i in range(4): if int(vt[i]) > int(version[i]): version = vt break if version[0] == '0': raise VMBuilderException('Something is wrong, no valid xen kernel for the suite %s found by rmadison' % self.context.suite) self.xen_kernel = '%s.%s.%s-%s' % (version[0],version[1],version[2],version[3]) return self.xen_kernel else: raise VMBuilderUserError('There is no valid xen kernel for the suite selected.') def xen_kernel_initrd_path(self, which): path = '/boot/%s-%s-%s' % (which, self.xen_kernel_version(), self.suite.xen_kernel_flavour) return path def xen_kernel_path(self): return self.xen_kernel_initrd_path('kernel') def xen_ramdisk_path(self): return self.xen_kernel_initrd_path('ramdisk') def get_ec2_kernel(self): if self.suite.ec2_kernel_info: return self.suite.ec2_kernel_info[self.context.arch] else: raise VMBuilderUserError('EC2 is not supported for the suite selected') def get_ec2_ramdisk(self): if self.suite.ec2_ramdisk_info: return self.suite.ec2_ramdisk_info[self.context.arch] else: raise VMBuilderUserError('EC2 is not supported for the suite selected') def disable_hwclock_access(self): return self.suite.disable_hwclock_access() def apply_ec2_settings(self): return self.suite.apply_ec2_settings() def has_256_bit_inode_ext3_support(self): return self.suite.has_256_bit_inode_ext3_support() def preferred_filesystem(self): return self.suite.preferred_filesystem def get_locale(): lang = os.getenv('LANG') if lang is None: return 'C' # People's $LANG looks different since lucid, but locale-gen still # wants the old format. if lang.endswith('utf8'): return lang[:-4] + 'UTF-8' return lang register_distro(Ubuntu) vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/edgy.py0000644000000000000000000001033412003417765021170 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import shutil import os import VMBuilder.disk as disk from VMBuilder.util import run_cmd from VMBuilder.plugins.ubuntu.dapper import Dapper class Edgy(Dapper): valid_flavours = { 'i386' : ['386', '686', '686-smp', 'generic', 'k7', 'k7-smp', 'server', 'server-bigiron'], 'amd64' : ['amd64-generic', 'amd64-k8', 'amd64-k8-smp', 'amd64-server', 'amd64-xeon', 'server']} default_flavour = { 'i386' : 'server', 'amd64' : 'server' } disk_prefix = 'sd' def mangle_grub_menu_lst(self, disks): bootdev = disk.bootpart(disks) run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=UUID=%s\\2/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.context.chroot_dir) run_cmd('sed', '-ie', 's/^# groot.*/# groot %s/g' % bootdev.get_grub_id(), '%s/boot/grub/menu.lst' % self.context.chroot_dir) run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.context.chroot_dir) def fstab(self): retval = '''# /etc/fstab: static file system information. # # proc /proc proc defaults 0 0 ''' parts = disk.get_ordered_partitions(self.context.disks) for part in parts: retval += "UUID=%-40s %15s %7s %15s %d %d\n" % (part.fs.uuid, part.fs.mntpnt, part.fs.fstab_fstype(), part.fs.fstab_options(), 0, 0) return retval def copy_settings(self): if os.path.exists('/etc/default/locale'): self.copy_to_target('/etc/default/locale', '/etc/default/locale') csdir = '%s/etc/console-setup' % self.destdir have_cs = os.path.isdir(csdir) if have_cs: shutil.rmtree(csdir) self.copy_to_target('/etc/console-setup', '/etc/console-setup') self.copy_to_target('/etc/default/console-setup', '/etc/default/console-setup') self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'tzdata') self.run_in_target('locale-gen', 'en_US') if self.context.lang: self.run_in_target('locale-gen', self.context.lang) self.install_from_template('/etc/default/locale', 'locale', { 'lang' : self.context.lang }) self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'locales') if have_cs: self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'console-setup') def set_timezone(self): timezone = self.context.get_setting('timezone') if timezone: self.install_from_template('/etc/timezone', 'timezone', { 'timezone' : timezone }) self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'tzdata') def divert_file(self, path, add): full_path = '%s/%s' % (self.context.chroot_dir, path) renamed_path = '%s.real' % (full_path, ) if add: (src, dst) = full_path, renamed_path else: (src, dst) = renamed_path, full_path os.rename(src, dst) def prevent_daemons_starting(self): super(Edgy, self).prevent_daemons_starting() initctl = '/sbin/initctl' self.divert_file(initctl, True) self.install_from_template('/sbin/initctl', 'initctl-stub', mode=0755) def unprevent_daemons_starting(self): super(Edgy, self).unprevent_daemons_starting() initctl = '/sbin/initctl' self.divert_file(initctl, False) vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/feisty.py0000644000000000000000000000216411341245160021535 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder.plugins.ubuntu.edgy import Edgy class Feisty(Edgy): updategrub = "/usr/sbin/update-grub" grubroot = "/usr/lib/grub" valid_flavours = { 'i386' : ['386', '686', '686-smp', 'generic', 'k7', 'k7-smp', 'server', 'server-bigiron', 'lowlatency'], 'amd64' : ['amd64-generic', 'amd64-k8', 'amd64-k8-smp', 'amd64-server', 'amd64-xeon', 'server']} disk_prefix = 'sd' vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/gutsy.py0000644000000000000000000000213211341245160021400 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder.plugins.ubuntu.feisty import Feisty class Gutsy(Feisty): valid_flavours = { 'i386' : ['386', 'generic', 'rt', 'server', 'virtual'], 'amd64' : ['generic', 'rt', 'server'], 'lpia' : ['lpia', 'lpiacompat'] } default_flavour = { 'i386' : 'virtual', 'amd64' : 'server', 'lpia' : 'lpia' } xen_kernel_flavour = 'xen' vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/hardy.py0000644000000000000000000000501012003417765021342 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.gutsy import Gutsy class Hardy(Gutsy): virtio_net = True ec2_kernel_info = { 'i386' : 'aki-6e709707', 'amd64' : 'aki-6f709706' } ec2_ramdisk_info = { 'i386' : 'ari-6c709705', 'amd64' : 'ari-61709708' } def apply_ec2_settings(self): self.context.addpkg += ['ec2-init', 'openssh-server', 'ec2-modules', 'standard^', 'ec2-ami-tools', 'update-motd'] if not self.context.ppa: self.context.ppa = [] self.context.ppa += ['ubuntu-on-ec2/ppa'] def install_ec2(self): if self.context.arch == 'i386': self.run_in_target('apt-get' ,'--force-yes', '-y', 'install', 'libc6-xen') self.run_in_target('apt-get','--purge','--force-yes', '-y', 'remove', 'libc6-i686') self.install_from_template('/etc/ld.so.conf.d/libc6-xen.conf', 'xen-ld-so-conf') self.install_from_template('/etc/event.d/xvc0', 'upstart', { 'console' : 'xvc0' }) self.run_in_target('update-rc.d', '-f', 'hwclockfirst.sh', 'remove') self.install_from_template('/etc/update-motd.d/51_update-motd', '51_update-motd-hardy') self.run_in_target('chmod', '755', '/etc/update-motd.d/51_update-motd') self.install_from_template('/etc/ec2-init/is-compat-env', 'is-compat-env') def xen_kernel_path(self): return '/boot/vmlinuz-2.6.24-19-xen' def xen_ramdisk_path(self): return '/boot/initrd.img-2.6.24-19-xen' def has_256_bit_inode_ext3_support(self): return True def unmount_dev(self): # no idea why, but something keep /dev busy briefly during the # bootstrap time.sleep(1) super(Hardy, self).unmount_dev() vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/intrepid.py0000644000000000000000000000446211405764413022063 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import VMBuilder.disk as disk from VMBuilder.util import run_cmd from VMBuilder.plugins.ubuntu.hardy import Hardy class Intrepid(Hardy): valid_flavours = { 'i386' : ['386', 'generic', 'server', 'virtual'], 'amd64' : ['generic', 'server', 'virtual'], 'lpia' : ['lpia', 'lpiacompat'] } default_flavour = { 'i386' : 'virtual', 'amd64' : 'virtual', 'lpia' : 'lpia' } xen_kernel_flavour = 'virtual' ec2_kernel_info = { 'i386' : 'aki-714daa18', 'amd64' : 'aki-4f4daa26' } ec2_ramdisk_info = { 'i386': 'ari-7e4daa17', 'amd64' : 'ari-4c4daa25' } def install_ec2(self): # workaround for policy bug on ubuntu-server. (see bug #275432) self.run_in_target('apt-get', '--force-yes', '-y', 'install', 'policykit') self.run_in_target('apt-get', '--force-yes', '-y', 'install', 'server^') self.install_from_template('/etc/update-motd.d/51_update-motd', '51_update-motd') self.run_in_target('chmod', '755', '/etc/update-motd.d/51_update-motd') self.install_from_template('/etc/ec2-init/is-compat-env', 'is-compat-env') def mangle_grub_menu_lst(self, disks): rootdev = disk.rootpart(disks) bootdev = disk.bootpart(disks) run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=UUID=%s\\2/g' % rootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.context.chroot_dir) run_cmd('sed', '-ie', 's/^# groot.*/# groot=%s/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.context.chroot_dir) run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.context.chroot_dir) vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/jaunty.py0000644000000000000000000000342411405764413021554 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import os import VMBuilder.disk as disk from VMBuilder.util import run_cmd from VMBuilder.plugins.ubuntu.intrepid import Intrepid class Jaunty(Intrepid): valid_flavours = { 'i386' : ['generic', 'server', 'virtual'], 'amd64' : ['generic', 'server', 'virtual'], 'lpia' : ['lpia', 'lpiacompat'] } xen_kernel_flavour = 'server' ec2_kernel_info = { 'i386' : 'aki-c553b4ac', 'amd64' : 'aki-d653b4bf' } ec2_ramdisk_info = { 'i386' : 'ari-c253b4ab', 'amd64' : 'ari-d753b4be' } chpasswd_cmd= [ 'chpasswd' ] def install_ec2(self): self.run_in_target('apt-get', '--force-yes', '-y', 'install', 'server^') self.install_from_template('/etc/update-motd.d/51_update-motd', '51_update-motd') # lucid and later wont have an /etc/ec2-init, so only write # that file if the dir exists if os.path.isdir("/etc/ec2-init"): self.install_from_template('/etc/ec2-init/is-compat-env', 'is-compat-env') self.run_in_target('chmod', '755', '/etc/update-motd.d/51_update-motd') vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/karmic.py0000644000000000000000000000231211341245160021473 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder.plugins.ubuntu.jaunty import Jaunty class Karmic(Jaunty): valid_flavours = { 'i386' : ['386', 'generic', 'generic-pae', 'virtual'], 'amd64' : ['generic', 'server', 'virtual'], 'lpia' : ['lpia'] } preferred_filesystem = 'ext4' def apply_ec2_settings(self): self.context.addpkg += ['standard^', 'uec^'] def pre_install(self): self.context.install_file('/etc/hosts', contents='') vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/lucid.py0000644000000000000000000000241312003417765021337 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import os from VMBuilder.util import run_cmd from VMBuilder.plugins.ubuntu.karmic import Karmic class Lucid(Karmic): valid_flavours = { 'i386' : ['386', 'generic', 'generic-pae', 'virtual'], 'amd64' : ['generic', 'preempt', 'server', 'virtual'] } def divert_file(self, path, add): if add: action = "--add" else: action = "--remove" if not add: os.remove('%s/%s' % (self.context.chroot_dir, path)) run_cmd('chroot', self.context.chroot_dir, 'dpkg-divert', '--local', '--rename', action, path) vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/maverick.py0000644000000000000000000000164411470531057022043 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder.plugins.ubuntu.lucid import Lucid class Maverick(Lucid): valid_flavours = { 'i386' : ['generic', 'generic-pae', 'virtual'], 'amd64' : ['generic', 'server', 'virtual'] } vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/natty.py0000644000000000000000000000144711470531057021402 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder.plugins.ubuntu.maverick import Maverick class Natty(Maverick): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/oneiric.py0000644000000000000000000000143612003417765021673 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder.plugins.ubuntu.natty import Natty class Oneiric(Natty): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/precise.py0000644000000000000000000000146011647620455021677 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.oneiric import Oneiric class Precise(Oneiric): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/quantal.py0000644000000000000000000000146011747641527021716 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.precise import Precise class Quantal(Precise): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/raring.py0000644000000000000000000000145712137515412021524 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.quantal import Quantal class Raring(Quantal): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/saucy.py0000644000000000000000000000145312137515412021362 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.raring import Raring class Saucy(Raring): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/suite.py0000644000000000000000000000211511341245160021357 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # class Suite(object): def __init__(self, context): self.context = context self.isodir = '/media/vmbuilder_inst_image' self.iso_mounted = False def check_arch_validity(self, arch): """Checks whether the given arch is valid for this suite""" raise NotImplemented('Suite subclasses need to implement the check_arch_validity method') vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/0000755000000000000000000000000011064415455021663 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/tests/0000755000000000000000000000000011400272572021022 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/trusty.py0000644000000000000000000000145112305452270021605 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.saucy import Saucy class Trusty(Saucy): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/utopic.py0000644000000000000000000000146112605215443021541 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010-2015 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.trusty import Trusty class Utopic(Trusty): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/vivid.py0000644000000000000000000000146012605215443021356 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010-2015 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.utopic import Utopic class Vivid(Utopic): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/wily.py0000644000000000000000000000145412605215443021224 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010-2015 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.vivid import Vivid class Wily(Vivid): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/xenial.py0000644000000000000000000000145312614545200021514 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2010-2015 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import time from VMBuilder.plugins.ubuntu.wily import Wily class Xenial(Wily): pass vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/51_update-motd-hardy.tmpl0000644000000000000000000000116311206734310026407 0ustar 00000000000000#!/bin/sh echo "---------------------------------------------------------------------" echo "At the moment, only the core of the system is installed. To tune the " echo "system to your needs, you can choose to install one or more " echo "predefined collections of software by running the following " echo "command: " echo " " echo " sudo tasksel " echo "---------------------------------------------------------------------" vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/51_update-motd.tmpl0000644000000000000000000000116311206734310025302 0ustar 00000000000000#!/bin/sh echo "---------------------------------------------------------------------" echo "At the moment, only the core of the system is installed. To tune the " echo "system to your needs, you can choose to install one or more " echo "predefined collections of software by running the following " echo "command: " echo " " echo " sudo tasksel --section server " echo "---------------------------------------------------------------------" vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/dapper_fstab.tmpl0000644000000000000000000000063312432643240025210 0ustar 00000000000000# /etc/fstab: static file system information. # # proc /proc proc defaults 0 0 #for $part in $parts UUID=$part.fs.uuid $part.mntpnt $part.fs.fstab_fstype() $part.fs.fstab_options() 0 0 #end for vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/dapper_fstab_fsimage.tmpl0000644000000000000000000000107011074454262026704 0ustar 00000000000000# /etc/fstab: static file system information. # # proc /proc proc defaults 0 0 #for $fs in $fss #echo '/dev/%s%-40s %-15s %-7s %-15s %d %d\n' % ($prefix, fs.get_suffix(), fs.mntpnt, fs.fstab_fstype(), fs.fstab_options(), 0, 0) #* echo "/dev/$prefix$part.get_suffix() $part.mntpnt $part.fs.fstab_fstype() $part.fs.fstab_options() 0 0 *# #end for vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/devicemap.tmpl0000644000000000000000000000012111076147061024506 0ustar 00000000000000#for $disk in $disks $disk.get_grub_id() /dev/$prefix$disk.devletters() #end for vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/etc_hosts.tmpl0000644000000000000000000000040311064415455024551 0ustar 00000000000000127.0.0.1 localhost 127.0.1.1 $hostname.$domain $hostname # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/initctl-stub.tmpl0000644000000000000000000000010211341273440025165 0ustar 00000000000000#!/bin/sh echo echo "Warning: Fake initctl called, doing nothing" vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/interfaces.tmpl0000644000000000000000000000107111067775032024706 0ustar 00000000000000# This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). # The loopback network interface auto lo iface lo inet loopback # The primary network interface auto eth0 #if $ip == 'dhcp' iface eth0 inet dhcp #else iface eth0 inet static address $ip netmask $mask network $net broadcast $bcast gateway $gw # dns-* options are implemented by the resolvconf package, if installed dns-nameservers $dns dns-search $domain #end if vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/is-compat-env.tmpl0000644000000000000000000000014511257450744025247 0ustar 00000000000000# this is read by ec2-is-compat-env to determine if this is an # ec2 compatible environment compat=1 vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/kernelimg.tmpl0000644000000000000000000000024511064415455024537 0ustar 00000000000000do_symlinks = yes relative_links = yes do_bootfloppy = no do_initrd = yes link_in_boot = no postinst_hook = $updategrub postrm_hook = $updategrub do_bootloader = no vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/locale.tmpl0000644000000000000000000000001511103360007023776 0ustar 00000000000000LANG="$lang" vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/nostart-policy-rc.d.tmpl0000644000000000000000000000037611064415455026402 0ustar 00000000000000#!/bin/sh while true; do case "$1" in -*) shift ;; makedev) exit 0 ;; x11-common) exit 0 ;; *) exit 101 ;; esac done vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/sources.list.tmpl0000644000000000000000000000044511553244007025215 0ustar 00000000000000deb $mirror $suite #slurp #echo ' '.join($components) deb $updates_mirror $suite-updates #slurp #echo ' '.join($components) deb $security_mirror $suite-security #slurp #echo ' '.join($components) #if $ppa #for $p in $ppa deb http://ppa.launchpad.net/$p/ubuntu $suite main #end for #end if vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/sudoers.tmpl0000644000000000000000000000076011064415455024250 0ustar 00000000000000# /etc/sudoers # # This file MUST be edited with the 'visudo' command as root. # # See the man page for details on how to write a sudoers file. # Defaults Defaults !lecture,tty_tickets,!fqdn # Uncomment to allow members of group sudo to not need a password # %sudo ALL=NOPASSWD: ALL # Host alias specification # User alias specification # Cmnd alias specification # User privilege specification root ALL=(ALL) ALL # Members of the admin group may gain root privileges %admin ALL=(ALL) ALL vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/timezone.tmpl0000644000000000000000000000001211343466360024405 0ustar 00000000000000$timezone vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/upstart.tmpl0000644000000000000000000000047611207512451024263 0ustar 00000000000000# $console - getty # # This service maintains a getty on $console from the point the system is # started until it is shut down again. start on stopped rc2 start on stopped rc3 start on stopped rc4 start on stopped rc5 stop on runlevel 0 stop on runlevel 1 stop on runlevel 6 respawn exec /sbin/getty 38400 $console vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/templates/xen-ld-so-conf.tmpl0000644000000000000000000000002111207716464025306 0ustar 00000000000000hwcap 0 nosegneg vm-builder-0.12.4+bzr494/VMBuilder/plugins/ubuntu/tests/test_distro.py0000644000000000000000000000064011400272572023737 0ustar 00000000000000import os import unittest from VMBuilder.plugins.ubuntu import distro class TestUbuntuDistro(unittest.TestCase): def test_get_locale(self): os.environ['LANG'] = 'foo' self.assertEqual(distro.get_locale(), 'foo') os.environ['LANG'] = 'foo.utf8' self.assertEqual(distro.get_locale(), 'foo.UTF-8') del os.environ['LANG'] self.assertEqual(distro.get_locale(), 'C') vm-builder-0.12.4+bzr494/VMBuilder/plugins/virtualbox/__init__.py0000644000000000000000000000134011213733731022645 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import vm vm-builder-0.12.4+bzr494/VMBuilder/plugins/virtualbox/templates/0000755000000000000000000000000011166116660022537 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/virtualbox/vm.py0000644000000000000000000000506411622473765021553 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import os import os.path import stat import VMBuilder from VMBuilder import register_hypervisor, Hypervisor from VMBuilder.disk import vbox_manager_path import VMBuilder.hypervisor class VirtualBox(Hypervisor): preferred_storage = VMBuilder.hypervisor.STORAGE_DISK_IMAGE needs_bootloader = True name = 'VirtualBox' arg = 'vbox' def register_options(self): group = self.setting_group('VirtualBox options') group.add_setting('mem', extra_args=['-m'], type='int', default=128, help='Assign MEM megabytes of memory to the guest vm. [default: %default]') group.add_setting('cpus', type='int', default=1, help='Assign NUM cpus to the guest vm. [default: %default]') group.add_setting('vbox-disk-format', metavar='FORMAT', default='vdi', help='Desired disk format. Valid options are: vdi vmdk. [default: %default]') def convert(self, disks, destdir): self.imgs = [] for disk in disks: img_path = disk.convert(destdir, self.context.get_setting('vbox-disk-format')) self.imgs.append(img_path) def deploy(self,destdir): hostname = self.context.distro.get_setting('hostname') mac = self.context.get_setting('mac') ip = self.context.get_setting('ip') vm_deploy_script = VMBuilder.util.render_template('virtualbox', self.context, 'vm_deploy_script', { 'os_type' : self.context.distro.__class__.__name__, 'vm_name' : hostname, 'vm_disks' : self.imgs, 'memory' : self.context.get_setting('mem'), 'cpus' : self.context.get_setting('cpus') }) script_file = '%s/deploy_%s.sh' % (destdir, hostname) fp = open(script_file, 'w') fp.write(vm_deploy_script) fp.close() os.chmod(script_file, stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH) self.context.result_files.append(script_file) register_hypervisor(VirtualBox) vm-builder-0.12.4+bzr494/VMBuilder/plugins/virtualbox/templates/vm_deploy_script.tmpl0000644000000000000000000000272711341322516027021 0ustar 00000000000000#raw #! /usr/bin/env bash ############################################################################### # # This script is used to create und register a new VM # in VirtualBox # ############################################################################### #end raw #import os #import os.path #if $os_type == "Ubuntu" os_type="Ubuntu" #else os_type="Other" #end if disk_path="#echo os.path.abspath(os.path.dirname($vm_disks[0]))#" VBoxManage createvm -name $vm_name -ostype \$os_type -register VBoxManage openmedium #slurp #set $i = 0 #for $disk in $vm_disks #set $i = $i + 1 #set $disk = os.path.basename(disk) disk \${disk_path}/$disk -type normal #slurp #end for VBoxManage modifyvm $vm_name -memory $memory -cpus $cpus -sata on #slurp #set $i = 0 #for $disk in $vm_disks #set $i = $i + 1 #set $disk = os.path.basename(disk) #if $i >= 31 #break #end if #if $i == 1 -hda \${disk_path}/$disk #slurp #else if $i == 2 -hdb \${disk_path}/$disk #slurp #else if $i == 3 -hdd \${disk_path}/$disk #slurp #else -sataport${i} \${disk_path}/$disk #slurp #end if #end for #if $mac VBoxManage modifyvm $vm_name -macaddress1 $mac #end if #if $ip #if $ip == "dhcp" VBoxManage modifyvm $vm_name -nic1 nat #else VBoxManage modifyvm $vm_name -nic1 intnet #end if #end if #activating PAE support for the CPU because some OS (e.g. ubuntu server ) won't boot in a virtual machine without it VBoxManage modifyvm $vm_name -pae on vm-builder-0.12.4+bzr494/VMBuilder/plugins/vmware/__init__.py0000644000000000000000000000134011213733731021747 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import vm vm-builder-0.12.4+bzr494/VMBuilder/plugins/vmware/templates/0000755000000000000000000000000011077307510021636 5ustar 00000000000000vm-builder-0.12.4+bzr494/VMBuilder/plugins/vmware/vm.py0000644000000000000000000001137411341322516020637 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder import register_hypervisor, Hypervisor import VMBuilder import VMBuilder.hypervisor import os import os.path import stat from shutil import move from math import floor class VMWare(Hypervisor): filetype = 'vmdk' preferred_storage = VMBuilder.hypervisor.STORAGE_DISK_IMAGE needs_bootloader = True vmxtemplate = 'vmware' def register_options(self): group = self.setting_group('VM settings') group.add_setting('mem', extra_args=['-m'], default='128', help='Assign MEM megabytes of memory to the guest vm. [default: %default]') group.add_setting('cpus', type='int', default=1, help='Assign NUM cpus to the guest vm. [default: %default]') def convert(self, disks, destdir): self.imgs = [] for disk in self.get_disks(): img_path = disk.convert(destdir, self.filetype) self.imgs.append(img_path) self.call_hooks('fix_ownership', img_path) def get_disks(self): return self.disks def deploy(self, destdir): mem = self.context.get_setting('mem') cpus = self.context.get_setting('cpus') hostname = self.context.distro.get_setting('hostname') arch = self.context.distro.get_setting('arch') mac = self.context.get_setting('mac') vmdesc = VMBuilder.util.render_template('vmware', self.context, self.vmxtemplate, { 'disks' : self.get_disks(), 'vmhwversion' : self.vmhwversion, 'mem' : mem, 'numvcpus' : cpus, 'hostname' : hostname, 'arch' : arch, 'mac' : mac, 'guestos' : (arch == 'amd64' and 'ubuntu-64' or 'ubuntu') }) vmx = '%s/%s.vmx' % (destdir, hostname) fp = open(vmx, 'w') fp.write(vmdesc) fp.close() os.chmod(vmx, stat.S_IRWXU | stat.S_IRWXU | stat.S_IROTH | stat.S_IXOTH) self.call_hooks('fix_ownership', vmx) class VMWareWorkstation6(VMWare): name = 'VMWare Workstation 6' arg = 'vmw6' vmhwversion = 6 class VMWareServer(VMWare): name = 'VMWare Server' arg = 'vmserver' vmhwversion = 4 class VMWareEsxi(VMWare): name = 'VMWare ESXi' arg = 'esxi' vmhwversion = 4 adaptertype = 'lsilogic' # lsilogic | buslogic, ide is not supported by ESXi vmxtemplate = 'esxi.vmx' vmdks = [] # vmdk filenames used when deploying vmx file def convert(self, disks, destdir): self.imgs = [] for disk in disks: # Move raw image to -flat.vmdk diskfilename = os.path.basename(disk.filename) if '.' in diskfilename: diskfilename = diskfilename[:diskfilename.rindex('.')] flat = '%s/%s-flat.vmdk' % (destdir, diskfilename) self.vmdks.append(diskfilename) move(disk.filename, flat) self.call_hooks('fix_ownership', flat) # Create disk descriptor file sectorTotal = disk.size * 2048 sector = int(floor(sectorTotal / 16065)) # pseudo geometry diskdescriptor = VMBuilder.util.render_template('vmware', self.context, 'flat.vmdk', { 'adaptertype' : self.adaptertype, 'sectors' : sector, 'diskname' : os.path.basename(flat), 'disksize' : sectorTotal }) vmdk = '%s/%s.vmdk' % (destdir, diskfilename) fp = open(vmdk, 'w') fp.write(diskdescriptor) fp.close() os.chmod(vmdk, stat.S_IRWXU | stat.S_IRWXU | stat.S_IROTH | stat.S_IXOTH) self.call_hooks('fix_ownership', vmdk) def get_disks(self): return self.vmdks register_hypervisor(VMWareServer) register_hypervisor(VMWareWorkstation6) register_hypervisor(VMWareEsxi) vm-builder-0.12.4+bzr494/VMBuilder/plugins/vmware/templates/esxi.vmx.tmpl0000644000000000000000000000252411341322516024315 0ustar 00000000000000config.version = "8" virtualHW.version = "$vmhwversion" floppy0.present = "true" nvram = "nvram" deploymentPlatform = "windows" virtualHW.productCompatibility = "hosted" tools.upgrade.policy = "useGlobal" powerType.powerOff = "default" powerType.powerOn = "default" powerType.suspend = "default" powerType.reset = "default" displayName = "$hostname $arch" numvcpus = "$numvcpus" scsi0.present = "true" scsi0.sharedBus = "none" scsi0.virtualDev = "lsilogic" memsize = "$mem" #set $i = -1 #for $disk in $disks #set $i = $i + 1 #set $bus = $i / 2 #set $id = $i % 2 scsi${bus}:${id}.present = "true" scsi${bus}:${id}.fileName = "${disk}.vmdk" scsi${bus}:${id}.deviceType = "scsi-hardDisk" #end for ide0:0.present = "true" ide0:0.clientDevice = "TRUE" ide0:0.deviceType = "cdrom-raw" ide0:0.startConnected = "FALSE" floppy0.startConnected = "false" floppy0.clientDevice = "true" ethernet0.present = "true" ethernet0.virtualDev = "e1000" ethernet0.networkName = "VM Network" ethernet0.addressType = "generated" guestOSAltName = "$guestos ($arch)" guestOS = "$guestos" toolScripts.afterPowerOn = "true" toolScripts.afterResume = "true" toolScripts.beforeSuspend = "true" toolScripts.beforePowerOff = "true" scsi0:0.redo = "" tools.syncTime = "FALSE" ethernet0.generatedAddressOffset = "0" tools.remindInstall = "TRUE" evcCompatibilityMode = "FALSE" vm-builder-0.12.4+bzr494/VMBuilder/plugins/vmware/templates/flat.vmdk.tmpl0000644000000000000000000000074311122262563024425 0ustar 00000000000000# Disk DescriptorFile for Virtual Disk: $diskname version=1 CID=ffffffff parentCID=ffffffff createType="vmfs" # Extent description RW $disksize FLAT "$diskname" 0 # The Disk Data Base #DDB ddb.toolsVersion = "0" ddb.adapterType = "$adaptertype" ddb.geometry.biosSectors = "$sectors" ddb.geometry.biosHeads = "255" ddb.geometry.biosCylinders = "63" ddb.geometry.sectors = "$sectors" ddb.geometry.heads = "255" ddb.geometry.cylinders = "63" ddb.virtualHWVersion = "4"vm-builder-0.12.4+bzr494/VMBuilder/plugins/vmware/templates/vmware.tmpl0000644000000000000000000000136311341322516024035 0ustar 00000000000000config.version = "8" virtualHW.version = "$vmhwversion" scsi0.present = "FALSE" scsi0.virtualDev = "lsilogic" memsize = "$mem" numvcpus = "$numvcpus" Ethernet0.virtualDev = "vlance" Ethernet0.present = "TRUE" Ethernet0.connectionType = "bridged" #if $mac Ethernet0.addressType = "static" Ethernet0.address = "$mac" #end if displayName = "$hostname $arch" guestOS = "$guestos" priority.grabbed = "normal" priority.ungrabbed = "normal" powerType.powerOff = "hard" powerType.powerOn = "hard" powerType.suspend = "hard" powerType.reset = "hard" floppy0.present = "FALSE" #set $i = -1 #for $disk in $disks #set $i = $i + 1 #set $bus = $i / 2 #set $id = $i % 2 ide${bus}:${id}.present = "TRUE" ide${bus}:${id}.fileName = "${disk.filename}" #end for vm-builder-0.12.4+bzr494/VMBuilder/plugins/xen/__init__.py0000644000000000000000000000136511213733731021247 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # import vm from vm import Xen vm-builder-0.12.4+bzr494/VMBuilder/plugins/xen/vm.py0000644000000000000000000000651411354222630020130 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # from VMBuilder import register_hypervisor, Hypervisor from VMBuilder.util import run_cmd import VMBuilder import VMBuilder.hypervisor import logging import os.path class Xen(Hypervisor): name = 'Xen' arg = 'xen' preferred_storage = VMBuilder.hypervisor.STORAGE_FS_IMAGE needs_bootloader = False def register_options(self): group = self.setting_group('Xen options') group.add_setting('xen-kernel', metavar='PATH', help='Path to the kernel to use (e.g.: /boot/vmlinux-2.6.27-7-server). Default depends on distribution and suite') group.add_setting('xen-ramdisk', metavar='PATH', help='Path to the ramdisk to use (e.g.: /boot/initrd.img-2.6.27-7-server). Default depends on distribution and suite.') group.add_setting('mem', extra_args=['-m'], type='int', default=128, help='Assign MEM megabytes of memory to the guest vm. [default: %default]') def convert(self, filesystems, destdir): destimages = [] for filesystem in filesystems: if not filesystem.preallocated: destfile = '%s/%s' % (destdir, os.path.basename(filesystem.filename)) logging.info('Moving %s to %s' % (filesystem.filename, destfile)) run_cmd('cp', '--sparse=always', filesystem.filename, destfile) self.call_hooks('fix_ownership', destfile) os.unlink(filesystem.filename) filesystem.filename = os.path.abspath(destfile) destimages.append(destfile) if not self.context.get_setting('xen-kernel'): self.context.xen_kernel = self.context.distro.xen_kernel_path() if not self.context.get_setting('xen-ramdisk'): self.context.xen_ramdisk = self.context.distro.xen_ramdisk_path() xenconf = '%s/xen.conf' % destdir fp = open(xenconf, 'w') fp.write(""" # Configuration file for the Xen instance %s, created # by VMBuilder kernel = '%s' ramdisk = '%s' memory = %d root = '/dev/xvda1 ro' disk = [ %s ] name = '%s' dhcp = 'dhcp' vif = [''] on_poweroff = 'destroy' on_reboot = 'restart' on_crash = 'restart' extra = 'xencons=tty console=tty1 console=hvc0' """ % (self.context.distro.get_setting('hostname'), self.context.get_setting('xen-kernel'), self.context.get_setting('xen-ramdisk'), self.context.get_setting('mem'), ',\n'.join(["'tap:aio:%s,xvda%d,w'" % (os.path.abspath(img), id+1) for (img, id) in zip(destimages, range(len(destimages)))]), self.context.distro.get_setting('hostname'))) fp.close() self.call_hooks('fix_ownership', xenconf) register_hypervisor(Xen) vm-builder-0.12.4+bzr494/VMBuilder/tests/__init__.py0000644000000000000000000000132411270273376020140 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . vm-builder-0.12.4+bzr494/VMBuilder/tests/base_test.py0000644000000000000000000000447311341460701020347 0ustar 00000000000000import unittest import VMBuilder import VMBuilder.plugins from VMBuilder.exception import VMBuilderUserError class TestBaseModule(unittest.TestCase): def test_register_distro(self): class TestDistro(): arg = 'test' VMBuilder.register_distro(TestDistro) self.assertEqual(TestDistro, VMBuilder.get_distro('test')) def test_register_hypervisor(self): class TestHypervisor(): arg = 'test' VMBuilder.register_hypervisor(TestHypervisor) self.assertEqual(TestHypervisor, VMBuilder.get_hypervisor('test')) def register_hypervisor_or_distro_plugin(self, plugin_attr_name, register_function): class Plugin(object): priority = 10 class PluginA(Plugin): pass class PluginB(Plugin): priority = 5 class PluginC(Plugin): priority = 15 saved_plugins = getattr(VMBuilder, plugin_attr_name) setattr(VMBuilder, plugin_attr_name, []) register_function(PluginA) register_function(PluginB) register_function(PluginC) self.assertEqual(getattr(VMBuilder, plugin_attr_name)[0], PluginB) self.assertEqual(getattr(VMBuilder, plugin_attr_name)[1], PluginA) self.assertEqual(getattr(VMBuilder, plugin_attr_name)[2], PluginC) setattr(VMBuilder, plugin_attr_name, saved_plugins) def test_register_hypervisor_plugin(self): self.register_hypervisor_or_distro_plugin('_hypervisor_plugins', VMBuilder.register_hypervisor_plugin) def test_register_distro_plugin(self): self.register_hypervisor_or_distro_plugin('_distro_plugins', VMBuilder.register_distro_plugin) def test_unknown_distro(self): self.assertRaises(VMBuilderUserError, VMBuilder.get_distro, 'unknown') def test_unknown_hypervisor(self): self.assertRaises(VMBuilderUserError, VMBuilder.get_hypervisor, 'unknown') def test_set_console_log_level(self): for x in range(50): VMBuilder.set_console_loglevel(x) self.assertEquals(VMBuilder.log.console.level, x) def test_get_version_info(self): info = VMBuilder.get_version_info() self.assertTrue('major' in info) self.assertTrue('minor' in info) self.assertTrue('micro' in info) self.assertTrue('revno' in info) vm-builder-0.12.4+bzr494/VMBuilder/tests/disk_tests.py0000644000000000000000000002340011354222510020537 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . import os import stat import tempfile import unittest import testtools import VMBuilder from VMBuilder.disk import detect_size, parse_size, index_to_devname, devname_to_index, Disk from VMBuilder.exception import VMBuilderException, VMBuilderUserError from VMBuilder.util import run_cmd TestSkipped = testtools.testcase.TestSkipped TestCase = testtools.TestCase def get_temp_filename(): (fd, tmpfile) = tempfile.mkstemp() os.close(fd) return tmpfile class MockDistro(object): def has_256_bit_inode_ext3_support(self): return True class MockHypervisor(object): def __init__(self): self.disks = [] self.distro = MockDistro() def add_clean_cb(self, *args, **kwargs): pass def add_disk(self, *args, **kwargs): disk = Disk(self, *args, **kwargs) self.disks.append(disk) return disk class TestSizeParser(TestCase): def test_suffixesAreCaseInsensitive(self): "Suffixes in size strings are case-insensitive" for letter in ['K', 'M', 'G']: self.assertEqual(parse_size('1%s' % letter), parse_size('1%s' % letter.lower())) def test_suffixless_counts_as_megabytes(self): "Suffix-less size string are counted as megabytes" self.assertEqual(parse_size(10), 10) self.assertEqual(parse_size('10'), 10) def test_M_suffix_counts_as_megabytes(self): "Sizes with M suffix are counted as megabytes" self.assertEqual(parse_size('10M'), 10) def test_G_suffix_counts_as_gigabytes(self): "1G is counted as 1024 megabytes" self.assertEqual(parse_size('1G'), 1024) def test_K_suffix_counts_as_kilobytes(self): "1024K is counted as 1 megabyte" self.assertEqual(parse_size('1024K'), 1) def test_rounds_size_to_nearest_megabyte(self): "parse_size rounds to nearest MB" self.assertEqual(parse_size('1025K'), 1) self.assertEqual(parse_size('10250K'), 10) class TestSequenceFunctions(TestCase): def test_index_to_devname(self): self.assertEqual(index_to_devname(0), 'a') self.assertEqual(index_to_devname(26), 'aa') self.assertEqual(index_to_devname(18277), 'zzz') def test_devname_to_index(self): self.assertEqual(devname_to_index('a'), 0) self.assertEqual(devname_to_index('b'), 1) self.assertEqual(devname_to_index('aa'), 26) self.assertEqual(devname_to_index('ab'), 27) self.assertEqual(devname_to_index('z'), 25) self.assertEqual(devname_to_index('zz'), 701) self.assertEqual(devname_to_index('zzz'), 18277) def test_index_to_devname_and_back(self): for i in range(18277): self.assertEqual(i, devname_to_index(index_to_devname(i))) class TestDetectSize(TestCase): def setUp(self): TestCase.setUp(self) self.tmpfile = get_temp_filename() run_cmd('qemu-img', 'create', self.tmpfile, '5G') self.imgdev = None def test_detect_size_file(self): self.assertTrue(detect_size(self.tmpfile), 5*1024) @testtools.skipIf(os.geteuid() != 0, 'Needs root to run') def test_detect_size_loopback_dev(self): self.imgdev = run_cmd('losetup', '-f', '--show', self.tmpfile).strip() self.assertTrue(detect_size(self.imgdev), 5*1024) def test_detect_size_fifo(self): os.unlink(self.tmpfile) os.mkfifo(self.tmpfile) self.assertRaises(VMBuilderException, detect_size, self.tmpfile) def tearDown(self): TestCase.tearDown(self) run_cmd('udevadm', 'settle') if self.imgdev: run_cmd('losetup', '-d', self.imgdev) os.unlink(self.tmpfile) class TestDiskPlugin(TestCase): def test_disk_filename(self): tmpfile = get_temp_filename() os.unlink(tmpfile) disk = Disk(MockHypervisor(), tmpfile, size='1G') disk.create() self.assertTrue(os.path.exists(tmpfile)) os.unlink(tmpfile) def test_disk_size(self): # parse_size only deals with MB resolution K = 1024 M = K*1024 G = M*1024 sizes = [('10G', 10*G), ('400M', 400*M), ('345', 345*M), ('10240k', 10*M), ('10250k', 10*M), ('10230k', 9*M)] for (sizestr, size) in sizes: tmpfile = get_temp_filename() os.unlink(tmpfile) disk = Disk(MockHypervisor(), filename=tmpfile, size=sizestr) disk.create() actual_size = os.stat(tmpfile)[stat.ST_SIZE] self.assertEqual(size, actual_size, 'Asked for %s, expected %d, got %d' % (sizestr, size, actual_size)) os.unlink(tmpfile) def test_disk_no_size_given(self): tmpname = get_temp_filename() os.unlink(tmpname) self.assertRaises(VMBuilderUserError, Disk, MockHypervisor(), filename=tmpname) def test_disk_size_given_file_exists(self): tmpname = get_temp_filename() self.assertRaises(VMBuilderUserError, Disk, MockHypervisor(), filename=tmpname, size='1G') def test_existing_image_no_overwrite(self): tmpfile = get_temp_filename() fp = open(tmpfile, 'w') fp.write('canary') fp.close() disk = Disk(MockHypervisor(), tmpfile) disk.create() fp = open(tmpfile, 'r') self.assertEqual(fp.read(), 'canary') fp.close() os.unlink(tmpfile) def test_devletters(self): from string import ascii_lowercase hypervisor = MockHypervisor() for (expected_devletter, index) in zip(ascii_lowercase, range(len(ascii_lowercase))): tmpname = get_temp_filename() disk = hypervisor.add_disk(filename=tmpname) devletters = disk.devletters() self.assertEqual(devletters, expected_devletter, 'Disk no. %d returned %s, expected %s.' % (index, devletters, expected_devletter)) class TestDiskPartitioningPlugin(TestCase): def setUp(self): TestCase.setUp(self) self.tmpfile = get_temp_filename() os.unlink(self.tmpfile) self.vm = MockHypervisor() self.disk = self.vm.add_disk(self.tmpfile, size='1G') self.disk.create() def tearDown(self): TestCase.tearDown(self) os.unlink(self.tmpfile) def test_partition_overlap(self): self.disk.add_part(1, 512, 'ext3', '/') self.assertRaises(VMBuilderUserError, self.disk.add_part, 512, 512, 'ext3', '/mnt') def test_partition_extends_beyond_disk(self): self.assertRaises(VMBuilderUserError, self.disk.add_part, 512, 514, 'ext3', '/') def test_partition_table_empty(self): from VMBuilder.util import run_cmd file_output = run_cmd('file', self.tmpfile) self.assertEqual('%s: data' % self.tmpfile, file_output.strip()) self.disk.partition() file_output = run_cmd('file', self.tmpfile) self.assertEqual('%s: x86 boot sector, code offset 0xb8' % self.tmpfile, file_output.strip()) file_output = run_cmd('parted', '--script', self.tmpfile, 'print') self.assertEqual('''Model: (file) Disk %s: 1074MB Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags''' % self.tmpfile, file_output.strip()) def test_partition_table_nonempty(self): from VMBuilder.util import run_cmd self.disk.add_part(1, 1023, 'ext3', '/') self.disk.partition() file_output = run_cmd('parted', '--script', self.tmpfile, 'print') self.assertEqual('''Model: (file) Disk %s: 1074MB Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 1049kB 1023MB 1022MB primary''' % self.tmpfile, file_output.strip()) @testtools.skipIf(os.geteuid() != 0, 'Needs root to run') def test_map_partitions(self): self.disk.add_part(1, 1023, 'ext3', '/') self.disk.partition() self.disk.map_partitions() try: from VMBuilder.disk import detect_size self.assertEqual(detect_size(self.disk.partitions[0].filename), 1023000576) except: raise finally: self.disk.unmap() @testtools.skipIf(os.geteuid() != 0, 'Needs root to run') def test_mkfs(self): self.disk.add_part(1, 1023, 'ext3', '/') self.disk.partition() self.disk.map_partitions() try: self.disk.mkfs() except: raise finally: self.disk.unmap() def test_get_grub_id(self): self.assertEqual(self.disk.get_grub_id(), '(hd0)') tmpfile2 = get_temp_filename() os.unlink(tmpfile2) disk2 = self.vm.add_disk(tmpfile2, '1G') self.assertEqual(self.disk.get_grub_id(), '(hd0)') self.assertEqual(disk2.get_grub_id(), '(hd1)') def test_get_index(self): self.assertEqual(self.disk.get_index(), 0) tmpfile2 = get_temp_filename() os.unlink(tmpfile2) disk2 = self.vm.add_disk(tmpfile2, '1G') self.assertEqual(self.disk.get_index(), 0) self.assertEqual(disk2.get_index(), 1) vm-builder-0.12.4+bzr494/VMBuilder/tests/network_tests.py0000644000000000000000000001140711332043203021276 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . import unittest from VMBuilder.exception import VMBuilderUserError from VMBuilder.plugins import network class TestNetworkPlugin(unittest.TestCase): def test_validate_mac(self): valid_macs = ['11:22:33:44:55:66', 'ff:ff:ff:ff:ff:ff', '00:00:00:00:00:00'] invalid_macs = ['g1:22:33:44:55:66', '11:ff:ff:ff:ff:ff:ff', 'ffffffffffff'] for mac in valid_macs: self.assertTrue(network.validate_mac(mac), '%s was not considered a valid MAC address' % mac) for mac in invalid_macs: self.assertFalse(network.validate_mac(mac), '%s was not considered an invalid MAC address' % mac) def test_dotted_to_numeric_ip(self): valid_ips = ['192.168.1.1', '1.1.1.1', '10.0.0.1', '255.255.255.255'] invalid_ips = ['this is not a valid IP', '256.1.1.1'] for ip in valid_ips: self.assertTrue(network.dotted_to_numeric_ip(ip), '%s was considered a valid IP address' % ip) for ip in invalid_ips: self.assertRaises(VMBuilderUserError, network.dotted_to_numeric_ip, ip) def test_guess_mask_from_ip(self): known_correct_values = [('10.0.0.1', 0xFF), ('127.0.0.1', 0xFF), ('172.17.0.1', 0xFFFF), ('192.168.1.1', 0xFFFFFF)] for ip, nummask in known_correct_values: numip = network.dotted_to_numeric_ip(ip) self.assertEqual(network.guess_mask_from_ip(numip), nummask, "Incorrect netmask guessed") self.assertRaises(VMBuilderUserError, network.guess_mask_from_ip, network.dotted_to_numeric_ip('230.0.0.0')) def test_calculate_net_address_from_ip_and_netmask(self): known_correct_values = [(('192.168.1.1', '255.255.255.0'), '192.168.1.0'), (('192.168.1.1', '255.255.0.0'), '192.168.0.0'), (('192.168.1.1', '255.0.0.0'), '192.0.0.0'), (('192.168.1.1', '255.242.255.0'), '192.160.1.0'), (('192.168.1.1', '0.255.255.0'), '0.168.1.0')] for ((ip, netmask), expected_network) in known_correct_values: numip = network.dotted_to_numeric_ip(ip) numnetmask = network.dotted_to_numeric_ip(netmask) self.assertEqual(network.calculate_net_address_from_ip_and_netmask(numip, numnetmask), network.dotted_to_numeric_ip(expected_network)) def test_calculate_broadcast_address_from_ip_and_netmask(self): known_correct_values = [(('192.168.1.0', '255.255.255.0'), '192.168.1.255'), (('192.168.0.0', '255.255.0.0'), '192.168.255.255'), (('192.0.0.0', '255.0.0.0'), '192.255.255.255'), (('192.160.1.0', '255.242.255.0'), '192.173.1.255'), (('0.168.1.0', '0.255.255.0'), '255.168.1.255')] for ((ip, netmask), expected_bcast) in known_correct_values: numip = network.dotted_to_numeric_ip(ip) numnetmask = network.dotted_to_numeric_ip(netmask) guessed_broadcast = network.calculate_broadcast_address_from_ip_and_netmask(numip, numnetmask) self.assertEqual(guessed_broadcast, network.dotted_to_numeric_ip(expected_bcast), "%s %s made %s, but expected %s" % (ip, netmask, network.numeric_to_dotted_ip(guessed_broadcast), expected_bcast)) def test_ip_conversion(self): for x in xrange(256*256): self.assertEqual(x*x, network.dotted_to_numeric_ip(network.numeric_to_dotted_ip(x*x))) vm-builder-0.12.4+bzr494/VMBuilder/tests/plugin_tests.py0000644000000000000000000001363411341605236021121 0ustar 00000000000000import unittest import VMBuilder.plugins from VMBuilder.exception import VMBuilderException class TestPluginsSettings(unittest.TestCase): class VM(VMBuilder.plugins.Plugin): def __init__(self, *args, **kwargs): self._config = {} self.context = self class TestPlugin(VMBuilder.plugins.Plugin): pass def setUp(self): self.vm = self.VM() self.plugin = self.TestPlugin(self.vm) self.i = 0 def test_add_setting_group_and_setting(self): setting_group = self.plugin.setting_group('Test Setting Group') self.assertTrue(setting_group in self.plugin._setting_groups, "Setting not added correctly to plugin's registry of setting groups.") setting_group.add_setting('testsetting') self.assertEqual(self.vm.get_setting('testsetting'), None, "Setting's default value is not None.") self.vm.set_setting_default('testsetting', 'newdefault') self.assertEqual(self.vm.get_setting('testsetting'), 'newdefault', "Setting does not return custom default value when no value is set.") self.assertEqual(self.vm.get_setting_default('testsetting'), 'newdefault', "Setting does not return custom default value through get_setting_default().") self.vm.set_setting('testsetting', 'foo') self.assertEqual(self.vm.get_setting('testsetting'), 'foo', "Setting does not return set value.") self.vm.set_setting_default('testsetting', 'newerdefault') self.assertEqual(self.vm.get_setting('testsetting'), 'foo', "Setting does not return set value after setting new default value.") def test_invalid_type_raises_exception(self): setting_group = self.plugin.setting_group('Test Setting Group') self.assertRaises(VMBuilderException, setting_group.add_setting, 'oddsetting', type='odd') def test_valid_options(self): setting_group = self.plugin.setting_group('Test Setting Group') setting_group.add_setting('strsetting') self.assertRaises(VMBuilderException, self.vm.set_setting_valid_options, 'strsetting', '') self.vm.set_setting_valid_options('strsetting', ['foo', 'bar']) self.assertEqual(self.vm.get_setting_valid_options('strsetting'), ['foo', 'bar']) self.vm.set_setting('strsetting', 'foo') self.assertRaises(VMBuilderException, self.vm.set_setting, 'strsetting', 'baz') self.vm.set_setting_valid_options('strsetting', None) self.vm.set_setting('strsetting', 'baz') def test_invalid_type_setting_raises_exception(self): setting_group = self.plugin.setting_group('Test Setting Group') test_table = [{ 'type' : 'str', 'good' : [''], 'fuzzy': [''], 'bad' : [0, True, ['foo']] }, { 'type' : 'int', 'good' : [0], 'fuzzy': [('0', 0), ('34', 34), (0, 0), (34, 34)], 'bad' : ['', '0', True, ['foo']] }, { 'type' : 'bool', 'good' : [True], 'fuzzy': [(True, True), ('tRuE', True), ('oN', True), ('yEs', True), ('1', True), (False, False), ('fAlSe', False), ('oFf', False), ('nO', False), ('0', False) ], 'bad' : ['', 0, '0', ['foo'], '1'] }, { 'type' : 'list', 'good' : [['foo']], 'fuzzy': [('main , universe,multiverse', ['main', 'universe', 'multiverse']), ('main:universe:multiverse', ['main', 'universe', 'multiverse']), ('''main: universe:multiverse''', ['main', 'universe', 'multiverse']), ('', [])], 'bad' : [True, '', 0, '0'] }] def get_new_setting(setting_type): setting_name = '%ssetting%d' % (setting_type, self.i) self.i += 1 setting_group.add_setting(setting_name, type=setting_type) return setting_name def try_bad_setting(setting_type, bad, setter): setting_name = get_new_setting(setting_type) self.assertRaises(VMBuilderException, setter, setting_name, bad) def try_good_setting(setting_type, good, getter, setter): setting_name = get_new_setting(setting_type) if type(good) == tuple: in_value, out_value = good else: in_value, out_value = good, good # print setting_name, in_value setter(setting_name, in_value) self.assertEqual(getter(setting_name), out_value) for setting_type in test_table: for good in setting_type['good']: try_good_setting(setting_type['type'], good, self.vm.get_setting, self.vm.set_setting) try_good_setting(setting_type['type'], good, self.vm.get_setting, self.vm.set_setting_default) try_good_setting(setting_type['type'], good, self.vm.get_setting_default, self.vm.set_setting_default) try_good_setting(setting_type['type'], good, self.vm.get_setting, self.vm.set_setting_fuzzy) for fuzzy in setting_type['fuzzy']: try_good_setting(setting_type['type'], fuzzy, self.vm.get_setting, self.vm.set_setting_fuzzy) for bad in setting_type['bad']: try_bad_setting(setting_type['type'], bad, self.vm.set_setting) try_bad_setting(setting_type['type'], bad, self.vm.set_setting_default) def test_set_setting_raises_exception_on_invalid_setting(self): self.assertRaises(VMBuilderException, self.vm.set_setting_default, 'testsetting', 'newdefault') def test_add_setting(self): setting_group = self.plugin.setting_group('Test Setting Group') vm-builder-0.12.4+bzr494/VMBuilder/tests/ubuntu_tests.py0000644000000000000000000000246411341723114021140 0ustar 00000000000000# # Uncomplicated VM Builder # Copyright (C) 2007-2009 Canonical Ltd. # # See AUTHORS for list of contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # # Tests, tests, tests, and more tests import logging import unittest import VMBuilder from VMBuilder.plugins.ubuntu.distro import Ubuntu from VMBuilder.exception import VMBuilderUserError from VMBuilder import set_console_loglevel class TestUbuntuPlugin(unittest.TestCase): def setUp(self): set_console_loglevel(logging.INFO) def test_invalid_suite_raises_UserError(self): 'Building Ubuntu VMs with an invalid suite raises UserError' ubuntu = Ubuntu() ubuntu.set_setting('suite', 'foo') self.assertRaises(VMBuilderUserError, ubuntu.preflight_check) vm-builder-0.12.4+bzr494/VMBuilder/tests/util_tests.py0000644000000000000000000000034311341714423020570 0ustar 00000000000000import unittest import VMBuilder from VMBuilder.util import run_cmd class TestUtils(unittest.TestCase): def test_run_cmd(self): self.assertTrue("foobarbaztest" in run_cmd("env", env={'foobarbaztest' : 'bar' })) vm-builder-0.12.4+bzr494/examples/ec2-amd64-part-file.txt0000644000000000000000000000003511534170721020645 0ustar 00000000000000root 2048 a1 rootfs /mnt 1 b vm-builder-0.12.4+bzr494/examples/ec2-firstboot.sh0000755000000000000000000000111311106345705017661 0ustar 00000000000000#!/bin/bash # # Regenerate the ssh host key # rm -f /etc/ssh/ssh_host_*_key* ssh-keygen -f /etc/ssh/ssh_host_rsa_key -t rsa -N '' | logger -s -t "ec2" ssh-keygen -f /etc/ssh/ssh_host_dsa_key -t dsa -N '' | logger -s -t "ec2" # This allows user to get host keys securely through console log echo "-----BEGIN SSH HOST KEY FINGERPRINTS-----" | logger -s -t "ec2" ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key.pub | logger -s -t "ec2" ssh-keygen -l -f /etc/ssh/ssh_host_dsa_key.pub | logger -s -t "ec2" echo "-----END SSH HOST KEY FINGERPRINTS-----" | logger -s -t "ec2" depmod -a exit 0 vm-builder-0.12.4+bzr494/examples/ec2-firstlogin.sh0000755000000000000000000000243511106345705020036 0ustar 00000000000000#!/bin/bash trap cleanup 1 2 3 6 cleanup() { exit 1 } ACCOUNT="ubuntu" echo echo "======================================================" echo "CONFIGURATION OF YOUR UBUNTU EC2 IMAGE" echo "======================================================" echo "Your EC2 image is about to be finished to be set up." echo echo "------------------------------------------------------" PASSWORD=$(uuidgen -r | head -c8) echo "New password for ${ACCOUNT} account: ${PASSWORD}" echo "ubuntu:${PASSWORD}" | chpasswd -m passwd -u ${ACCOUNT} echo "Setting up ssh public keys for the ${ACCOUNT} account." [ ! -e /home/${ACCOUNT}/.ssh ] && mkdir -p /home/${ACCOUNT}/.ssh cp -a /root/.ssh/authorized_keys* /home/${ACCOUNT}/.ssh chown -R ${ACCOUNT}:${ACCOUNT} /home/${ACCOUNT}/.ssh echo echo "------------------------------------------------------" echo "Please select software that you wish to install:" tasksel --section server echo echo "------------------------------------------------------" echo echo "We are now going to log you out of the root account." echo "To perform administrative tasks please use the ${ACCOUNT} account" echo "in combination with sudo using the password: ${PASSWORD}" echo echo "======================================================" echo touch /root/firstlogin_done kill -HUP $PPID vm-builder-0.12.4+bzr494/examples/ec2-i386-part-file.txt0000644000000000000000000000006011534170721020421 0ustar 00000000000000root 2048 a1 rootfs /mnt 1 a2 swap 1024 a3 swap