summaryrefslogtreecommitdiff
path: root/morphlib/exts/kvm.write
diff options
context:
space:
mode:
authorLars Wirzenius <lars.wirzenius@codethink.co.uk>2013-01-24 15:41:11 +0000
committerLars Wirzenius <lars.wirzenius@codethink.co.uk>2013-02-06 20:58:46 +0000
commitdfd854a0c1ce312ec20b91762be9a344d9c47417 (patch)
tree75d74bc59577de2d4dea965896eab6dc146c490e /morphlib/exts/kvm.write
parenta77e0639a0b5521105e0bdc4d8021ee99de8f72f (diff)
downloadmorph-dfd854a0c1ce312ec20b91762be9a344d9c47417.tar.gz
Add a write extension for kvm+libvirt
Diffstat (limited to 'morphlib/exts/kvm.write')
-rwxr-xr-xmorphlib/exts/kvm.write140
1 files changed, 140 insertions, 0 deletions
diff --git a/morphlib/exts/kvm.write b/morphlib/exts/kvm.write
new file mode 100755
index 00000000..ed85b17e
--- /dev/null
+++ b/morphlib/exts/kvm.write
@@ -0,0 +1,140 @@
+#!/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 KVM+libvirt.'''
+
+
+import os
+import re
+import urlparse
+
+import morphlib.writeexts
+
+
+class KvmPlusSshWriteExtension(morphlib.writeexts.WriteExtension):
+
+ '''Create a KVM/LibVirt 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:
+
+ kvm+ssh://HOST/GUEST/PATH
+
+ where:
+
+ * HOST is the host on which KVM/LibVirt 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 libvirt'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, vm_path = self.parse_location(location)
+
+ self.status(
+ msg='Temporary system root: %(temp_root)s',
+ temp_root=temp_root)
+ self.status(
+ msg='libvirt server: %(ssh_host)s',
+ ssh_host=ssh_host)
+ self.status(
+ msg='libvirt guest: %(vm_name)s',
+ vm_name=vm_name)
+ self.status(
+ msg='libvirt disk image: %(vm_path)s',
+ vm_path=vm_path)
+
+ 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(msg='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(raw_disk, size, ssh_host, vm_path)
+ self.create_libvirt_guest(ssh_host, vm_name, vm_path)
+ except BaseException:
+ self.status(msg='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 != 'kvm+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(self, raw_disk, size, ssh_host, vm_path):
+ '''Transfer raw disk image to libvirt host.'''
+
+ self.status(msg='Transfer disk image')
+ target = '%s:%s' % (ssh_host, vm_path)
+ with open(raw_disk, 'rb') as f:
+ cliapp.runcmd(['rsync', '-zS', raw_disk, target])
+
+ def create_libvirt_guest(self, ssh_host, vm_name, vm_path):
+ '''Create the libvirt virtual machine.'''
+
+ self.status(msg='Create libvirt/kvm virtual machine')
+ cliapp.runcmd(
+ ['ssh', ssh_host,
+ 'virt-install', '--connect qemu:///system', '--import',
+ '--name', vm_name, '--ram', '1024', '--vnc', '--noreboot',
+ '--disk path=%s,bus=ide' % vm_path])
+
+
+KvmPlusSshWriteExtension().run()
+