mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-24 15:36:27 +00:00
VirtualBox integration
This commit is contained in:
parent
0f8dbb7ac3
commit
65b9e10ce3
10 changed files with 188 additions and 53 deletions
|
@ -34,7 +34,7 @@ class SSHRPCManager(object):
|
||||||
'-R' + str(self.remote_callback_port) + ':localhost:' + str(self.local_callback_port),
|
'-R' + str(self.remote_callback_port) + ':localhost:' + str(self.local_callback_port),
|
||||||
self.settings['username'] + '@' + self.settings['address'],
|
self.settings['username'] + '@' + self.settings['address'],
|
||||||
'--',
|
'--',
|
||||||
'sudo', self.settings['server-bin'],
|
'sudo', self.settings['server_bin'],
|
||||||
'--listen', str(self.remote_server_port)]
|
'--listen', str(self.remote_server_port)]
|
||||||
import sys
|
import sys
|
||||||
self.ssh_process = subprocess.Popen(args=ssh_cmd, stdout=sys.stderr, stderr=sys.stderr)
|
self.ssh_process = subprocess.Popen(args=ssh_cmd, stdout=sys.stderr, stderr=sys.stderr)
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
virtualbox:
|
|
||||||
guest_additions: /root/images/VBoxGuestAdditions.iso
|
|
|
@ -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')
|
|
|
@ -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
|
|
|
@ -1,6 +1,7 @@
|
||||||
from bootstrapvz.common.tools import load_data
|
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
|
# Snatched from here: http://stackoverflow.com/a/7205107
|
||||||
def merge_dicts(*args):
|
def merge_dicts(*args):
|
||||||
|
@ -21,20 +22,30 @@ def merge_dicts(*args):
|
||||||
return reduce(merge, args, {})
|
return reduce(merge, args, {})
|
||||||
|
|
||||||
|
|
||||||
def bootstrap(manifest):
|
def pick_build_server(manifest):
|
||||||
# if 'build_host' in build_settings:
|
if manifest['provider']['name'] == 'ec2':
|
||||||
# run = get_remote_run(build_settings)
|
img_type = 'ec2-' + manifest['volume']['backing']
|
||||||
# else:
|
else:
|
||||||
# run = __import__('bootstrapvz.base.run')
|
img_type = manifest['provider']['name']
|
||||||
# run(manifest)
|
|
||||||
|
# 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 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
|
from bootstrapvz.base.remote.remote import run
|
||||||
run(manifest,
|
bootstrap_info = run(manifest, build_server.settings)
|
||||||
build_servers['virtualbox'],
|
return bootstrap_info
|
||||||
debug=True,
|
|
||||||
dry_run=True)
|
|
||||||
|
|
||||||
from ..image import Image
|
|
||||||
return Image()
|
|
||||||
|
|
||||||
def test_instance(instance):
|
def test(instance):
|
||||||
pass
|
pass
|
||||||
|
|
40
tests/integration/tools/build_servers.py
Normal file
40
tests/integration/tools/build_servers.py
Normal 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)
|
25
tests/integration/tools/images.py
Normal file
25
tests/integration/tools/images.py
Normal 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)
|
69
tests/integration/tools/instances.py
Normal file
69
tests/integration/tools/instances.py
Normal 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)
|
|
@ -1,6 +1,5 @@
|
||||||
import tools
|
import tools
|
||||||
from manifests import partials
|
from manifests import partials
|
||||||
from . import build_settings
|
|
||||||
|
|
||||||
|
|
||||||
def test_virtualbox_unpartitioned_extlinux():
|
def test_virtualbox_unpartitioned_extlinux():
|
||||||
|
@ -8,22 +7,40 @@ def test_virtualbox_unpartitioned_extlinux():
|
||||||
specific_settings = yaml.load("""
|
specific_settings = yaml.load("""
|
||||||
provider:
|
provider:
|
||||||
name: virtualbox
|
name: virtualbox
|
||||||
guest_additions: {guest_additions}
|
|
||||||
system:
|
system:
|
||||||
bootloader: extlinux
|
bootloader: extlinux
|
||||||
volume:
|
volume:
|
||||||
backing: vdi
|
backing: vdi
|
||||||
partitions:
|
partitions:
|
||||||
type: msdos
|
type: msdos
|
||||||
""".format(guest_additions=build_settings['virtualbox']['guest_additions']))
|
""")
|
||||||
manifest = tools.merge_dicts(partials['base'], partials['stable64'],
|
manifest = tools.merge_dicts(partials['base'], partials['stable64'],
|
||||||
partials['unpartitioned'], specific_settings)
|
partials['unpartitioned'], specific_settings)
|
||||||
|
|
||||||
image = tools.bootstrap(manifest)
|
build_server = tools.pick_build_server(manifest)
|
||||||
instance = image.create_instance()
|
manifest['provider']['guest_additions'] = build_server.build_settings['guest_additions']
|
||||||
|
|
||||||
|
bootstrap_info = tools.bootstrap(manifest, build_server)
|
||||||
|
|
||||||
|
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()
|
instance.boot()
|
||||||
|
|
||||||
tools.test_instance(instance)
|
tools.test(instance)
|
||||||
|
finally:
|
||||||
|
if 'instance' in locals():
|
||||||
instance.destroy()
|
instance.destroy()
|
||||||
|
if 'image' in locals():
|
||||||
image.destroy()
|
image.destroy()
|
||||||
|
|
1
tox.ini
1
tox.ini
|
@ -19,6 +19,7 @@ commands = nosetests -v tests/unit --with-coverage --cover-package=bootstrapvz -
|
||||||
deps =
|
deps =
|
||||||
nose
|
nose
|
||||||
Pyro4 >= 4.26
|
Pyro4 >= 4.26
|
||||||
|
pyvbox >= 0.2.0
|
||||||
commands = nosetests -v tests/integration --with-coverage --cover-package=bootstrapvz --cover-inclusive
|
commands = nosetests -v tests/integration --with-coverage --cover-package=bootstrapvz --cover-inclusive
|
||||||
|
|
||||||
[testenv:docs]
|
[testenv:docs]
|
||||||
|
|
Loading…
Add table
Reference in a new issue