Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #301 from dutsii/docker_integration
Docker integration
- Loading branch information
Showing
17 changed files
with
733 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
docker==3.7.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,14 @@ | |||
# Prerequisites # | |||
To run the docker example one has to have docker-ce installed and | |||
accessible via "unix:///var/run/docker.sock" (the default). The | |||
default docker bridge network also needs to be accessible from the | |||
pytest executor since the test tries to establish an ssh connection to | |||
the container (again the default after a standard installation of | |||
docker-ce). | |||
|
|||
After following steps similar to [Getting started](https://labgrid.readthedocs.io/en/latest/getting_started.html#running-your-first-test) the demo can be run with: | |||
|
|||
pytest -s --lg-env env.yaml test_shell.py | |||
|
|||
Successfully tested against Docker version 18.06.1-ce, build e68fc7a. | |||
But it should work with later versions as well. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,9 @@ | |||
import pytest | |||
|
|||
@pytest.fixture(scope='session') | |||
def command(target): | |||
strategy = target.get_driver('DockerStrategy') | |||
strategy.transition("shell") | |||
shell = target.get_driver('CommandProtocol') | |||
return shell | |||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,14 @@ | |||
targets: | |||
main: | |||
resources: | |||
- DockerDaemon: | |||
docker_daemon_url: "unix:///var/run/docker.sock" | |||
drivers: | |||
- DockerDriver: | |||
image_uri: "rastasheep/ubuntu-sshd:16.04" | |||
container_name: "ubuntu-lg-example" | |||
host_config: {"network_mode":"bridge"} | |||
network_services: [{"port":22,"username":"root","password":"root"}] | |||
- DockerStrategy: {} | |||
- SSHDriver: | |||
keyfile: "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,11 @@ | |||
def test_shell(command): | |||
stdout, stderr, returncode = command.run('cat /proc/version') | |||
assert returncode == 0 | |||
assert len(stdout) > 0 | |||
assert len(stderr) == 0 | |||
assert 'Linux' in stdout[0] | |||
|
|||
stdout, stderr, returncode = command.run('false') | |||
assert returncode != 0 | |||
assert len(stdout) == 0 | |||
assert len(stderr) == 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,110 @@ | |||
""" | |||
Class for connecting to a docker daemon running on the host machine. | |||
""" | |||
|
|||
import attr | |||
import logging | |||
|
|||
from labgrid.factory import target_factory | |||
from labgrid.driver.common import Driver | |||
from labgrid.resource.docker import DockerDaemon, DockerConstants | |||
from labgrid.protocol.powerprotocol import PowerProtocol | |||
|
|||
|
|||
@target_factory.reg_driver | |||
@attr.s(cmp=False) | |||
class DockerDriver(PowerProtocol, Driver): | |||
"""The DockerDriver is used to create docker containers. | |||
This is done via communication with a docker daemon. | |||
When a container is created the container is labeled with an | |||
cleanup strategy identifier. Currently only one strategy is | |||
implemented. This strategy simply deletes all labgrid created | |||
containers before each test run. This is to ensure cleanup of | |||
dangling containers from crashed tests or hanging containers. | |||
Image pruning is not done by the driver. | |||
For detailed information about the arguments see the | |||
"Docker SDK for Python" documentation | |||
https://docker-py.readthedocs.io/en/stable/containers.html#container-objects | |||
Args: | |||
bindings (dict): The labgrid bindings | |||
Args passed to docker.create_container: | |||
image_uri (str): The uri of the image to fetch | |||
command (str): The command to execute once container has been created | |||
volumes (list): The volumes to declare | |||
environment (list): Docker environment variables to set | |||
host_config (dict): Docker host configuration parameters | |||
network_services (list): Sequence of dicts each specifying a network \ | |||
service that the docker container exposes. | |||
""" | |||
bindings = {"docker_daemon": {DockerDaemon}} | |||
image_uri = attr.ib(default=None, validator=attr.validators.optional( | |||
attr.validators.instance_of(str))) | |||
command = attr.ib(default=None, validator=attr.validators.optional( | |||
attr.validators.instance_of(str))) | |||
volumes = attr.ib(default=None, validator=attr.validators.optional( | |||
attr.validators.instance_of(list))) | |||
container_name = attr.ib(default=None, validator=attr.validators.optional( | |||
attr.validators.instance_of(str))) | |||
environment = attr.ib( | |||
default=None, validator=attr.validators.optional( | |||
attr.validators.instance_of(list))) | |||
host_config = attr.ib( | |||
default=None, validator=attr.validators.optional( | |||
attr.validators.instance_of(dict))) | |||
network_services = attr.ib( | |||
default=None, validator=attr.validators.optional( | |||
attr.validators.instance_of(list))) | |||
|
|||
def __attrs_post_init__(self): | |||
self.logger = logging.getLogger("{}({})".format(self, self.target)) | |||
super().__attrs_post_init__() | |||
self._client = None | |||
self._container = None | |||
|
|||
def on_activate(self): | |||
""" On activation: | |||
1. Import docker module (_client and _container remain available) | |||
2. Connect to the docker daemon | |||
3. Pull requested image from docker registry if needed | |||
4. Create the new container according to parameters from conf | |||
""" | |||
import docker | |||
self._client = docker.DockerClient( | |||
base_url=self.docker_daemon.docker_daemon_url) | |||
self._client.images.pull(self.image_uri) | |||
self._container = self._client.api.create_container( | |||
self.image_uri, | |||
command=self.command, | |||
volumes=self.volumes, | |||
name=self.container_name, | |||
environment=self.environment, | |||
labels={ | |||
DockerConstants.DOCKER_LG_CLEANUP_LABEL: | |||
DockerConstants.DOCKER_LG_CLEANUP_TYPE_AUTO}, | |||
host_config=self._client.api.create_host_config( | |||
**self.host_config)) | |||
|
|||
def on_deactivate(self): | |||
""" Remove container after use""" | |||
self._client.api.remove_container(self._container.get('Id'), | |||
force=True) | |||
self._client = None | |||
self._container = None | |||
|
|||
def on(self): | |||
""" Start the container created during activation """ | |||
self._client.api.start(container=self._container.get('Id')) | |||
|
|||
def off(self): | |||
""" Stop the container created during activation """ | |||
self._client.api.stop(container=self._container.get('Id')) | |||
|
|||
def cycle(self): | |||
"""Cycle the docker container by stopping and starting it""" | |||
self.off() | |||
self.on() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.