summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <lars.wirzenius@codethink.co.uk>2013-01-24 15:08:18 +0000
committerLars Wirzenius <lars.wirzenius@codethink.co.uk>2013-02-06 20:58:46 +0000
commita77e0639a0b5521105e0bdc4d8021ee99de8f72f (patch)
tree0b3d464c5e814222b8baaecb20b04a7040a02b65
parent35ec60c76bca93615a2230a5e318738a2fa460e6 (diff)
downloadmorph-a77e0639a0b5521105e0bdc4d8021ee99de8f72f.tar.gz
Add a write extension for VirtualBox
-rwxr-xr-xmorphlib/exts/virtualbox-ssh.write158
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()
+