VirtualBox integration

This commit is contained in:
Anders Ingemann 2014-11-30 00:33:42 +01:00
parent 0f8dbb7ac3
commit 65b9e10ce3
10 changed files with 188 additions and 53 deletions

View file

@ -34,7 +34,7 @@ class SSHRPCManager(object):
'-R' + str(self.remote_callback_port) + ':localhost:' + str(self.local_callback_port),
self.settings['username'] + '@' + self.settings['address'],
'--',
'sudo', self.settings['server-bin'],
'sudo', self.settings['server_bin'],
'--listen', str(self.remote_server_port)]
import sys
self.ssh_process = subprocess.Popen(args=ssh_cmd, stdout=sys.stderr, stderr=sys.stderr)

View file

@ -1,3 +0,0 @@
---
virtualbox:
guest_additions: /root/images/VBoxGuestAdditions.iso

View file

@ -1,4 +0,0 @@
from bootstrapvz.common.tools import load_data
# tox makes sure that the cwd is the project root
build_settings = load_data('build_settings.yml')

View file

@ -1,21 +0,0 @@
class Image(object):
def create_instance(self):
return Instance()
def destroy(self):
pass
class Instance(object):
def boot(self):
pass
def shutdown(self):
pass
def destroy(self):
pass

View file

@ -1,6 +1,7 @@
from bootstrapvz.common.tools import load_data
from build_servers import LocalBuildServer
from build_servers import RemoteBuildServer
build_servers = load_data('build_servers.yml')
# Snatched from here: http://stackoverflow.com/a/7205107
def merge_dicts(*args):
@ -21,20 +22,30 @@ def merge_dicts(*args):
return reduce(merge, args, {})
def bootstrap(manifest):
# if 'build_host' in build_settings:
# run = get_remote_run(build_settings)
# else:
# run = __import__('bootstrapvz.base.run')
# run(manifest)
from bootstrapvz.base.remote.remote import run
run(manifest,
build_servers['virtualbox'],
debug=True,
dry_run=True)
def pick_build_server(manifest):
if manifest['provider']['name'] == 'ec2':
img_type = 'ec2-' + manifest['volume']['backing']
else:
img_type = manifest['provider']['name']
from ..image import Image
return Image()
# tox makes sure that the cwd is the project root
build_servers = load_data('build_servers.yml')
settings = next((server for name, server in build_servers.iteritems() if img_type in server['can_bootstrap']), None)
if settings['type'] == 'local':
return LocalBuildServer(settings)
else:
return RemoteBuildServer(settings)
def test_instance(instance):
def bootstrap(manifest, build_server):
if isinstance(build_server, LocalBuildServer):
from bootstrapvz.base.main import run
bootstrap_info = run(manifest)
else:
from bootstrapvz.base.remote.remote import run
bootstrap_info = run(manifest, build_server.settings)
return bootstrap_info
def test(instance):
pass

View file

@ -0,0 +1,40 @@
from bootstrapvz.common.tools import log_check_call
class BuildServer(object):
def __init__(self, settings):
self.settings = settings
self.build_settings = settings.get('build_settings', None)
self.can_bootstrap = settings['can_bootstrap']
self.release = settings.get('release', None)
class LocalBuildServer(BuildServer):
pass
class RemoteBuildServer(BuildServer):
def __init__(self, settings):
self.address = settings['address']
self.port = settings['port']
self.username = settings['username']
self.password = settings['password']
self.root_password = settings['root_password']
self.keyfile = settings['keyfile']
self.server_bin = settings['server_bin']
super(RemoteBuildServer, self).__init__(settings)
def download(self, src, dst):
src_arg = '{user}@{host}:{path}'.format(self.username, self.address, src)
log_check_call(['scp', '-i', self.keyfile, '-P', self.port,
src_arg, dst])
def delete(self, path):
ssh_cmd = ['ssh', '-i', self.settings['keyfile'],
'-p', str(self.settings['port']),
self.username + '@' + self.address,
'--',
'sudo', 'rm', path]
log_check_call(ssh_cmd)

View file

@ -0,0 +1,25 @@
class Image(object):
def __init__(self, manifest):
self.manifest = manifest
def destroy(self):
pass
class VirtualBoxImage(Image):
def __init__(self, manifest, image_path):
super(VirtualBoxImage, self).__init__(manifest)
self.image_path = image_path
self.medium = self.vbox.open_medium(location=self.image.image_path,
decive_type=self.vbox.library.DeviceType.HardDisk,
access_mode=self.vbox.library.AccessMode.read_only,
force_new_uuid=False)
def destroy(self):
self.medium.delete_storage()
import os
os.remove(self.image_path)

View file

@ -0,0 +1,69 @@
from bootstrapvz.common.tools import log_check_call
class Instance(object):
def __init__(self, name, image):
self.name = name
self.image = image
def boot(self):
pass
def shutdown(self):
pass
def destroy(self):
pass
class VirtualBoxInstance(Instance):
cpus = 1
memory = 256
def __init__(self, name, image):
super(VirtualBoxInstance, self).__init__(name, image)
import virtualbox
self.vbox = virtualbox.VirtualBox()
def create(self):
if self.image.manifest['system']['architecture'] == 'x86':
os_type = 'Debian'
else:
os_type = 'Debian_64'
self.machine = self.vbox.create_machine(settings_file='', name=self.name,
groups=[], os_type_id=os_type, flags='')
self.machine.save_settings()
self.machine.cpu_count = self.cpus
self.machine.memory_size = self.memory
self.machine.attach_device(name='root', controller_port=0, device=0,
type_p=self.vbox.library.DeviceType.HardDisk,
medium=self.image.medium)
self.vbox.register_machine(self.machine)
# [self.uuid] = log_check_call(['VBoxManage', 'createvm'
# '--name', self.name])
# log_check_call(['VBoxManage', 'modifyvm', self.uuid,
# '--cpus', self.cpus,
# '--memory', self.memory])
# log_check_call(['VBoxManage', 'storageattach', self.uuid,
# '--storagectl', '"SATA Controller"',
# '--device', '0',
# '--port', '0',
# '--type', 'hdd',
# '--medium', self.image.image_path])
def boot(self):
self.session = self.vbox.Session()
self.machine.launch_vm_process(self.session, 'headless')
# log_check_call(['VBoxManage', 'startvm', self.uuid,
# '--type', 'headless'])
def shutdown(self):
self.session.console.power_down()
log_check_call(['VBoxManage', 'stopvm', self.uuid,
'--type', 'headless'])
def destroy(self):
self.machine.unregister(self.vbox.CleanupMode.full)
self.machine.remove(delete=True)

View file

@ -1,6 +1,5 @@
import tools
from manifests import partials
from . import build_settings
def test_virtualbox_unpartitioned_extlinux():
@ -8,22 +7,40 @@ def test_virtualbox_unpartitioned_extlinux():
specific_settings = yaml.load("""
provider:
name: virtualbox
guest_additions: {guest_additions}
system:
bootloader: extlinux
volume:
backing: vdi
partitions:
type: msdos
""".format(guest_additions=build_settings['virtualbox']['guest_additions']))
""")
manifest = tools.merge_dicts(partials['base'], partials['stable64'],
partials['unpartitioned'], specific_settings)
image = tools.bootstrap(manifest)
instance = image.create_instance()
instance.boot()
build_server = tools.pick_build_server(manifest)
manifest['provider']['guest_additions'] = build_server.build_settings['guest_additions']
tools.test_instance(instance)
bootstrap_info = tools.bootstrap(manifest, build_server)
instance.destroy()
image.destroy()
if isinstance(build_server, tools.build_servers.LocalBuildServer):
image_path = bootstrap_info.volume.image_path
else:
import tempfile
handle, image_path = tempfile.mkstemp()
handle.close()
build_server.download(bootstrap_info.volume.image_path, image_path)
build_server.delete(bootstrap_info.volume.image_path)
try:
image = tools.images.VirtualBoxImage(manifest, image_path)
instance = tools.instances.VirtualBoxInstance(image)
instance.create()
instance.boot()
tools.test(instance)
finally:
if 'instance' in locals():
instance.destroy()
if 'image' in locals():
image.destroy()

View file

@ -19,6 +19,7 @@ commands = nosetests -v tests/unit --with-coverage --cover-package=bootstrapvz -
deps =
nose
Pyro4 >= 4.26
pyvbox >= 0.2.0
commands = nosetests -v tests/integration --with-coverage --cover-package=bootstrapvz --cover-inclusive
[testenv:docs]