mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-22 18:00:35 +00:00
Implement docker integration test provider and docker tests
Also make build_server.remote_command() public. It's quite useful.
This commit is contained in:
parent
7502b2a756
commit
072969065c
8 changed files with 162 additions and 4 deletions
|
@ -4,7 +4,7 @@ Changelog
|
|||
2015-12-13
|
||||
----------
|
||||
Anders Ingemann:
|
||||
* Docker provider implemented
|
||||
* Docker provider implemented (including integration testing harness & tests)
|
||||
* minimize_size: Added various size reduction options for dpkg and apt
|
||||
* Removed image section in manifest.
|
||||
Provider specific options have been moved to the provider section.
|
||||
|
|
|
@ -185,6 +185,10 @@ This is useful only when running integration tests.
|
|||
ec2-credentials:
|
||||
access-key: AFAKEACCESSKEYFORAWS
|
||||
secret-key: thes3cr3tkeyf0ryourawsaccount/FS4d8Qdva
|
||||
docker:
|
||||
machine: default
|
||||
|
||||
* ``ec2-credentials`` contains the access key and secret key used to boot
|
||||
an EC2 AMI.
|
||||
* ``docker.machine`` The docker machine on which an image built for docker
|
||||
should run.
|
||||
|
|
|
@ -26,6 +26,7 @@ definitions:
|
|||
- virtualbox
|
||||
- ec2-ebs
|
||||
- ec2-s3
|
||||
- docker
|
||||
|
||||
build_settings:
|
||||
type: object
|
||||
|
@ -60,6 +61,11 @@ definitions:
|
|||
access-key: {type: string}
|
||||
secret-key: {type: string}
|
||||
additional_properties: false
|
||||
docker:
|
||||
type: object
|
||||
properties:
|
||||
machine: {type: string}
|
||||
additional_properties: false
|
||||
|
||||
ssh:
|
||||
type: object
|
||||
|
|
|
@ -80,16 +80,16 @@ class RemoteBuildServer(BuildServer):
|
|||
'build server `{name}\' to `{dst}\''
|
||||
.format(src=src, dst=dst, name=self.name))
|
||||
# Make sure we can read the file as {user}
|
||||
self._remote_command(['sudo', 'chown', self.username, src])
|
||||
self.remote_command(['sudo', 'chown', self.username, src])
|
||||
src_arg = '{user}@{host}:{path}'.format(user=self.username, host=self.address, path=src)
|
||||
log_check_call(['scp', '-i', self.keyfile, '-P', str(self.port),
|
||||
src_arg, dst])
|
||||
|
||||
def delete(self, path):
|
||||
log.debug('Deleting file `{path}\' on build server `{name}\''.format(path=path, name=self.name))
|
||||
self._remote_command(['sudo', 'rm', path])
|
||||
self.remote_command(['sudo', 'rm', path])
|
||||
|
||||
def _remote_command(self, command):
|
||||
def remote_command(self, command):
|
||||
ssh_cmd = ['ssh', '-i', self.keyfile,
|
||||
'-p', str(self.port),
|
||||
self.username + '@' + self.address,
|
||||
|
|
29
tests/integration/docker_tests.py
Normal file
29
tests/integration/docker_tests.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
from manifests import merge_manifest_data
|
||||
from tools import boot_manifest
|
||||
|
||||
partials = {'docker': '''
|
||||
provider:
|
||||
name: docker
|
||||
virtualization: hvm
|
||||
dockerfile: CMD /bin/bash
|
||||
bootstrapper:
|
||||
variant: minbase
|
||||
system:
|
||||
bootloader: none
|
||||
volume:
|
||||
backing: folder
|
||||
partitions:
|
||||
type: none
|
||||
root:
|
||||
filesystem: ext4
|
||||
size: 1GiB
|
||||
''',
|
||||
}
|
||||
|
||||
|
||||
def test_stable():
|
||||
std_partials = ['base', 'stable64']
|
||||
custom_partials = [partials['docker']]
|
||||
manifest_data = merge_manifest_data(std_partials, custom_partials)
|
||||
with boot_manifest(manifest_data) as instance:
|
||||
print('\n'.join(instance.run(['echo', 'test'])))
|
7
tests/integration/providers/docker/README.rst
Normal file
7
tests/integration/providers/docker/README.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
Docker
|
||||
------
|
||||
|
||||
|
||||
Dependencies
|
||||
~~~~~~~~~~~~
|
||||
The host machine running the integration tests must have docker installed.
|
57
tests/integration/providers/docker/__init__.py
Normal file
57
tests/integration/providers/docker/__init__.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
from contextlib import contextmanager
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def boot_image(manifest, build_server, bootstrap_info):
|
||||
image_id = None
|
||||
try:
|
||||
import os
|
||||
from bootstrapvz.common.tools import log_check_call
|
||||
docker_machine = build_server.run_settings.get('docker', {}).get('machine', None)
|
||||
docker_env = os.environ.copy()
|
||||
if docker_machine is not None:
|
||||
cmd = ('eval "$(docker-machine env {machine})" && '
|
||||
'echo $DOCKER_HOST && echo $DOCKER_CERT_PATH && echo $DOCKER_TLS_VERIFY'
|
||||
.format(machine=docker_machine))
|
||||
[docker_host, docker_cert_path, docker_tls] = log_check_call([cmd], shell=True)
|
||||
docker_env['DOCKER_TLS_VERIFY'] = docker_tls
|
||||
docker_env['DOCKER_HOST'] = docker_host
|
||||
docker_env['DOCKER_CERT_PATH'] = docker_cert_path
|
||||
docker_env['DOCKER_MACHINE_NAME'] = docker_machine
|
||||
from bootstrapvz.remote.build_servers.local import LocalBuildServer
|
||||
image_id = bootstrap_info._docker['image_id']
|
||||
if not isinstance(build_server, LocalBuildServer):
|
||||
import tempfile
|
||||
handle, image_path = tempfile.mkstemp()
|
||||
os.close(handle)
|
||||
remote_image_path = os.path.join('/tmp', image_id)
|
||||
try:
|
||||
log.debug('Saving remote image to file')
|
||||
build_server.remote_command([
|
||||
'sudo', 'docker', 'save',
|
||||
'--output=' + remote_image_path,
|
||||
image_id,
|
||||
])
|
||||
log.debug('Downloading remote image')
|
||||
build_server.download(remote_image_path, image_path)
|
||||
log.debug('Importing image')
|
||||
log_check_call(['docker', 'load', '--input=' + image_path], env=docker_env)
|
||||
except (Exception, KeyboardInterrupt):
|
||||
raise
|
||||
finally:
|
||||
log.debug('Deleting exported image from build server and locally')
|
||||
build_server.delete(remote_image_path)
|
||||
os.remove(image_path)
|
||||
log.debug('Deleting image from build server')
|
||||
build_server.remote_command(['sudo', 'docker', 'rmi',
|
||||
bootstrap_info._docker['image_id']])
|
||||
|
||||
from image import Image
|
||||
with Image(image_id, docker_env) as container:
|
||||
yield container
|
||||
finally:
|
||||
if image_id is not None:
|
||||
log.debug('Deleting image')
|
||||
log_check_call(['docker', 'rmi', image_id], env=docker_env)
|
55
tests/integration/providers/docker/image.py
Normal file
55
tests/integration/providers/docker/image.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
from bootstrapvz.common.tools import log_check_call
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Image(object):
|
||||
|
||||
def __init__(self, image_id, docker_env):
|
||||
self.image_id = image_id
|
||||
self.docker_env = docker_env
|
||||
|
||||
def __enter__(self):
|
||||
self.container = Container(self.image_id, self.docker_env)
|
||||
self.container.create()
|
||||
try:
|
||||
self.container.start()
|
||||
except:
|
||||
self.container.destroy()
|
||||
raise
|
||||
return self.container
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
try:
|
||||
self.container.stop()
|
||||
self.container.destroy()
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
||||
|
||||
class Container(object):
|
||||
|
||||
def __init__(self, image_id, docker_env):
|
||||
self.image_id = image_id
|
||||
self.docker_env = docker_env
|
||||
|
||||
def create(self):
|
||||
log.debug('Creating container')
|
||||
[self.container_id] = log_check_call(['docker', 'create', '--tty=true', self.image_id], env=self.docker_env)
|
||||
|
||||
def start(self):
|
||||
log.debug('Starting container')
|
||||
log_check_call(['docker', 'start', self.container_id], env=self.docker_env)
|
||||
|
||||
def run(self, command):
|
||||
log.debug('Running command in container')
|
||||
return log_check_call(['docker', 'exec', self.container_id] + command, env=self.docker_env)
|
||||
|
||||
def stop(self):
|
||||
log.debug('Stopping container')
|
||||
log_check_call(['docker', 'stop', self.container_id], env=self.docker_env)
|
||||
|
||||
def destroy(self):
|
||||
log.debug('Deleting container')
|
||||
log_check_call(['docker', 'rm', self.container_id], env=self.docker_env)
|
||||
del self.container_id
|
Loading…
Add table
Reference in a new issue