#!/usr/bin/python
# Copyright (C) 2012-2015 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, see .
'''A Morph deployment write extension for deploying to KVM+libvirt.
See file kvm.write.help for documentation
'''
import os
import re
import subprocess
import sys
import tempfile
import urlparse
import writeexts
class KvmPlusSshWriteExtension(writeexts.WriteExtension):
location_pattern = '^/(?P[^/]+)(?P/.+)$'
def process_args(self, args):
if len(args) != 2:
raise writeexts.ExtensionError(
'Wrong number of command line args')
temp_root, location = args
ssh_host, vm_name, vm_path = self.parse_location(location)
autostart = self.get_environment_boolean('AUTOSTART')
fd, raw_disk = tempfile.mkstemp()
os.close(fd)
self.create_local_system(temp_root, raw_disk)
try:
self.transfer(raw_disk, ssh_host, vm_path)
self.create_libvirt_guest(ssh_host, vm_name, vm_path, autostart)
except BaseException:
sys.stderr.write('Error deploying to libvirt')
os.remove(raw_disk)
writeexts.ssh_runcmd(ssh_host, ['rm', '-f', vm_path])
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)
m = re.match('^/(?P[^/]+)(?P/.+)$', x.path)
return x.netloc, m.group('guest'), m.group('path')
def transfer(self, raw_disk, ssh_host, vm_path):
'''Transfer raw disk image to libvirt host.'''
self.status(msg='Transferring disk image')
xfer_hole_path = writeexts.get_data_path('xfer-hole')
recv_hole = writeexts.get_data('recv-hole')
ssh_remote_cmd = [
'sh', '-c', recv_hole, 'dummy-argv0', 'file', vm_path
]
xfer_hole_proc = subprocess.Popen(
['python', xfer_hole_path, raw_disk],
stdout=subprocess.PIPE)
recv_hole_proc = subprocess.Popen(
['ssh', ssh_host] + map(writeexts.shell_quote, ssh_remote_cmd),
stdin=xfer_hole_proc.stdout)
xfer_hole_proc.stdout.close()
recv_hole_proc.communicate()
def create_libvirt_guest(self, ssh_host, vm_name, vm_path, autostart):
'''Create the libvirt virtual machine.'''
self.status(msg='Creating libvirt/kvm virtual machine')
attach_disks = self.parse_attach_disks()
attach_opts = []
for disk in attach_disks:
attach_opts.extend(['--disk', 'path=%s' % disk])
if 'NIC_CONFIG' in os.environ:
nics = os.environ['NIC_CONFIG'].split()
for nic in nics:
attach_opts.extend(['--network', nic])
ram_mebibytes = str(self.get_ram_size() / (1024**2))
vcpu_count = str(self.get_vcpu_count())
cmdline = ['virt-install', '--connect', 'qemu:///system',
'--import', '--name', vm_name, '--vnc',
'--ram', ram_mebibytes, '--vcpus', vcpu_count,
'--disk', 'path=%s,bus=ide' % vm_path] + attach_opts
if not autostart:
cmdline += ['--noreboot']
writeexts.ssh_runcmd(ssh_host, cmdline)
if autostart:
writeexts.ssh_runcmd(ssh_host,
['virsh', '--connect', 'qemu:///system',
'autostart', vm_name])
KvmPlusSshWriteExtension().run()