diff --git a/.dockerignore b/.dockerignore index 050b8bce..198b23ec 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,5 +13,4 @@ html/* __pycache__ # Compiled Documentation -site/ -Makefile +docs/_build diff --git a/Dockerfile-docs b/Dockerfile-docs index 6f419400..105083e8 100644 --- a/Dockerfile-docs +++ b/Dockerfile-docs @@ -1,12 +1,13 @@ FROM python:3.5 -RUN mkdir /src +ARG uid=1000 +ARG gid=1000 + +RUN addgroup --gid $gid sphinx \ + && useradd --uid $uid --gid $gid -M sphinx + WORKDIR /src +COPY requirements.txt docs-requirements.txt ./ +RUN pip install -r requirements.txt -r docs-requirements.txt -COPY requirements.txt /src/requirements.txt -RUN pip install -r requirements.txt - -COPY docs-requirements.txt /src/docs-requirements.txt -RUN pip install -r docs-requirements.txt - -COPY . /src +USER sphinx diff --git a/Makefile b/Makefile index e4c64e71..cd117467 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ build-py3: .PHONY: build-docs build-docs: - docker build -t docker-sdk-python-docs -f Dockerfile-docs . + docker build -t docker-sdk-python-docs -f Dockerfile-docs --build-arg uid=$(shell id -u) --build-arg gid=$(shell id -g) . .PHONY: build-dind-certs build-dind-certs: @@ -77,7 +77,7 @@ flake8: build .PHONY: docs docs: build-docs - docker run --rm -it -v `pwd`:/code docker-sdk-python-docs sphinx-build docs ./_build + docker run --rm -it -v `pwd`:/src docker-sdk-python-docs sphinx-build docs docs/_build .PHONY: shell shell: build diff --git a/docker/models/containers.py b/docker/models/containers.py index fb10ba90..93f63725 100644 --- a/docker/models/containers.py +++ b/docker/models/containers.py @@ -18,6 +18,24 @@ class Container(Model): if self.attrs.get('Name') is not None: return self.attrs['Name'].lstrip('/') + @property + def image(self): + """ + The image of the container. + """ + image_id = self.attrs['Image'] + if image_id is None: + return None + return self.client.images.get(image_id.split(':')[1]) + + @property + def labels(self): + """ + The labels of a container as dictionary. + """ + result = self.attrs['Config'].get('Labels') + return result or {} + @property def status(self): """ diff --git a/docker/models/images.py b/docker/models/images.py index 51ee6f4a..3fd3dc19 100644 --- a/docker/models/images.py +++ b/docker/models/images.py @@ -15,6 +15,14 @@ class Image(Model): def __repr__(self): return "<%s: '%s'>" % (self.__class__.__name__, "', '".join(self.tags)) + @property + def labels(self): + """ + The labels of an image as dictionary. + """ + result = self.attrs['Config'].get('Labels') + return result or {} + @property def short_id(self): """ diff --git a/docs/containers.rst b/docs/containers.rst index 20529b0e..6c895c6b 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -21,11 +21,13 @@ Container objects .. autoclass:: Container() - .. autoattribute:: id - .. autoattribute:: short_id - .. autoattribute:: name - .. autoattribute:: status .. py:attribute:: attrs + .. autoattribute:: id + .. autoattribute:: image + .. autoattribute:: labels + .. autoattribute:: name + .. autoattribute:: short_id + .. autoattribute:: status The raw representation of this object from the server. diff --git a/docs/images.rst b/docs/images.rst index 25fcffc8..3ba06010 100644 --- a/docs/images.rst +++ b/docs/images.rst @@ -26,10 +26,11 @@ Image objects .. autoclass:: Image() - .. autoattribute:: id - .. autoattribute:: short_id - .. autoattribute:: tags - .. py:attribute:: attrs +.. py:attribute:: attrs +.. autoattribute:: id +.. autoattribute:: labels +.. autoattribute:: short_id +.. autoattribute:: tags The raw representation of this object from the server. diff --git a/tests/unit/fake_api.py b/tests/unit/fake_api.py index 2d0a0b45..ff0f1b65 100644 --- a/tests/unit/fake_api.py +++ b/tests/unit/fake_api.py @@ -134,7 +134,7 @@ def get_fake_inspect_container(tty=False): status_code = 200 response = { 'Id': FAKE_CONTAINER_ID, - 'Config': {'Privileged': True, 'Tty': tty}, + 'Config': {'Labels': {'foo': 'bar'}, 'Privileged': True, 'Tty': tty}, 'ID': FAKE_CONTAINER_ID, 'Image': 'busybox:latest', 'Name': 'foobar', @@ -158,6 +158,7 @@ def get_fake_inspect_image(): 'Parent': "27cf784147099545", 'Created': "2013-03-23T22:24:18.818426-07:00", 'Container': FAKE_CONTAINER_ID, + 'Config': {'Labels': {'bar': 'foo'}}, 'ContainerConfig': { "Hostname": "", diff --git a/tests/unit/models_containers_test.py b/tests/unit/models_containers_test.py index ae1bd12a..c5946061 100644 --- a/tests/unit/models_containers_test.py +++ b/tests/unit/models_containers_test.py @@ -384,12 +384,22 @@ class ContainerTest(unittest.TestCase): container.get_archive('foo') client.api.get_archive.assert_called_with(FAKE_CONTAINER_ID, 'foo') + def test_image(self): + client = make_fake_client() + container = client.containers.get(FAKE_CONTAINER_ID) + assert container.image.id == FAKE_IMAGE_ID + def test_kill(self): client = make_fake_client() container = client.containers.get(FAKE_CONTAINER_ID) container.kill(signal=5) client.api.kill.assert_called_with(FAKE_CONTAINER_ID, signal=5) + def test_labels(self): + client = make_fake_client() + container = client.containers.get(FAKE_CONTAINER_ID) + assert container.labels == {'foo': 'bar'} + def test_logs(self): client = make_fake_client() container = client.containers.get(FAKE_CONTAINER_ID) diff --git a/tests/unit/models_images_test.py b/tests/unit/models_images_test.py index efb21166..784717be 100644 --- a/tests/unit/models_images_test.py +++ b/tests/unit/models_images_test.py @@ -21,6 +21,11 @@ class ImageCollectionTest(unittest.TestCase): assert isinstance(image, Image) assert image.id == FAKE_IMAGE_ID + def test_labels(self): + client = make_fake_client() + image = client.images.get(FAKE_IMAGE_ID) + assert image.labels == {'bar': 'foo'} + def test_list(self): client = make_fake_client() images = client.images.list(all=True)