Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions remoteappmanager/docker/container_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ def __init__(self, docker_config, *args, **kwargs):
super().__init__(*args, **kwargs)

@gen.coroutine
def start_container(self, user_name, image_name, mapping_id, volumes):
def start_container(self,
user_name,
image_name,
mapping_id,
volumes,
environment=None):
"""Starts a container using the given image name.

Parameters
Expand All @@ -71,6 +76,9 @@ def start_container(self, user_name, image_name, mapping_id, volumes):
(i.e. configuration).
volumes: dict or None
{volume_source: {'bind': volume_target, 'mode': volume_mode}
environment: dict or None
Contains additional keyvalue pairs that will be exported
as environment variables inside the container.

Return
------
Expand All @@ -80,12 +88,16 @@ def start_container(self, user_name, image_name, mapping_id, volumes):
if image_name in self._start_pending:
return None

if environment is None:
environment = {}

try:
self._start_pending.add(image_name)
result = yield self._start_container(user_name,
image_name,
mapping_id,
volumes)
volumes,
environment)
finally:
self._start_pending.remove(image_name)

Expand Down Expand Up @@ -204,7 +216,12 @@ def image(self, image_id_or_name):
# Private

@gen.coroutine
def _start_container(self, user_name, image_name, mapping_id, volumes):
def _start_container(self,
user_name,
image_name,
mapping_id,
volumes,
environment):
"""Helper method that performs the physical operation of starting
the container.

Expand Down Expand Up @@ -272,7 +289,9 @@ def _start_container(self, user_name, image_name, mapping_id, volumes):
create_kwargs = dict(
image=image_name,
name=container_name,
environment=_get_container_env(user_name, container_url_id),
environment=_get_container_env(user_name,
container_url_id,
environment),
volumes=volume_targets,
labels=_get_container_labels(user_name,
mapping_id,
Expand Down Expand Up @@ -473,7 +492,7 @@ def _docker_client_default(self):
return AsyncDockerClient(**self.docker_config)


def _get_container_env(user_name, url_id):
def _get_container_env(user_name, url_id, environment):
"""Introduces the environment variables that are available
at container startup time.

Expand All @@ -486,12 +505,20 @@ def _get_container_env(user_name, url_id):
A string containing the container identifier that will be used
in the user-exposed URL.

environment: dict
Additional environment keys to add to the final result.
Note that these will not take precedence.

Return
------
a dictionary containing the envvars to export.
"""

return dict(
result = {}
if environment:
result.update(environment)

result.update(dict(
# Username used to login to jupyterhub. Generally an email address.
JPY_USER=user_name,
# The base url. We use this one because the JPY username might
Expand All @@ -501,7 +528,8 @@ def _get_container_env(user_name, url_id):
USER=_unix_user(user_name),
# The identifier that will be used for the URL.
URL_ID=url_id,
)
))
return result


def _get_container_labels(user_name, mapping_id, url_id):
Expand Down
20 changes: 20 additions & 0 deletions remoteappmanager/docker/tests/test_container_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,23 @@ def raiser(*args, **kwargs):

self.assertTrue(self.mock_docker_client.stop.called)
self.assertTrue(self.mock_docker_client.remove_container.called)

@gen_test
def test_start_container_with_environment(self):
mock_client = self.mock_docker_client

environment = {
"FOO": "bar"
}

yield self.manager.start_container(
"username",
"image_name1",
"mapping_id",
None,
environment
)

self.assertEqual(
mock_client.create_container.call_args[1]["environment"]["FOO"],
"bar")