Skip to content

Commit

Permalink
Merge pull request #45 from esben/container-create
Browse files Browse the repository at this point in the history
Improvements to container_create()
  • Loading branch information
esben authored Aug 13, 2016
2 parents edbbc83 + fd93fdc commit 630485f
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 5 deletions.
4 changes: 3 additions & 1 deletion tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
DOCKER_HOST = os.environ.get('DOCKER_HOST', None)


@pytest.fixture(scope="module")
@pytest.fixture(scope="function")
def docker(request):
os.system("for c in `docker ps -a -q`;do docker rm $c;done")
os.system("for i in `docker images -q`;do docker rmi $i;done")
return DockerClient(host=DOCKER_HOST)


Expand Down
49 changes: 49 additions & 0 deletions tests/integration/container_create_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import pytest
import contextlib
import os
import re

from xd.docker.client import *
from xd.docker.container import *
from xd.docker.parameters import *


def test_pull_needed(docker, stdout):
with stdout.redirect():
container = docker.container_create(
ContainerConfig("busybox:latest"),
"xd-docker-container-create-1")
assert container is not None
assert isinstance(container, Container)
assert re.match('^[0-9a-f]+$', container.id)


def test_pull_but_not_needed(docker, stdout):
docker.image_pull("busybox:latest")
with stdout.redirect():
container = docker.container_create(
ContainerConfig("busybox:latest"),
"xd-docker-container-create-2")
assert container is not None
assert isinstance(container, Container)
assert re.match('^[0-9a-f]+$', container.id)


def test_no_pull_but_needed(docker, stdout):
with pytest.raises(ClientError):
docker.container_create(
ContainerConfig("busybox:latest"),
"xd-docker-container-create-3",
pull=False)


def test_no_pull_and_not_needed(docker, stdout):
docker.image_pull("busybox:latest")
with stdout.redirect():
container = docker.container_create(
ContainerConfig("busybox:latest"),
"xd-docker-container-create-4",
pull=False)
assert container is not None
assert isinstance(container, Container)
assert re.match('^[0-9a-f]+$', container.id)
5 changes: 2 additions & 3 deletions tests/integration/image_build_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def test_image_build_9_error(docker, busybox_error, stdout):
image = docker.image_build('.', cache=False)
assert image is None
assert re.search(
'^The command ./bin/sh -c false. returned a non-zero code: 1$',
'The command ./bin/sh -c false. returned a non-zero code: 1$',
stdout.get(), re.M)


Expand All @@ -97,6 +97,5 @@ def test_image_build_10_error_quiet(docker, busybox_error, stdout):
image = docker.image_build('.', cache=False, output=('error'))
assert image is None
assert re.search(
'^The command ./bin/sh -c false. returned a non-zero code: 1$',
'The command ./bin/sh -c false. returned a non-zero code: 1$',
stdout.get(), re.M)
assert len(stdout.getlines()) == 1
54 changes: 54 additions & 0 deletions tests/unit/client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1046,3 +1046,57 @@ def test_container_create_with_exposed_ports(self, post_mock):
exposed_ports_arg = data_arg['ExposedPorts']
print(exposed_ports_arg)
self.assertEqual(exposed_ports_arg, {'22/tcp': {}, '80/tcp': {}})

@mock.patch('requests.get')
@mock.patch('requests.post')
def test_container_create_pull_needed(self, post_mock, get_mock):
post_mock.return_value = self.simple_success_response
get_mock.side_effect = [
requests_mock.version_response("1.22", "1.10.3"),
requests_mock.Response('404 no such image\n', 404)]
self.client.container_create(
ContainerConfig('busybox:latest'), pull=True)
assert post_mock.call_count == 2
name, args, kwargs = post_mock.mock_calls[1]
assert args[0].endswith('/containers/create')

@mock.patch('requests.get')
@mock.patch('requests.post')
def test_container_create_pull_not_needed(self, post_mock, get_mock):
post_mock.return_value = self.simple_success_response
get_mock.side_effect = [
requests_mock.version_response("1.22", "1.10.3"),
requests_mock.Response(json.dumps(
image_inspect_tests.response), 200)]
self.client.container_create(
ContainerConfig('busybox:latest'), pull=True)
assert post_mock.call_count == 1
name, args, kwargs = post_mock.mock_calls[0]
assert args[0].endswith('/containers/create')

@mock.patch('requests.get')
@mock.patch('requests.post')
def test_container_create_nopull_needed(self, post_mock, get_mock):
post_mock.return_value = self.simple_success_response
get_mock.side_effect = [
requests_mock.version_response("1.22", "1.10.3"),
requests_mock.Response('404 no such image\n', 404)]
self.client.container_create(
ContainerConfig('busybox:latest'), pull=False)
assert post_mock.call_count == 1
name, args, kwargs = post_mock.mock_calls[0]
assert args[0].endswith('/containers/create')

@mock.patch('requests.get')
@mock.patch('requests.post')
def test_container_create_nopull_not_needed(self, post_mock, get_mock):
post_mock.return_value = self.simple_success_response
get_mock.side_effect = [
requests_mock.version_response("1.22", "1.10.3"),
requests_mock.Response(json.dumps(
image_inspect_tests.response), 200)]
self.client.container_create(
ContainerConfig('busybox:latest'), pull=False)
assert post_mock.call_count == 1
name, args, kwargs = post_mock.mock_calls[0]
assert args[0].endswith('/containers/create')
11 changes: 10 additions & 1 deletion xd/docker/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ def container_create(
config: ContainerConfig,
name: Optional[Union[ContainerName, str]]=None,
mounts: Optional[Sequence[VolumeMount]]=None,
host_config: Optional[HostConfig]=None):
host_config: Optional[HostConfig]=None,
pull: bool=True):
"""Create a new container.
Create a new container based on existing image.
Expand All @@ -388,6 +389,7 @@ def container_create(
name: name to assign to container.
mounts: mount points in the container (list of strings).
host_config: HostConfig instance.
pull: Pull image if needed.
"""

# Handle convenience argument types
Expand Down Expand Up @@ -415,6 +417,13 @@ def container_create(
json_params['ExposedPorts'] = {
port: {} for port in json_params['ExposedPorts']}

# Pull image if necessary
if pull:
try:
self.image_inspect_raw(config.image)
except ClientError:
self.image_pull(config.image, output=())

response = self._post('/containers/create', params=query_params,
headers=headers, data=json.dumps(json_params))
response_json = response.json()
Expand Down

0 comments on commit 630485f

Please sign in to comment.