Skip to content

Commit 7779b84

Browse files
authored
Merge pull request #2809 from feliperuhland/add-service-capability
Add service capability
2 parents df59f53 + 7ac8b56 commit 7779b84

File tree

6 files changed

+95
-4
lines changed

6 files changed

+95
-4
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
TEST_API_VERSION ?= 1.39
2-
TEST_ENGINE_VERSION ?= 19.03.13
1+
TEST_API_VERSION ?= 1.41
2+
TEST_ENGINE_VERSION ?= 20.10.05
33

44
.PHONY: all
55
all: test

docker/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import sys
22
from .version import version
33

4-
DEFAULT_DOCKER_API_VERSION = '1.39'
4+
DEFAULT_DOCKER_API_VERSION = '1.41'
55
MINIMUM_DOCKER_API_VERSION = '1.21'
66
DEFAULT_TIMEOUT_SECONDS = 60
77
STREAM_HEADER_SIZE_BYTES = 8

docker/models/services.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ def create(self, image, command=None, **kwargs):
213213
to the service.
214214
privileges (Privileges): Security options for the service's
215215
containers.
216+
cap_add (:py:class:`list`): A list of kernel capabilities to add to
217+
the default set for the container.
218+
cap_drop (:py:class:`list`): A list of kernel capabilities to drop
219+
from the default set for the container.
216220
217221
Returns:
218222
:py:class:`Service`: The created service.
@@ -277,6 +281,8 @@ def list(self, **kwargs):
277281
# kwargs to copy straight over to ContainerSpec
278282
CONTAINER_SPEC_KWARGS = [
279283
'args',
284+
'cap_add',
285+
'cap_drop',
280286
'command',
281287
'configs',
282288
'dns_config',

docker/types/services.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,18 @@ class ContainerSpec(dict):
110110
containers. Only used for Windows containers.
111111
init (boolean): Run an init inside the container that forwards signals
112112
and reaps processes.
113+
cap_add (:py:class:`list`): A list of kernel capabilities to add to the
114+
default set for the container.
115+
cap_drop (:py:class:`list`): A list of kernel capabilities to drop from
116+
the default set for the container.
113117
"""
114118
def __init__(self, image, command=None, args=None, hostname=None, env=None,
115119
workdir=None, user=None, labels=None, mounts=None,
116120
stop_grace_period=None, secrets=None, tty=None, groups=None,
117121
open_stdin=None, read_only=None, stop_signal=None,
118122
healthcheck=None, hosts=None, dns_config=None, configs=None,
119-
privileges=None, isolation=None, init=None):
123+
privileges=None, isolation=None, init=None, cap_add=None,
124+
cap_drop=None):
120125
self['Image'] = image
121126

122127
if isinstance(command, str):
@@ -186,6 +191,18 @@ def __init__(self, image, command=None, args=None, hostname=None, env=None,
186191
if init is not None:
187192
self['Init'] = init
188193

194+
if cap_add is not None:
195+
if not isinstance(cap_add, list):
196+
raise TypeError('cap_add must be a list')
197+
198+
self['CapabilityAdd'] = cap_add
199+
200+
if cap_drop is not None:
201+
if not isinstance(cap_drop, list):
202+
raise TypeError('cap_drop must be a list')
203+
204+
self['CapabilityDrop'] = cap_drop
205+
189206

190207
class Mount(dict):
191208
"""

tests/integration/api_service_test.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,3 +1356,33 @@ def _update_service(self, svc_id, *args, **kwargs):
13561356
self.client.update_service(*args, **kwargs)
13571357
else:
13581358
raise
1359+
1360+
@requires_api_version('1.41')
1361+
def test_create_service_cap_add(self):
1362+
name = self.get_service_name()
1363+
container_spec = docker.types.ContainerSpec(
1364+
TEST_IMG, ['echo', 'hello'], cap_add=['CAP_SYSLOG']
1365+
)
1366+
task_tmpl = docker.types.TaskTemplate(container_spec)
1367+
svc_id = self.client.create_service(task_tmpl, name=name)
1368+
assert self.client.inspect_service(svc_id)
1369+
services = self.client.services(filters={'name': name})
1370+
assert len(services) == 1
1371+
assert services[0]['ID'] == svc_id['ID']
1372+
spec = services[0]['Spec']['TaskTemplate']['ContainerSpec']
1373+
assert 'CAP_SYSLOG' in spec['CapabilityAdd']
1374+
1375+
@requires_api_version('1.41')
1376+
def test_create_service_cap_drop(self):
1377+
name = self.get_service_name()
1378+
container_spec = docker.types.ContainerSpec(
1379+
TEST_IMG, ['echo', 'hello'], cap_drop=['CAP_SYSLOG']
1380+
)
1381+
task_tmpl = docker.types.TaskTemplate(container_spec)
1382+
svc_id = self.client.create_service(task_tmpl, name=name)
1383+
assert self.client.inspect_service(svc_id)
1384+
services = self.client.services(filters={'name': name})
1385+
assert len(services) == 1
1386+
assert services[0]['ID'] == svc_id['ID']
1387+
spec = services[0]['Spec']['TaskTemplate']['ContainerSpec']
1388+
assert 'CAP_SYSLOG' in spec['CapabilityDrop']

tests/integration/models_services_test.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,41 @@ def test_force_update_service_using_shorthand_method(self):
333333
assert service.force_update()
334334
service.reload()
335335
assert service.version > initial_version
336+
337+
@helpers.requires_api_version('1.41')
338+
def test_create_cap_add(self):
339+
client = docker.from_env(version=TEST_API_VERSION)
340+
name = helpers.random_name()
341+
service = client.services.create(
342+
name=name,
343+
labels={'foo': 'bar'},
344+
image="alpine",
345+
command="sleep 300",
346+
container_labels={'container': 'label'},
347+
cap_add=["CAP_SYSLOG"]
348+
)
349+
assert service.name == name
350+
assert service.attrs['Spec']['Labels']['foo'] == 'bar'
351+
container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec']
352+
assert "alpine" in container_spec['Image']
353+
assert container_spec['Labels'] == {'container': 'label'}
354+
assert "CAP_SYSLOG" in container_spec["CapabilityAdd"]
355+
356+
@helpers.requires_api_version('1.41')
357+
def test_create_cap_drop(self):
358+
client = docker.from_env(version=TEST_API_VERSION)
359+
name = helpers.random_name()
360+
service = client.services.create(
361+
name=name,
362+
labels={'foo': 'bar'},
363+
image="alpine",
364+
command="sleep 300",
365+
container_labels={'container': 'label'},
366+
cap_drop=["CAP_SYSLOG"]
367+
)
368+
assert service.name == name
369+
assert service.attrs['Spec']['Labels']['foo'] == 'bar'
370+
container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec']
371+
assert "alpine" in container_spec['Image']
372+
assert container_spec['Labels'] == {'container': 'label'}
373+
assert "CAP_SYSLOG" in container_spec["CapabilityDrop"]

0 commit comments

Comments
 (0)