summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnca Iordache <aiordache@users.noreply.github.com>2021-10-08 00:01:28 +0200
committerGitHub <noreply@github.com>2021-10-08 00:01:28 +0200
commit7779b84e87bea3bac3a32b3ec1511bc1bfaa44f1 (patch)
tree93381490bc7a04e9e5cf372291d5c464854699f9
parentdf59f538c28fef92743820c2689111119c182cf1 (diff)
parent7ac8b56730c70e3b61ad628e7512082a4468e4f3 (diff)
downloaddocker-py-7779b84e87bea3bac3a32b3ec1511bc1bfaa44f1.tar.gz
Merge pull request #2809 from feliperuhland/add-service-capability
Add service capability
-rw-r--r--Makefile4
-rw-r--r--docker/constants.py2
-rw-r--r--docker/models/services.py6
-rw-r--r--docker/types/services.py19
-rw-r--r--tests/integration/api_service_test.py30
-rw-r--r--tests/integration/models_services_test.py38
6 files changed, 95 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 60d9984..78a0d33 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-TEST_API_VERSION ?= 1.39
-TEST_ENGINE_VERSION ?= 19.03.13
+TEST_API_VERSION ?= 1.41
+TEST_ENGINE_VERSION ?= 20.10.05
.PHONY: all
all: test
diff --git a/docker/constants.py b/docker/constants.py
index 218e491..d5bfc35 100644
--- a/docker/constants.py
+++ b/docker/constants.py
@@ -1,7 +1,7 @@
import sys
from .version import version
-DEFAULT_DOCKER_API_VERSION = '1.39'
+DEFAULT_DOCKER_API_VERSION = '1.41'
MINIMUM_DOCKER_API_VERSION = '1.21'
DEFAULT_TIMEOUT_SECONDS = 60
STREAM_HEADER_SIZE_BYTES = 8
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 a6dd76e..fe7cc26 100644
--- a/docker/types/services.py
+++ b/docker/types/services.py
@@ -110,13 +110,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, str):
@@ -186,6 +191,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 19a6f15..dcf195d 100644
--- a/tests/integration/api_service_test.py
+++ b/tests/integration/api_service_test.py
@@ -1356,3 +1356,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"]