Fixed binds and volumes. Now recognizes bound vs unbound as well as named volumes.

This commit is contained in:
chouseknecht 2016-06-01 12:28:47 -04:00 committed by Matt Clay
parent abbddbde49
commit 9dd95efe76

View file

@ -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,24 +829,37 @@ 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(':')
if re.match(r'[\.~]', host):
host = os.path.abspath(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("%s:%s:rw" % (host, parts[1]))
continue
new_vols.append(vol) 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:
if len(vol.split(':')) == 3:
host, container, _ = vol.split(':') host, container, _ = vol.split(':')
result.append(host) result.append(container)
else: continue
if len(vol.split(':')) == 2:
parts = vol.split(':')
if parts[1] not in VOLUME_PERMISSIONS:
result.append(parts[1])
continue
result.append(vol) result.append(vol)
self.log("mounts:") self.log("mounts:")
self.log(result, pretty_print=True) self.log(result, pretty_print=True)
@ -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:
parts = vol.split(':')
if parts[1] not in VOLUME_PERMISSIONS:
host, container, mode = (vol.split(':') + ['rw']) host, container, mode = (vol.split(':') + ['rw'])
self.volume_binds[host] = dict( 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:
parts = vol.split(':')
if parts[1] not in VOLUME_PERMISSIONS:
host, container, mode = vol.split(':') + ['rw'] 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()
@ -1535,7 +1592,7 @@ class ContainerManager(DockerBaseClass):
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)