diff options
author | Lars Wirzenius <lars.wirzenius@codethink.co.uk> | 2013-01-24 15:08:18 +0000 |
---|---|---|
committer | Lars Wirzenius <lars.wirzenius@codethink.co.uk> | 2013-02-06 20:58:46 +0000 |
commit | a77e0639a0b5521105e0bdc4d8021ee99de8f72f (patch) | |
tree | 0b3d464c5e814222b8baaecb20b04a7040a02b65 /morphlib/exts | |
parent | 35ec60c76bca93615a2230a5e318738a2fa460e6 (diff) | |
download | morph-a77e0639a0b5521105e0bdc4d8021ee99de8f72f.tar.gz |
Add a write extension for VirtualBox
Diffstat (limited to 'morphlib/exts')
-rwxr-xr-x | morphlib/exts/virtualbox-ssh.write | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/morphlib/exts/virtualbox-ssh.write b/morphlib/exts/virtualbox-ssh.write new file mode 100755 index 00000000..e2f592e7 --- /dev/null +++ b/morphlib/exts/virtualbox-ssh.write @@ -0,0 +1,158 @@ +#!/usr/bin/python +# Copyright (C) 2012-2013 Codethink Limited +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +'''A Morph deployment write extension for deploying to VirtualBox via ssh. + +VirtualBox is assumed to be running on a remote machine, which is +accessed over ssh. The machine gets created, but not started. + +''' + + +import os +import re +import time +import tempfile +import urlparse + +import morphlib.writeexts + + +class VirtualBoxPlusSshWriteExtension(morphlib.writeexts.WriteExtension): + + '''Create a VirtualBox virtual machine during Morph's deployment. + + The location command line argument is the pathname of the disk image + to be created. The user is expected to provide the location argument + using the following syntax: + + vbox+ssh://HOST/GUEST/PATH + + where: + + * HOST is the host on which VirtualBox is running + * GUEST is the name of the guest virtual machine on that host + * PATH is the path to the disk image that should be created, + on that host + + The extension will connect to HOST via ssh to run VirtualBox's + command line management tools. + + ''' + + def process_args(self, args): + if len(args) != 2: + raise cliapp.AppException('Wrong number of command line args') + + temp_root, location = args + ssh_host, vm_name, vdi_path = self.parse_location(location) + + self.status( + msg='Temporary system root: %(temp_root)s', + temp_root=temp_root) + self.status( + msg='VirtualBox server: %(ssh_host)s', + ssh_host=ssh_host) + self.status( + msg='VirtualBox guest: %(vm_name)s', + vm_name=vm_name) + + size = self.get_disk_size() + self.status(msg='Disk size is %(size)d bytes', size=size) + + raw_disk = tempfile.mkstemp() + self.create_raw_disk_image(raw_disk, size) + try: + self.mkfs_btrfs(raw_disk) + mp = self.mount(raw_disk) + except BaseException: + self.status('EEEK') + os.remove(raw_disk) + raise + try: + self.create_factory(mp, temp_root) + self.create_fstab(mp) + self.install_extlinux(mp) + except BaseException, e: + self.status(msg='EEK') + self.unmount(mp) + os.remove(raw_disk) + raise + else: + self.unmount(mp) + + try: + self.transfer_and_convert_to_vdi( + raw_disk, size, ssh_host, vdi_path) + self.create_virtualbox_guest(ssh_host, vm_name, vdi_path) + except BaseException: + self.status('EEEK') + os.remove(raw_disk) + raise + else: + os.remove(raw_disk) + + self.status( + msg='Virtual machine %(vm_name)s has been created', + vm_name=vm_name) + + def parse_location(self, location): + '''Parse the location argument to get relevant data.''' + + x = urlparse.urlparse(location) + if x.scheme != 'vbox+ssh': + raise cliapp.AppException( + 'URL schema must be vbox+ssh in %s' % location) + m = re.match('^/(?P<guest>[^/]+)(?P<path>/.+)$', x.path) + if not m: + raise cliapp.AppException('Cannot parse location %s' % location) + return x.netloc, m.group('guest'), m.group('path') + + def transfer_and_convert_to_vdi(self, raw_disk, size, ssh_host, vdi_path): + '''Transfer raw disk image to VirtualBox host, and convert to VDI.''' + + self.status(msg='Transfer disk and convert to VDI') + with open(raw_disk, 'rb') as f: + cliapp.runcmd( + ['ssh', ssh_host, + 'VBoxManage', 'convertfromraw', 'stdin', vdi_path, str(size)], + stdin=f) + + def create_virtualbox_guest(self, ssh_host, vm_name, vdi_path): + '''Create the VirtualBox virtual machine.''' + + self.status(msg='Create VirtualBox virtual machine') + + commands = [ + ['createvm', '--name', vm_name, '--ostype', 'Linux26_64', + '--register'], + ['modifyvm', vm_name, '--ioapic', 'on', '--memory', '1024', + '--nic1', 'nat'], + ['storagectl', vm_name, '--name', '"SATA Controller"', + '--add', 'sata', '--bootable', 'on', '--sataportcount', '2'], + ['storageattach', vm_name, '--storagectl', '"SATA Controller"', + '--port', '0', '--device', '0', '--type', 'hdd', '--medium', + vdi_path], + ] + + for command in commands: + argv = ['ssh', ssh_host, 'VBoxManage'] + command + cliapp.runcmd(argv) + + +VirtualBoxPlusSshWriteExtension().run() + |