mirror of https://github.com/docker/compose.git
Use mounts for secrets instead of volumes
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
58dcfac853
commit
415fa6c59b
|
@ -133,6 +133,48 @@ def normalize_path_for_engine(path):
|
|||
return path.replace('\\', '/')
|
||||
|
||||
|
||||
class MountSpec(object):
|
||||
options_map = {
|
||||
'volume': {
|
||||
'nocopy': 'no_copy'
|
||||
},
|
||||
'bind': {
|
||||
'propagation': 'propagation'
|
||||
}
|
||||
}
|
||||
_fields = ['type', 'source', 'target', 'read_only', 'consistency']
|
||||
|
||||
def __init__(self, type, source=None, target=None, read_only=None, consistency=None, **kwargs):
|
||||
self.type = type
|
||||
self.source = source
|
||||
self.target = target
|
||||
self.read_only = read_only
|
||||
self.consistency = consistency
|
||||
self.options = None
|
||||
if self.type in kwargs:
|
||||
self.options = kwargs[self.type]
|
||||
|
||||
def as_volume_spec(self):
|
||||
mode = 'ro' if self.read_only else 'rw'
|
||||
return VolumeSpec(external=self.source, internal=self.target, mode=mode)
|
||||
|
||||
def legacy_repr(self):
|
||||
return self.as_volume_spec().repr()
|
||||
|
||||
def repr(self):
|
||||
res = {}
|
||||
for field in self._fields:
|
||||
if getattr(self, field, None):
|
||||
res[field] = getattr(self, field)
|
||||
if self.options:
|
||||
res[self.type] = self.options
|
||||
return res
|
||||
|
||||
@property
|
||||
def is_named_volume(self):
|
||||
return self.type == 'volume' and self.source
|
||||
|
||||
|
||||
class VolumeSpec(namedtuple('_VolumeSpec', 'external internal mode')):
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -14,6 +14,7 @@ from docker.errors import APIError
|
|||
from docker.errors import ImageNotFound
|
||||
from docker.errors import NotFound
|
||||
from docker.types import LogConfig
|
||||
from docker.types import Mount
|
||||
from docker.utils import version_gte
|
||||
from docker.utils import version_lt
|
||||
from docker.utils.ports import build_port_bindings
|
||||
|
@ -27,6 +28,7 @@ from .config import DOCKER_CONFIG_KEYS
|
|||
from .config import merge_environment
|
||||
from .config import merge_labels
|
||||
from .config.errors import DependencyError
|
||||
from .config.types import MountSpec
|
||||
from .config.types import ServicePort
|
||||
from .config.types import VolumeSpec
|
||||
from .const import DEFAULT_TIMEOUT
|
||||
|
@ -795,9 +797,13 @@ class Service(object):
|
|||
|
||||
secret_volumes = self.get_secret_volumes()
|
||||
if secret_volumes:
|
||||
override_options['binds'].extend(v.repr() for v in secret_volumes)
|
||||
container_options['volumes'].update(
|
||||
(v.internal, {}) for v in secret_volumes)
|
||||
if version_lt(self.client.api_version, '1.30'):
|
||||
override_options['binds'].extend(v.legacy_repr() for v in secret_volumes)
|
||||
container_options['volumes'].update(
|
||||
(v.target, {}) for v in secret_volumes
|
||||
)
|
||||
else:
|
||||
override_options['mounts'] = [build_mount(v) for v in secret_volumes]
|
||||
|
||||
container_options['image'] = self.image_name
|
||||
|
||||
|
@ -891,6 +897,7 @@ class Service(object):
|
|||
device_read_iops=blkio_config.get('device_read_iops'),
|
||||
device_write_bps=blkio_config.get('device_write_bps'),
|
||||
device_write_iops=blkio_config.get('device_write_iops'),
|
||||
mounts=options.get('mounts'),
|
||||
)
|
||||
|
||||
def get_secret_volumes(self):
|
||||
|
@ -901,7 +908,7 @@ class Service(object):
|
|||
elif not os.path.isabs(target):
|
||||
target = '{}/{}'.format(const.SECRETS_PATH, target)
|
||||
|
||||
return VolumeSpec(secret['file'], target, 'ro')
|
||||
return MountSpec('bind', secret['file'], target, read_only=True)
|
||||
|
||||
return [build_spec(secret) for secret in self.secrets]
|
||||
|
||||
|
@ -1346,6 +1353,18 @@ def build_volume_from(volume_from_spec):
|
|||
return "{}:{}".format(volume_from_spec.source.id, volume_from_spec.mode)
|
||||
|
||||
|
||||
def build_mount(mount_spec):
|
||||
kwargs = {}
|
||||
if mount_spec.options:
|
||||
for option, sdk_name in mount_spec.options_map[mount_spec.type].items():
|
||||
if option in mount_spec.options:
|
||||
kwargs[sdk_name] = mount_spec.options[option]
|
||||
|
||||
return Mount(
|
||||
type=mount_spec.type, target=mount_spec.target, source=mount_spec.source,
|
||||
read_only=mount_spec.read_only, consistency=mount_spec.consistency, **kwargs
|
||||
)
|
||||
|
||||
# Labels
|
||||
|
||||
|
||||
|
|
|
@ -1133,8 +1133,8 @@ class ServiceSecretTest(unittest.TestCase):
|
|||
)
|
||||
volumes = service.get_secret_volumes()
|
||||
|
||||
assert volumes[0].external == secret1['file']
|
||||
assert volumes[0].internal == '{}/{}'.format(SECRETS_PATH, secret1['secret'].target)
|
||||
assert volumes[0].source == secret1['file']
|
||||
assert volumes[0].target == '{}/{}'.format(SECRETS_PATH, secret1['secret'].target)
|
||||
|
||||
def test_get_secret_volumes_abspath(self):
|
||||
secret1 = {
|
||||
|
@ -1149,8 +1149,8 @@ class ServiceSecretTest(unittest.TestCase):
|
|||
)
|
||||
volumes = service.get_secret_volumes()
|
||||
|
||||
assert volumes[0].external == secret1['file']
|
||||
assert volumes[0].internal == secret1['secret'].target
|
||||
assert volumes[0].source == secret1['file']
|
||||
assert volumes[0].target == secret1['secret'].target
|
||||
|
||||
def test_get_secret_volumes_no_target(self):
|
||||
secret1 = {
|
||||
|
@ -1165,5 +1165,5 @@ class ServiceSecretTest(unittest.TestCase):
|
|||
)
|
||||
volumes = service.get_secret_volumes()
|
||||
|
||||
assert volumes[0].external == secret1['file']
|
||||
assert volumes[0].internal == '{}/{}'.format(SECRETS_PATH, secret1['secret'].source)
|
||||
assert volumes[0].source == secret1['file']
|
||||
assert volumes[0].target == '{}/{}'.format(SECRETS_PATH, secret1['secret'].source)
|
||||
|
|
Loading…
Reference in New Issue