Skip to content

Commit 5edcbe4

Browse files
committed
feat(docker/api/container): add support for subpath in volume_opts
Adds support for specifying a subpath when creating a container This allows users to specify a subdirectory within the volume to use as the container's root. Changes: * Added `subpath` parameter to `create_container` method in `docker/api/container.py` * Updated `Mount` class in `docker/types/mounts.py` to include `subpath` attribute * Modified `Container` model in `docker/models/containers.py` to include `subpath` attribute BREAKING CHANGE: None TESTED: Yes, added unit tests to verify subpath functionality Signed-off-by: Khushiyant <[email protected]>
1 parent a365202 commit 5edcbe4

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

docker/api/volume.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def volumes(self, filters=None):
3535
url = self._url('/volumes')
3636
return self._result(self._get(url, params=params), True)
3737

38-
def create_volume(self, name=None, driver=None, driver_opts=None,
38+
def create_volume(self, name=None, driver=None, driver_opts=None, subpath=None,
3939
labels=None):
4040
"""
4141
Create and register a named volume
@@ -45,6 +45,9 @@ def create_volume(self, name=None, driver=None, driver_opts=None,
4545
driver (str): Name of the driver used to create the volume
4646
driver_opts (dict): Driver options as a key-value dictionary
4747
labels (dict): Labels to set on the volume
48+
subpath (str): Subpath within the volume to use as the volume's
49+
root.
50+
4851
4952
Returns:
5053
(dict): The created volume reference object
@@ -77,6 +80,7 @@ def create_volume(self, name=None, driver=None, driver_opts=None,
7780
'Name': name,
7881
'Driver': driver,
7982
'DriverOpts': driver_opts,
83+
'Subpath': subpath
8084
}
8185

8286
if labels is not None:

docker/types/services.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,16 @@ class Mount(dict):
242242
for the ``volume`` type.
243243
driver_config (DriverConfig): Volume driver configuration. Only valid
244244
for the ``volume`` type.
245+
subpath (string): The path within the volume where the container's
246+
volume should be mounted.
245247
tmpfs_size (int or string): The size for the tmpfs mount in bytes.
246248
tmpfs_mode (int): The permission mode for the tmpfs mount.
247249
"""
248250

249251
def __init__(self, target, source, type='volume', read_only=False,
250252
consistency=None, propagation=None, no_copy=False,
251253
labels=None, driver_config=None, tmpfs_size=None,
252-
tmpfs_mode=None):
254+
tmpfs_mode=None, subpath=None):
253255
self['Target'] = target
254256
self['Source'] = source
255257
if type not in ('bind', 'volume', 'tmpfs', 'npipe'):
@@ -267,7 +269,7 @@ def __init__(self, target, source, type='volume', read_only=False,
267269
self['BindOptions'] = {
268270
'Propagation': propagation
269271
}
270-
if any([labels, driver_config, no_copy, tmpfs_size, tmpfs_mode]):
272+
if any([labels, driver_config, no_copy, tmpfs_size, tmpfs_mode, subpath]):
271273
raise errors.InvalidArgument(
272274
'Incompatible options have been provided for the bind '
273275
'type mount.'
@@ -280,6 +282,8 @@ def __init__(self, target, source, type='volume', read_only=False,
280282
volume_opts['Labels'] = labels
281283
if driver_config:
282284
volume_opts['DriverConfig'] = driver_config
285+
if subpath:
286+
volume_opts['SubPath'] = subpath
283287
if volume_opts:
284288
self['VolumeOptions'] = volume_opts
285289
if any([propagation, tmpfs_size, tmpfs_mode]):
@@ -299,7 +303,7 @@ def __init__(self, target, source, type='volume', read_only=False,
299303
tmpfs_opts['SizeBytes'] = parse_bytes(tmpfs_size)
300304
if tmpfs_opts:
301305
self['TmpfsOptions'] = tmpfs_opts
302-
if any([propagation, labels, driver_config, no_copy]):
306+
if any([propagation, labels, driver_config, no_copy, subpath]):
303307
raise errors.InvalidArgument(
304308
'Incompatible options have been provided for the tmpfs '
305309
'type mount.'

tests/integration/api_container_test.py

+23
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,29 @@ def test_create_with_volume_mount(self):
620620
assert mount['Source'] == mount_data['Name']
621621
assert mount_data['RW'] is True
622622

623+
@requires_api_version('1.45')
624+
def test_create_with_subpath_volume_mount(self):
625+
mount = docker.types.Mount(
626+
type="volume", source=helpers.random_name(),
627+
target=self.mount_dest, read_only=True,
628+
subpath='subdir'
629+
)
630+
host_config = self.client.create_host_config(mounts=[mount])
631+
container = self.client.create_container(
632+
TEST_IMG, ['true'], host_config=host_config,
633+
)
634+
assert container
635+
inspect_data = self.client.inspect_container(container)
636+
assert 'Mounts' in inspect_data
637+
filtered = list(filter(
638+
lambda x: x['Destination'] == self.mount_dest,
639+
inspect_data['Mounts']
640+
))
641+
assert len(filtered) == 1
642+
mount_data = filtered[0]
643+
assert mount['Source'] == mount_data['Name']
644+
assert mount_data['RW'] is False
645+
623646
def check_container_data(self, inspect_data, rw, propagation='rprivate'):
624647
assert 'Mounts' in inspect_data
625648
filtered = list(filter(

0 commit comments

Comments
 (0)