From d018e37229c57006cdf7dc754459736af7262794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Martins?= Date: Tue, 17 Mar 2015 18:21:12 +0000 Subject: [PATCH 1/3] Implemented labels for docker-py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: André Martins --- docker/client.py | 4 ++-- docker/utils/utils.py | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docker/client.py b/docker/client.py index 79726aafab..ad994f3675 100644 --- a/docker/client.py +++ b/docker/client.py @@ -444,7 +444,7 @@ def create_container(self, image, command=None, hostname=None, user=None, network_disabled=False, name=None, entrypoint=None, cpu_shares=None, working_dir=None, domainname=None, memswap_limit=0, cpuset=None, host_config=None, - mac_address=None): + mac_address=None, labels=None): if isinstance(volumes, six.string_types): volumes = [volumes, ] @@ -458,7 +458,7 @@ def create_container(self, image, command=None, hostname=None, user=None, self._version, image, command, hostname, user, detach, stdin_open, tty, mem_limit, ports, environment, dns, volumes, volumes_from, network_disabled, entrypoint, cpu_shares, working_dir, domainname, - memswap_limit, cpuset, host_config, mac_address + memswap_limit, cpuset, host_config, mac_address, labels ) return self.create_container_from_config(config, name) diff --git a/docker/utils/utils.py b/docker/utils/utils.py index 6abde98416..403296b2b4 100644 --- a/docker/utils/utils.py +++ b/docker/utils/utils.py @@ -443,7 +443,8 @@ def create_container_config( stdin_open=False, tty=False, mem_limit=0, ports=None, environment=None, dns=None, volumes=None, volumes_from=None, network_disabled=False, entrypoint=None, cpu_shares=None, working_dir=None, domainname=None, - memswap_limit=0, cpuset=None, host_config=None, mac_address=None + memswap_limit=0, cpuset=None, host_config=None, mac_address=None, + labels=None ): if isinstance(command, six.string_types): command = shlex.split(str(command)) @@ -453,6 +454,15 @@ def create_container_config( for k, v in six.iteritems(environment) ] + if isinstance(labels, six.string_types): + labels = [labels, ] + + if isinstance(labels, list): + labels_dict = {} + for lbl in labels: + labels_dict[lbl] = {} + labels = labels_dict + if isinstance(mem_limit, six.string_types): mem_limit = parse_bytes(mem_limit) if isinstance(memswap_limit, six.string_types): @@ -532,5 +542,6 @@ def create_container_config( 'WorkingDir': working_dir, 'MemorySwap': memswap_limit, 'HostConfig': host_config, - 'MacAddress': mac_address + 'MacAddress': mac_address, + 'Labels': labels } From 014dba284198e97925223bb95172281d7dd4e3e0 Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Fri, 20 Mar 2015 14:49:03 -0700 Subject: [PATCH 2/3] Update default API version to 1.18 Signed-off-by: Aanand Prasad --- docker/client.py | 2 +- tests/fake_api.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/client.py b/docker/client.py index ad994f3675..f3c4c1f442 100644 --- a/docker/client.py +++ b/docker/client.py @@ -34,7 +34,7 @@ if not six.PY3: import websocket -DEFAULT_DOCKER_API_VERSION = '1.17' +DEFAULT_DOCKER_API_VERSION = '1.18' DEFAULT_TIMEOUT_SECONDS = 60 STREAM_HEADER_SIZE_BYTES = 8 diff --git a/tests/fake_api.py b/tests/fake_api.py index a6a637a792..60106b4335 100644 --- a/tests/fake_api.py +++ b/tests/fake_api.py @@ -14,7 +14,7 @@ import fake_stat -CURRENT_VERSION = 'v1.17' +CURRENT_VERSION = 'v1.18' FAKE_CONTAINER_ID = '3cc2351ab11b' FAKE_IMAGE_ID = 'e9aa60c60128' @@ -33,7 +33,7 @@ def get_fake_raw_version(): status_code = 200 response = { - "ApiVersion": "1.17", + "ApiVersion": "1.18", "GitCommit": "fake-commit", "GoVersion": "go1.3.3", "Version": "1.5.0" From bd72bd13c7a49f69dcacfdf655c15b5be2aaa2ad Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Fri, 20 Mar 2015 14:26:10 -0700 Subject: [PATCH 3/3] Finish labels implementation, add tests and docs Signed-off-by: Aanand Prasad --- docker/utils/utils.py | 11 +++++----- docs/api.md | 1 + tests/test.py | 48 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/docker/utils/utils.py b/docker/utils/utils.py index 403296b2b4..63cd2a79b6 100644 --- a/docker/utils/utils.py +++ b/docker/utils/utils.py @@ -454,14 +454,13 @@ def create_container_config( for k, v in six.iteritems(environment) ] - if isinstance(labels, six.string_types): - labels = [labels, ] + if labels is not None and compare_version('1.18', version) < 0: + raise errors.DockerException( + 'labels were only introduced in API version 1.18' + ) if isinstance(labels, list): - labels_dict = {} - for lbl in labels: - labels_dict[lbl] = {} - labels = labels_dict + labels = dict((lbl, six.text_type('')) for lbl in labels) if isinstance(mem_limit, six.string_types): mem_limit = parse_bytes(mem_limit) diff --git a/docs/api.md b/docs/api.md index fa1987a470..2415cc24a7 100644 --- a/docs/api.md +++ b/docs/api.md @@ -209,6 +209,7 @@ from. Optionally a single string joining container id's with commas * memswap_limit (int): * host_config (dict): A [HostConfig](hostconfig.md) dictionary * mac_address (str): The Mac Address to assign the container +* labels (dict or list): A dictionary of name-value labels (e.g. `{"label1": "value1", "label2": "value2"}`) or a list of names of labels to set with empty values (e.g. `["label1", "label2"]`) **Returns** (dict): A dictionary with an image 'Id' key and a 'Warnings' key. diff --git a/tests/test.py b/tests/test.py index 5750c94d46..a363c35103 100644 --- a/tests/test.py +++ b/tests/test.py @@ -1305,6 +1305,54 @@ def test_create_container_with_devices(self): args[1]['timeout'], docker.client.DEFAULT_TIMEOUT_SECONDS ) + def test_create_container_with_labels_dict(self): + labels_dict = { + six.text_type('foo'): six.text_type('1'), + six.text_type('bar'): six.text_type('2'), + } + try: + self.client.create_container( + 'busybox', 'true', + labels=labels_dict, + ) + except Exception as e: + self.fail('Command should not raise exception: {0}'.format(e)) + args = fake_request.call_args + self.assertEqual(args[0][0], url_prefix + 'containers/create') + self.assertEqual(json.loads(args[1]['data'])['Labels'], labels_dict) + self.assertEqual( + args[1]['headers'], {'Content-Type': 'application/json'} + ) + self.assertEqual( + args[1]['timeout'], docker.client.DEFAULT_TIMEOUT_SECONDS + ) + + def test_create_container_with_labels_list(self): + labels_list = [ + six.text_type('foo'), + six.text_type('bar'), + ] + labels_dict = { + six.text_type('foo'): six.text_type(), + six.text_type('bar'): six.text_type(), + } + try: + self.client.create_container( + 'busybox', 'true', + labels=labels_list, + ) + except Exception as e: + self.fail('Command should not raise exception: {0}'.format(e)) + args = fake_request.call_args + self.assertEqual(args[0][0], url_prefix + 'containers/create') + self.assertEqual(json.loads(args[1]['data'])['Labels'], labels_dict) + self.assertEqual( + args[1]['headers'], {'Content-Type': 'application/json'} + ) + self.assertEqual( + args[1]['timeout'], docker.client.DEFAULT_TIMEOUT_SECONDS + ) + def test_resize_container(self): try: self.client.resize(