Fixed binds and volumes. Now recognizes bound vs unbound as well as named volumes.
This commit is contained in:
parent
abbddbde49
commit
9dd95efe76
1 changed files with 99 additions and 42 deletions
|
@ -626,6 +626,8 @@ ansible_docker_container:
|
||||||
}'
|
}'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from ansible.module_utils.docker_common import *
|
from ansible.module_utils.docker_common import *
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -643,6 +645,7 @@ REQUIRES_CONVERSION_TO_BYTES = [
|
||||||
'shm_size'
|
'shm_size'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
VOLUME_PERMISSIONS = ('rw', 'ro', 'z', 'Z')
|
||||||
|
|
||||||
class TaskParameters(DockerBaseClass):
|
class TaskParameters(DockerBaseClass):
|
||||||
'''
|
'''
|
||||||
|
@ -739,14 +742,16 @@ class TaskParameters(DockerBaseClass):
|
||||||
if self.volumes:
|
if self.volumes:
|
||||||
self.volumes = self._expand_host_paths()
|
self.volumes = self._expand_host_paths()
|
||||||
|
|
||||||
self.log("volumes:")
|
|
||||||
self.log(self.volumes, pretty_print=True)
|
|
||||||
|
|
||||||
self.env = self._get_environment()
|
self.env = self._get_environment()
|
||||||
self.ulimits = self._parse_ulimits()
|
self.ulimits = self._parse_ulimits()
|
||||||
self.log_config = self._parse_log_config()
|
self.log_config = self._parse_log_config()
|
||||||
self.exp_links = None
|
self.exp_links = None
|
||||||
self._parse_volumes()
|
self.volume_binds = self._get_volume_binds(self.volumes)
|
||||||
|
|
||||||
|
self.log("volumes:")
|
||||||
|
self.log(self.volumes, pretty_print=True)
|
||||||
|
self.log("volume binds:")
|
||||||
|
self.log(self.volume_binds, pretty_print=True)
|
||||||
|
|
||||||
if self.networks:
|
if self.networks:
|
||||||
for network in self.networks:
|
for network in self.networks:
|
||||||
|
@ -824,25 +829,38 @@ class TaskParameters(DockerBaseClass):
|
||||||
if ':' in vol:
|
if ':' in vol:
|
||||||
if len(vol.split(':')) == 3:
|
if len(vol.split(':')) == 3:
|
||||||
host, container, mode = vol.split(':')
|
host, container, mode = vol.split(':')
|
||||||
host = os.path.abspath(host)
|
if re.match(r'[\.~]', host):
|
||||||
|
host = os.path.abspath(host)
|
||||||
new_vols.append("%s:%s:%s" % (host, container, mode))
|
new_vols.append("%s:%s:%s" % (host, container, mode))
|
||||||
else:
|
continue
|
||||||
host, container = vol.split(':')
|
elif len(vol.split(':')) == 2:
|
||||||
host = os.path.abspath(host)
|
parts = vol.split(':')
|
||||||
new_vols.append("%s:%s:rw" % (host, container))
|
if parts[1] not in VOLUME_PERMISSIONS and re.match(r'[\.~]', parts[0]):
|
||||||
else:
|
host = os.path.abspath(parts[0])
|
||||||
new_vols.append(vol)
|
new_vols.append("%s:%s:rw" % (host, parts[1]))
|
||||||
|
continue
|
||||||
|
new_vols.append(vol)
|
||||||
return new_vols
|
return new_vols
|
||||||
|
|
||||||
def _get_mounts(self):
|
def _get_mounts(self):
|
||||||
|
'''
|
||||||
|
Return a list of container mounts.
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
result = []
|
result = []
|
||||||
if self.volumes:
|
if self.volumes:
|
||||||
for vol in self.volumes:
|
for vol in self.volumes:
|
||||||
if ':' in vol:
|
if ':' in vol:
|
||||||
host, container, _ = vol.split(':')
|
if len(vol.split(':')) == 3:
|
||||||
result.append(host)
|
host, container, _ = vol.split(':')
|
||||||
else:
|
result.append(container)
|
||||||
result.append(vol)
|
continue
|
||||||
|
if len(vol.split(':')) == 2:
|
||||||
|
parts = vol.split(':')
|
||||||
|
if parts[1] not in VOLUME_PERMISSIONS:
|
||||||
|
result.append(parts[1])
|
||||||
|
continue
|
||||||
|
result.append(vol)
|
||||||
self.log("mounts:")
|
self.log("mounts:")
|
||||||
self.log(result, pretty_print=True)
|
self.log(result, pretty_print=True)
|
||||||
return result
|
return result
|
||||||
|
@ -923,24 +941,30 @@ class TaskParameters(DockerBaseClass):
|
||||||
binds[container_port] = bind
|
binds[container_port] = bind
|
||||||
return binds
|
return binds
|
||||||
|
|
||||||
def _parse_volumes(self):
|
@staticmethod
|
||||||
|
def _get_volume_binds(volumes):
|
||||||
'''
|
'''
|
||||||
Convert volumes parameter to host_config bind format.
|
Extract host bindings, if any, from list of volume mapping strings.
|
||||||
https://docker-py.readthedocs.org/en/latest/volumes/
|
|
||||||
:return: array of binds
|
:return: dictionary of bind mappings
|
||||||
'''
|
'''
|
||||||
if self.volumes:
|
result = dict()
|
||||||
for vol in self.volumes:
|
if volumes:
|
||||||
|
for vol in volumes:
|
||||||
|
host = None
|
||||||
if ':' in vol:
|
if ':' in vol:
|
||||||
if len(vol.split(':')) == 3:
|
if len(vol.split(':')) == 3:
|
||||||
host, container, mode = vol.split(':')
|
host, container, mode = vol.split(':')
|
||||||
else:
|
if len(vol.split(':')) == 2:
|
||||||
host, container, mode = (vol.split(':') + ['rw'])
|
parts = vol.split(':')
|
||||||
self.volume_binds[host] = dict(
|
if parts[1] not in VOLUME_PERMISSIONS:
|
||||||
|
host, container, mode = (vol.split(':') + ['rw'])
|
||||||
|
if host is not None:
|
||||||
|
result[host] = dict(
|
||||||
bind=container,
|
bind=container,
|
||||||
mode=mode
|
mode=mode
|
||||||
)
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
def _parse_exposed_ports(self):
|
def _parse_exposed_ports(self):
|
||||||
'''
|
'''
|
||||||
|
@ -1091,6 +1115,7 @@ class Container(DockerBaseClass):
|
||||||
self.parameters.expected_ports = self._get_expected_ports()
|
self.parameters.expected_ports = self._get_expected_ports()
|
||||||
self.parameters.expected_exposed = self._get_expected_exposed(image)
|
self.parameters.expected_exposed = self._get_expected_exposed(image)
|
||||||
self.parameters.expected_volumes = self._get_expected_volumes(image)
|
self.parameters.expected_volumes = self._get_expected_volumes(image)
|
||||||
|
self.parameters.expected_binds = self._get_expected_binds(image)
|
||||||
self.parameters.expected_ulimits = self._get_expected_ulimits(self.parameters.ulimits)
|
self.parameters.expected_ulimits = self._get_expected_ulimits(self.parameters.ulimits)
|
||||||
self.parameters.expected_etc_hosts = self._convert_simple_dict_to_list('etc_hosts')
|
self.parameters.expected_etc_hosts = self._convert_simple_dict_to_list('etc_hosts')
|
||||||
self.parameters.expected_env = self._get_expected_env(image)
|
self.parameters.expected_env = self._get_expected_env(image)
|
||||||
|
@ -1154,7 +1179,8 @@ class Container(DockerBaseClass):
|
||||||
tty=config.get('Tty'),
|
tty=config.get('Tty'),
|
||||||
expected_ulimits=host_config.get('Ulimits'),
|
expected_ulimits=host_config.get('Ulimits'),
|
||||||
uts=host_config.get('UTSMode'),
|
uts=host_config.get('UTSMode'),
|
||||||
expected_volumes=host_config['Binds'],
|
expected_volumes=config.get('Volumes'),
|
||||||
|
expected_binds=host_config.get('Binds'),
|
||||||
volumes_from=host_config.get('VolumesFrom'),
|
volumes_from=host_config.get('VolumesFrom'),
|
||||||
volume_driver=host_config.get('VolumeDriver')
|
volume_driver=host_config.get('VolumeDriver')
|
||||||
)
|
)
|
||||||
|
@ -1382,26 +1408,30 @@ class Container(DockerBaseClass):
|
||||||
exp_links.append("/%s:%s/%s" % (link, ('/' + self.parameters.name), alias))
|
exp_links.append("/%s:%s/%s" % (link, ('/' + self.parameters.name), alias))
|
||||||
return exp_links
|
return exp_links
|
||||||
|
|
||||||
def _get_expected_volumes(self, image):
|
def _get_expected_binds(self, image):
|
||||||
self.log('_get_expected_volumes')
|
self.log('_get_expected_binds')
|
||||||
image_vols = []
|
image_vols = []
|
||||||
if image:
|
if image:
|
||||||
image_vols = self._get_volumes_from_binds(image['ContainerConfig'].get('Volumes'))
|
image_vols = self._get_image_binds(image['ContainerConfig'].get('Volumes'))
|
||||||
param_vols = []
|
param_vols = []
|
||||||
if self.parameters.volumes:
|
if self.parameters.volumes:
|
||||||
for vol in self.parameters.volumes:
|
for vol in self.parameters.volumes:
|
||||||
|
host = None
|
||||||
if ':' in vol:
|
if ':' in vol:
|
||||||
if len(vol.split(':')) == 3:
|
if len(vol.split(':')) == 3:
|
||||||
host, container, mode = vol.split(':')
|
host, container, mode = vol.split(':')
|
||||||
else:
|
if len(vol.split(':')) == 2:
|
||||||
host, container, mode = vol.split(':') + ['rw']
|
parts = vol.split(':')
|
||||||
|
if parts[1] not in VOLUME_PERMISSIONS:
|
||||||
|
host, container, mode = vol.split(':') + ['rw']
|
||||||
|
if host:
|
||||||
param_vols.append("%s:%s:%s" % (host, container, mode))
|
param_vols.append("%s:%s:%s" % (host, container, mode))
|
||||||
else:
|
result = list(set(image_vols + param_vols))
|
||||||
param_vols.append(vol)
|
self.log("expected_binds:")
|
||||||
# flip to container first
|
self.log(result, pretty_print=True)
|
||||||
return list(set(image_vols + param_vols))
|
return result
|
||||||
|
|
||||||
def _get_volumes_from_binds(self, volumes):
|
def _get_image_binds(self, volumes):
|
||||||
'''
|
'''
|
||||||
Convert array of binds to array of strings with format host_path:container_path:mode
|
Convert array of binds to array of strings with format host_path:container_path:mode
|
||||||
|
|
||||||
|
@ -1410,13 +1440,14 @@ class Container(DockerBaseClass):
|
||||||
'''
|
'''
|
||||||
results = []
|
results = []
|
||||||
if isinstance(volumes, dict):
|
if isinstance(volumes, dict):
|
||||||
results += self._get_volume_from_dict(volumes)
|
results += self._get_bind_from_dict(volumes)
|
||||||
elif isinstance(volumes, list):
|
elif isinstance(volumes, list):
|
||||||
for vol in volumes:
|
for vol in volumes:
|
||||||
results += self._get_volume_from_dict(vol)
|
results += self._get_bind_from_dict(vol)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def _get_volume_from_dict(self, volume_dict):
|
@staticmethod
|
||||||
|
def _get_bind_from_dict(volume_dict):
|
||||||
results = []
|
results = []
|
||||||
if volume_dict:
|
if volume_dict:
|
||||||
for host_path, config in volume_dict.items():
|
for host_path, config in volume_dict.items():
|
||||||
|
@ -1426,6 +1457,32 @@ class Container(DockerBaseClass):
|
||||||
results.append("%s:%s:%s" % (host_path, container_path, mode))
|
results.append("%s:%s:%s" % (host_path, container_path, mode))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
def _get_expected_volumes(self, image):
|
||||||
|
self.log('_get_expected_volumes')
|
||||||
|
expected_vols = dict()
|
||||||
|
if image and image['ContainerConfig'].get('Volumes'):
|
||||||
|
expected_vols.upate(image['ContainerConfig'].get('Volumes'))
|
||||||
|
|
||||||
|
if self.parameters.volumes:
|
||||||
|
for vol in self.parameters.volumes:
|
||||||
|
container = None
|
||||||
|
if ':' in vol:
|
||||||
|
if len(vol.split(':')) == 3:
|
||||||
|
host, container, mode = vol.split(':')
|
||||||
|
if len(vol.split(':')) == 2:
|
||||||
|
parts = vol.split(':')
|
||||||
|
if parts[1] not in VOLUME_PERMISSIONS:
|
||||||
|
host, container, mode = vol.split(':') + ['rw']
|
||||||
|
new_vol = dict()
|
||||||
|
if container:
|
||||||
|
new_vol[container] = dict()
|
||||||
|
else:
|
||||||
|
new_vol[vol] = dict()
|
||||||
|
expected_vols.update(new_vol)
|
||||||
|
self.log("expected_volumes:")
|
||||||
|
self.log(expected_vols, pretty_print=True)
|
||||||
|
return expected_vols
|
||||||
|
|
||||||
def _get_expected_env(self, image):
|
def _get_expected_env(self, image):
|
||||||
self.log('_get_expected_env')
|
self.log('_get_expected_env')
|
||||||
expected_env = dict()
|
expected_env = dict()
|
||||||
|
@ -1530,12 +1587,12 @@ class ContainerManager(DockerBaseClass):
|
||||||
new_container = self.container_create(self.parameters.image, self.parameters.create_parameters)
|
new_container = self.container_create(self.parameters.image, self.parameters.create_parameters)
|
||||||
if new_container:
|
if new_container:
|
||||||
container = new_container
|
container = new_container
|
||||||
container = self.update_limits(container)
|
container = self.update_limits(container)
|
||||||
container = self.update_networks(container)
|
container = self.update_networks(container)
|
||||||
if state == 'started':
|
if state == 'started':
|
||||||
container = self.container_start(container.Id)
|
container = self.container_start(container.Id)
|
||||||
self.facts = container.raw
|
self.facts = container.raw
|
||||||
return True
|
return
|
||||||
|
|
||||||
# Existing container
|
# Existing container
|
||||||
self.log(container.raw, pretty_print=True)
|
self.log(container.raw, pretty_print=True)
|
||||||
|
|
Loading…
Reference in a new issue