From 52ad76905f95ba584d71575361fbe70b655d7838 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Wed, 9 Aug 2023 10:03:52 +0200 Subject: [PATCH] added support for propagation (with flake conformity) Signed-off-by: Janne Jakob Fleischer --- docker/api/container.py | 8 +++++- docker/utils/utils.py | 9 +++++- tests/integration/api_container_test.py | 38 ++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/docker/api/container.py b/docker/api/container.py index 40607e79..6aaf8846 100644 --- a/docker/api/container.py +++ b/docker/api/container.py @@ -317,6 +317,11 @@ class ContainerApiMixin: '/var/www': { 'bind': '/mnt/vol1', 'mode': 'ro', + }, + '/autofs/user1': { + 'bind': '/mnt/vol3', + 'mode': 'rw', + 'propagation': 'shared' } }) ) @@ -327,10 +332,11 @@ class ContainerApiMixin: .. code-block:: python container_id = client.api.create_container( - 'busybox', 'ls', volumes=['/mnt/vol1', '/mnt/vol2'], + 'busybox', 'ls', volumes=['/mnt/vol1', '/mnt/vol2', '/mnt/vol3'], host_config=client.api.create_host_config(binds=[ '/home/user1/:/mnt/vol2', '/var/www:/mnt/vol1:ro', + '/autofs/user1:/mnt/vol3:rw,shared', ]) ) diff --git a/docker/utils/utils.py b/docker/utils/utils.py index 7b2bbf4b..301ee989 100644 --- a/docker/utils/utils.py +++ b/docker/utils/utils.py @@ -17,7 +17,6 @@ from ..tls import TLSConfig from urllib.parse import urlparse, urlunparse - URLComponents = collections.namedtuple( 'URLComponents', 'scheme netloc url params query fragment', @@ -116,6 +115,7 @@ def convert_port_bindings(port_bindings): def convert_volume_binds(binds): + if isinstance(binds, list): return binds @@ -141,6 +141,13 @@ def convert_volume_binds(binds): mode = v['mode'] else: mode = 'rw' + + #this is only relevant for linux-hosts; doesn't work in Docker Desktop + if 'propagation' in v and v['propagation'] in ('rshared','shared','rslave','slave','rprivate','private'): + if mode: + mode = ','.join([mode, v['propagation']]) + else: + mode = v['propagation'] result.append( f'{k}:{bind}:{mode}' diff --git a/tests/integration/api_container_test.py b/tests/integration/api_container_test.py index 0cb8fec6..d6c4edf6 100644 --- a/tests/integration/api_container_test.py +++ b/tests/integration/api_container_test.py @@ -542,6 +542,24 @@ class VolumeBindTest(BaseAPIIntegrationTest): inspect_data = self.client.inspect_container(container) self.check_container_data(inspect_data, False) + def test_create_with_binds_rw_rshared(self): + self.run_with_volume_propagation( + False, + 'rshared', + TEST_IMG, + ['touch', os.path.join(self.mount_dest, self.filename)], + ) + container = self.run_with_volume_propagation( + True, + 'rshared', + TEST_IMG, + ['ls', self.mount_dest], + ) + logs = self.client.logs(container).decode('utf-8') + assert self.filename in logs + inspect_data = self.client.inspect_container(container) + self.check_container_data(inspect_data, True, 'rshared') + @requires_api_version('1.30') def test_create_with_mounts(self): mount = docker.types.Mount( @@ -597,7 +615,7 @@ class VolumeBindTest(BaseAPIIntegrationTest): assert mount['Source'] == mount_data['Name'] assert mount_data['RW'] is True - def check_container_data(self, inspect_data, rw): + def check_container_data(self, inspect_data, rw, propagation='rprivate'): assert 'Mounts' in inspect_data filtered = list(filter( lambda x: x['Destination'] == self.mount_dest, @@ -607,6 +625,7 @@ class VolumeBindTest(BaseAPIIntegrationTest): mount_data = filtered[0] assert mount_data['Source'] == self.mount_origin assert mount_data['RW'] == rw + assert mount_data['Propagation'] == propagation def run_with_volume(self, ro, *args, **kwargs): return self.run_container( @@ -624,6 +643,23 @@ class VolumeBindTest(BaseAPIIntegrationTest): **kwargs ) + def run_with_volume_propagation(self, ro, propagation, *args, **kwargs): + return self.run_container( + *args, + volumes={self.mount_dest: {}}, + host_config=self.client.create_host_config( + binds={ + self.mount_origin: { + 'bind': self.mount_dest, + 'ro': ro, + 'propagation': propagation + }, + }, + network_mode='none' + ), + **kwargs + ) + class ArchiveTest(BaseAPIIntegrationTest): def test_get_file_archive_from_container(self):