diff options
author | Felipe Ruhland <felipe.ruhland@gmail.com> | 2021-04-07 22:11:52 +0200 |
---|---|---|
committer | Felipe Ruhland <felipe.ruhland@gmail.com> | 2021-04-07 22:11:52 +0200 |
commit | 7ac8b56730c70e3b61ad628e7512082a4468e4f3 (patch) | |
tree | ac73568a887fa723b5e52759bc4c3ccdb47076f9 | |
parent | f53e615e0fd4b7becf9d72c73b8a9e021d473f62 (diff) | |
download | docker-py-7ac8b56730c70e3b61ad628e7512082a4468e4f3.tar.gz |
Add `CapabilityAdd` and `CapabilityDrop` to
ContainerSpec
Docker Engine v1.41 added `CapAdd` and `CapDrop` as part of the
ContainerSpec, and `docker-py` should do the same.
```
GET /services now returns CapAdd and CapDrop as part of the ContainerSpec.
GET /services/{id} now returns CapAdd and CapDrop as part of the ContainerSpec.
POST /services/create now accepts CapAdd and CapDrop as part of the ContainerSpec.
POST /services/{id}/update now accepts CapAdd and CapDrop as part of the ContainerSpec.
GET /tasks now returns CapAdd and CapDrop as part of the ContainerSpec.
GET /tasks/{id} now returns CapAdd and CapDrop as part of the ContainerSpec.
```
I added capabilities on docstrings, `service.create` init method and
create tests for that.
That change was mention in issue #2802.
Signed-off-by: Felipe Ruhland <felipe.ruhland@gmail.com>
-rw-r--r-- | docker/models/services.py | 6 | ||||
-rw-r--r-- | docker/types/services.py | 19 | ||||
-rw-r--r-- | tests/integration/api_service_test.py | 30 | ||||
-rw-r--r-- | tests/integration/models_services_test.py | 38 |
4 files changed, 92 insertions, 1 deletions
diff --git a/docker/models/services.py b/docker/models/services.py index a29ff13..200dd33 100644 --- a/docker/models/services.py +++ b/docker/models/services.py @@ -213,6 +213,10 @@ class ServiceCollection(Collection): to the service. privileges (Privileges): Security options for the service's containers. + cap_add (:py:class:`list`): A list of kernel capabilities to add to + the default set for the container. + cap_drop (:py:class:`list`): A list of kernel capabilities to drop + from the default set for the container. Returns: :py:class:`Service`: The created service. @@ -277,6 +281,8 @@ class ServiceCollection(Collection): # kwargs to copy straight over to ContainerSpec CONTAINER_SPEC_KWARGS = [ 'args', + 'cap_add', + 'cap_drop', 'command', 'configs', 'dns_config', diff --git a/docker/types/services.py b/docker/types/services.py index 29498e9..8e87c7b 100644 --- a/docker/types/services.py +++ b/docker/types/services.py @@ -112,13 +112,18 @@ class ContainerSpec(dict): containers. Only used for Windows containers. init (boolean): Run an init inside the container that forwards signals and reaps processes. + cap_add (:py:class:`list`): A list of kernel capabilities to add to the + default set for the container. + cap_drop (:py:class:`list`): A list of kernel capabilities to drop from + the default set for the container. """ def __init__(self, image, command=None, args=None, hostname=None, env=None, workdir=None, user=None, labels=None, mounts=None, stop_grace_period=None, secrets=None, tty=None, groups=None, open_stdin=None, read_only=None, stop_signal=None, healthcheck=None, hosts=None, dns_config=None, configs=None, - privileges=None, isolation=None, init=None): + privileges=None, isolation=None, init=None, cap_add=None, + cap_drop=None): self['Image'] = image if isinstance(command, six.string_types): @@ -188,6 +193,18 @@ class ContainerSpec(dict): if init is not None: self['Init'] = init + if cap_add is not None: + if not isinstance(cap_add, list): + raise TypeError('cap_add must be a list') + + self['CapabilityAdd'] = cap_add + + if cap_drop is not None: + if not isinstance(cap_drop, list): + raise TypeError('cap_drop must be a list') + + self['CapabilityDrop'] = cap_drop + class Mount(dict): """ diff --git a/tests/integration/api_service_test.py b/tests/integration/api_service_test.py index 1bee46e..57077e6 100644 --- a/tests/integration/api_service_test.py +++ b/tests/integration/api_service_test.py @@ -1358,3 +1358,33 @@ class ServiceTest(BaseAPIIntegrationTest): self.client.update_service(*args, **kwargs) else: raise + + @requires_api_version('1.41') + def test_create_service_cap_add(self): + name = self.get_service_name() + container_spec = docker.types.ContainerSpec( + TEST_IMG, ['echo', 'hello'], cap_add=['CAP_SYSLOG'] + ) + task_tmpl = docker.types.TaskTemplate(container_spec) + svc_id = self.client.create_service(task_tmpl, name=name) + assert self.client.inspect_service(svc_id) + services = self.client.services(filters={'name': name}) + assert len(services) == 1 + assert services[0]['ID'] == svc_id['ID'] + spec = services[0]['Spec']['TaskTemplate']['ContainerSpec'] + assert 'CAP_SYSLOG' in spec['CapabilityAdd'] + + @requires_api_version('1.41') + def test_create_service_cap_drop(self): + name = self.get_service_name() + container_spec = docker.types.ContainerSpec( + TEST_IMG, ['echo', 'hello'], cap_drop=['CAP_SYSLOG'] + ) + task_tmpl = docker.types.TaskTemplate(container_spec) + svc_id = self.client.create_service(task_tmpl, name=name) + assert self.client.inspect_service(svc_id) + services = self.client.services(filters={'name': name}) + assert len(services) == 1 + assert services[0]['ID'] == svc_id['ID'] + spec = services[0]['Spec']['TaskTemplate']['ContainerSpec'] + assert 'CAP_SYSLOG' in spec['CapabilityDrop'] diff --git a/tests/integration/models_services_test.py b/tests/integration/models_services_test.py index 36caa85..982842b 100644 --- a/tests/integration/models_services_test.py +++ b/tests/integration/models_services_test.py @@ -333,3 +333,41 @@ class ServiceTest(unittest.TestCase): assert service.force_update() service.reload() assert service.version > initial_version + + @helpers.requires_api_version('1.41') + def test_create_cap_add(self): + client = docker.from_env(version=TEST_API_VERSION) + name = helpers.random_name() + service = client.services.create( + name=name, + labels={'foo': 'bar'}, + image="alpine", + command="sleep 300", + container_labels={'container': 'label'}, + cap_add=["CAP_SYSLOG"] + ) + assert service.name == name + assert service.attrs['Spec']['Labels']['foo'] == 'bar' + container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec'] + assert "alpine" in container_spec['Image'] + assert container_spec['Labels'] == {'container': 'label'} + assert "CAP_SYSLOG" in container_spec["CapabilityAdd"] + + @helpers.requires_api_version('1.41') + def test_create_cap_drop(self): + client = docker.from_env(version=TEST_API_VERSION) + name = helpers.random_name() + service = client.services.create( + name=name, + labels={'foo': 'bar'}, + image="alpine", + command="sleep 300", + container_labels={'container': 'label'}, + cap_drop=["CAP_SYSLOG"] + ) + assert service.name == name + assert service.attrs['Spec']['Labels']['foo'] == 'bar' + container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec'] + assert "alpine" in container_spec['Image'] + assert container_spec['Labels'] == {'container': 'label'} + assert "CAP_SYSLOG" in container_spec["CapabilityDrop"] |