diff --git a/changelogs/fragments/58791-docker-errors.yml b/changelogs/fragments/58791-docker-errors.yml new file mode 100644 index 00000000000..226c8f1730e --- /dev/null +++ b/changelogs/fragments/58791-docker-errors.yml @@ -0,0 +1,3 @@ +bugfixes: +- "docker_image - validate ``tag`` option value." +- "docker_* modules - behave better when requests errors are not caught by docker-py." \ No newline at end of file diff --git a/lib/ansible/module_utils/docker/common.py b/lib/ansible/module_utils/docker/common.py index f530bcc2556..ded0316a582 100644 --- a/lib/ansible/module_utils/docker/common.py +++ b/lib/ansible/module_utils/docker/common.py @@ -74,6 +74,16 @@ except ImportError: HAS_DOCKER_SSLADAPTER = False +try: + from request.exceptions import RequestException +except ImportError: + # Either docker-py is no longer using requests, or docker-py isn't around either, + # or docker-py's dependency requests is missing. In any case, define an exception + # class RequestException so that our code doesn't break. + class RequestException(Exception): + pass + + DEFAULT_DOCKER_HOST = 'unix://var/run/docker.sock' DEFAULT_TLS = False DEFAULT_TLS_VERIFY = False @@ -123,12 +133,21 @@ if not HAS_DOCKER_PY: def is_image_name_id(name): - """Checks whether the given image name is in fact an image ID (hash).""" + """Check whether the given image name is in fact an image ID (hash).""" if re.match('^sha256:[0-9a-fA-F]{64}$', name): return True return False +def is_valid_tag(tag, allow_empty=False): + """Check whether the given string is a valid docker tag name.""" + if not tag: + return allow_empty + # See here ("Extended description") for a definition what tags can be: + # https://docs.docker.com/engine/reference/commandline/tag/ + return bool(re.match('^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$', tag)) + + def sanitize_result(data): """Sanitize data object for return to Ansible. diff --git a/lib/ansible/modules/cloud/docker/docker_compose.py b/lib/ansible/modules/cloud/docker/docker_compose.py index c3b14d10024..4635bcc4e2c 100644 --- a/lib/ansible/modules/cloud/docker/docker_compose.py +++ b/lib/ansible/modules/cloud/docker/docker_compose.py @@ -451,7 +451,7 @@ try: import yaml HAS_YAML = True HAS_YAML_EXC = None -except ImportError as exc: +except ImportError as dummy: HAS_YAML = False HAS_YAML_EXC = traceback.format_exc() @@ -470,12 +470,16 @@ try: HAS_COMPOSE = True HAS_COMPOSE_EXC = None MINIMUM_COMPOSE_VERSION = '1.7.0' -except ImportError as exc: +except ImportError as dummy: HAS_COMPOSE = False HAS_COMPOSE_EXC = traceback.format_exc() DEFAULT_TIMEOUT = 10 -from ansible.module_utils.docker.common import AnsibleDockerClient, DockerBaseClass +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + DockerBaseClass, + RequestException, +) AUTH_PARAM_MAPPING = { @@ -1101,6 +1105,8 @@ def main(): client.module.exit_json(**result) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_config.py b/lib/ansible/modules/cloud/docker/docker_config.py index 876f96124d4..2ee7cc7b768 100644 --- a/lib/ansible/modules/cloud/docker/docker_config.py +++ b/lib/ansible/modules/cloud/docker/docker_config.py @@ -160,7 +160,12 @@ except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass -from ansible.module_utils.docker.common import AnsibleDockerClient, DockerBaseClass, compare_generic +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + DockerBaseClass, + compare_generic, + RequestException, +) from ansible.module_utils._text import to_native, to_bytes @@ -291,6 +296,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_container.py b/lib/ansible/modules/cloud/docker/docker_container.py index ad3aeb0e630..d31c98a4660 100644 --- a/lib/ansible/modules/cloud/docker/docker_container.py +++ b/lib/ansible/modules/cloud/docker/docker_container.py @@ -955,6 +955,7 @@ from ansible.module_utils.docker.common import ( sanitize_result, parse_healthcheck, DOCKER_COMMON_ARGS, + RequestException, ) from ansible.module_utils.six import string_types @@ -1419,7 +1420,7 @@ class TaskParameters(DockerBaseClass): break except NotFound as e: self.client.fail( - "Cannot inspect the network '{0}' to determine the default IP.".format(net['name']), + "Cannot inspect the network '{0}' to determine the default IP: {1}".format(net['name'], e), exception=traceback.format_exc() ) return ip @@ -2651,9 +2652,9 @@ class ContainerManager(DockerBaseClass): if not self.check_mode: try: if self.parameters.stop_timeout: - response = self.client.restart(container_id, timeout=self.parameters.stop_timeout) + dummy = self.client.restart(container_id, timeout=self.parameters.stop_timeout) else: - response = self.client.restart(container_id) + dummy = self.client.restart(container_id) except Exception as exc: self.fail("Error restarting container %s: %s" % (container_id, str(exc))) return self._get_container(container_id) @@ -3029,6 +3030,8 @@ def main(): client.module.exit_json(**sanitize_result(cm.results)) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_container_info.py b/lib/ansible/modules/cloud/docker/docker_container_info.py index 59211a622c9..44be2e95231 100644 --- a/lib/ansible/modules/cloud/docker/docker_container_info.py +++ b/lib/ansible/modules/cloud/docker/docker_container_info.py @@ -115,7 +115,10 @@ except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass -from ansible.module_utils.docker.common import AnsibleDockerClient +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + RequestException, +) def main(): @@ -139,6 +142,8 @@ def main(): ) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_host_info.py b/lib/ansible/modules/cloud/docker/docker_host_info.py index 64ce257b7de..f3bcf796e74 100644 --- a/lib/ansible/modules/cloud/docker/docker_host_info.py +++ b/lib/ansible/modules/cloud/docker/docker_host_info.py @@ -187,7 +187,11 @@ disk_usage: import traceback -from ansible.module_utils.docker.common import AnsibleDockerClient, DockerBaseClass +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + DockerBaseClass, + RequestException, +) from ansible.module_utils._text import to_native try: @@ -332,6 +336,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_image.py b/lib/ansible/modules/cloud/docker/docker_image.py index 6a9a672c46d..71e83c9b4a9 100644 --- a/lib/ansible/modules/cloud/docker/docker_image.py +++ b/lib/ansible/modules/cloud/docker/docker_image.py @@ -424,7 +424,12 @@ import traceback from distutils.version import LooseVersion from ansible.module_utils.docker.common import ( - docker_version, AnsibleDockerClient, DockerBaseClass, is_image_name_id, + docker_version, + AnsibleDockerClient, + DockerBaseClass, + is_image_name_id, + is_valid_tag, + RequestException, ) from ansible.module_utils._text import to_native @@ -879,6 +884,9 @@ def main(): 'and will be removed in Ansible 2.11. Please use the' '"tls" and "tls_verify" options instead.') + if not is_valid_tag(client.module.params['tag'], allow_empty=True): + client.fail('"{0}" is not a valid docker tag!'.format(client.module.params['tag'])) + build_options = dict( container_limits='container_limits', dockerfile='dockerfile', @@ -942,6 +950,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_image_info.py b/lib/ansible/modules/cloud/docker/docker_image_info.py index 773aa188b42..c1027162d5c 100644 --- a/lib/ansible/modules/cloud/docker/docker_image_info.py +++ b/lib/ansible/modules/cloud/docker/docker_image_info.py @@ -163,7 +163,12 @@ except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass -from ansible.module_utils.docker.common import AnsibleDockerClient, DockerBaseClass, is_image_name_id +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + DockerBaseClass, + is_image_name_id, + RequestException, +) class ImageManager(DockerBaseClass): @@ -247,6 +252,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_login.py b/lib/ansible/modules/cloud/docker/docker_login.py index 60475be9edb..19df546de39 100644 --- a/lib/ansible/modules/cloud/docker/docker_login.py +++ b/lib/ansible/modules/cloud/docker/docker_login.py @@ -138,7 +138,13 @@ except ImportError: pass from ansible.module_utils._text import to_bytes, to_text -from ansible.module_utils.docker.common import AnsibleDockerClient, DEFAULT_DOCKER_REGISTRY, DockerBaseClass, EMAIL_REGEX +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + DEFAULT_DOCKER_REGISTRY, + DockerBaseClass, + EMAIL_REGEX, + RequestException, +) class LoginManager(DockerBaseClass): @@ -331,6 +337,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_network.py b/lib/ansible/modules/cloud/docker/docker_network.py index ad79c24fdec..fbeebd1fe89 100644 --- a/lib/ansible/modules/cloud/docker/docker_network.py +++ b/lib/ansible/modules/cloud/docker/docker_network.py @@ -286,6 +286,7 @@ from ansible.module_utils.docker.common import ( docker_version, DifferenceTracker, clean_dict_booleans_for_docker_api, + RequestException, ) try: @@ -688,6 +689,8 @@ def main(): client.module.exit_json(**cm.results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_network_info.py b/lib/ansible/modules/cloud/docker/docker_network_info.py index 40d02c21c05..ed2963165c0 100644 --- a/lib/ansible/modules/cloud/docker/docker_network_info.py +++ b/lib/ansible/modules/cloud/docker/docker_network_info.py @@ -111,7 +111,10 @@ except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass -from ansible.module_utils.docker.common import AnsibleDockerClient +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + RequestException, +) def main(): @@ -135,6 +138,8 @@ def main(): ) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_node.py b/lib/ansible/modules/cloud/docker/docker_node.py index 1c2455dbbe8..9ef36fb586b 100644 --- a/lib/ansible/modules/cloud/docker/docker_node.py +++ b/lib/ansible/modules/cloud/docker/docker_node.py @@ -139,6 +139,7 @@ except ImportError: from ansible.module_utils.docker.common import ( DockerBaseClass, + RequestException, ) from ansible.module_utils._text import to_native @@ -288,6 +289,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_node_info.py b/lib/ansible/modules/cloud/docker/docker_node_info.py index 38fe2fbc43b..a32545c2fd1 100644 --- a/lib/ansible/modules/cloud/docker/docker_node_info.py +++ b/lib/ansible/modules/cloud/docker/docker_node_info.py @@ -89,10 +89,13 @@ nodes: import traceback +from ansible.module_utils.docker.common import ( + RequestException, +) from ansible.module_utils.docker.swarm import AnsibleDockerSwarmClient try: - from docker.errors import DockerException, APIError, NotFound + from docker.errors import DockerException except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass @@ -147,6 +150,8 @@ def main(): ) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_prune.py b/lib/ansible/modules/cloud/docker/docker_prune.py index 902e6fbb515..f088f60c272 100644 --- a/lib/ansible/modules/cloud/docker/docker_prune.py +++ b/lib/ansible/modules/cloud/docker/docker_prune.py @@ -187,7 +187,10 @@ except ImportError: from distutils.version import LooseVersion -from ansible.module_utils.docker.common import AnsibleDockerClient +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + RequestException, +) try: from ansible.module_utils.docker.common import docker_version, clean_dict_booleans_for_docker_api @@ -255,6 +258,8 @@ def main(): client.module.exit_json(**result) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_secret.py b/lib/ansible/modules/cloud/docker/docker_secret.py index 5822a2719d9..2cd32dea37a 100644 --- a/lib/ansible/modules/cloud/docker/docker_secret.py +++ b/lib/ansible/modules/cloud/docker/docker_secret.py @@ -160,7 +160,12 @@ except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass -from ansible.module_utils.docker.common import AnsibleDockerClient, DockerBaseClass, compare_generic +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + DockerBaseClass, + compare_generic, + RequestException, +) from ansible.module_utils._text import to_native, to_bytes @@ -292,6 +297,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_swarm.py b/lib/ansible/modules/cloud/docker/docker_swarm.py index d6ff74a6400..c91212b5b45 100644 --- a/lib/ansible/modules/cloud/docker/docker_swarm.py +++ b/lib/ansible/modules/cloud/docker/docker_swarm.py @@ -278,7 +278,7 @@ except ImportError: from ansible.module_utils.docker.common import ( DockerBaseClass, DifferenceTracker, - LooseVersion, + RequestException, ) from ansible.module_utils.docker.swarm import AnsibleDockerSwarmClient @@ -671,6 +671,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_swarm_info.py b/lib/ansible/modules/cloud/docker/docker_swarm_info.py index 8cde9b4576a..dedbb01bdf2 100644 --- a/lib/ansible/modules/cloud/docker/docker_swarm_info.py +++ b/lib/ansible/modules/cloud/docker/docker_swarm_info.py @@ -195,7 +195,7 @@ tasks: import traceback try: - from docker.errors import DockerException, APIError, NotFound + from docker.errors import DockerException, APIError except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker_common pass @@ -203,7 +203,11 @@ except ImportError: from ansible.module_utils._text import to_native from ansible.module_utils.docker.swarm import AnsibleDockerSwarmClient -from ansible.module_utils.docker.common import DockerBaseClass, clean_dict_booleans_for_docker_api +from ansible.module_utils.docker.common import ( + DockerBaseClass, + clean_dict_booleans_for_docker_api, + RequestException, +) class DockerSwarmManager(DockerBaseClass): @@ -373,6 +377,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_swarm_service.py b/lib/ansible/modules/cloud/docker/docker_swarm_service.py index 2825c4cf473..08b24df5475 100644 --- a/lib/ansible/modules/cloud/docker/docker_swarm_service.py +++ b/lib/ansible/modules/cloud/docker/docker_swarm_service.py @@ -1051,9 +1051,10 @@ from ansible.module_utils.docker.common import ( DifferenceTracker, DockerBaseClass, convert_duration_to_nanosecond, - parse_healthcheck - + parse_healthcheck, + RequestException, ) + from ansible.module_utils.basic import human_to_bytes from ansible.module_utils.six import string_types from ansible.module_utils._text import to_text @@ -2813,6 +2814,8 @@ def main(): client.module.exit_json(**results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_swarm_service_info.py b/lib/ansible/modules/cloud/docker/docker_swarm_service_info.py index 9ec4cb3aeca..76465f30192 100644 --- a/lib/ansible/modules/cloud/docker/docker_swarm_service_info.py +++ b/lib/ansible/modules/cloud/docker/docker_swarm_service_info.py @@ -74,6 +74,10 @@ except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass +from ansible.module_utils.docker.common import ( + RequestException, +) + from ansible.module_utils.docker.swarm import AnsibleDockerSwarmClient @@ -109,6 +113,8 @@ def main(): ) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_volume.py b/lib/ansible/modules/cloud/docker/docker_volume.py index 66eade09b70..544bce0e86e 100644 --- a/lib/ansible/modules/cloud/docker/docker_volume.py +++ b/lib/ansible/modules/cloud/docker/docker_volume.py @@ -137,6 +137,7 @@ from ansible.module_utils.docker.common import ( DockerBaseClass, AnsibleDockerClient, DifferenceTracker, + RequestException, ) from ansible.module_utils.six import iteritems, text_type @@ -330,6 +331,8 @@ def main(): client.module.exit_json(**cm.results) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__': diff --git a/lib/ansible/modules/cloud/docker/docker_volume_info.py b/lib/ansible/modules/cloud/docker/docker_volume_info.py index 3bad1a937cb..75a53dd2096 100644 --- a/lib/ansible/modules/cloud/docker/docker_volume_info.py +++ b/lib/ansible/modules/cloud/docker/docker_volume_info.py @@ -88,7 +88,10 @@ except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass -from ansible.module_utils.docker.common import AnsibleDockerClient +from ansible.module_utils.docker.common import ( + AnsibleDockerClient, + RequestException, +) def get_existing_volume(client, volume_name): @@ -122,6 +125,8 @@ def main(): ) except DockerException as e: client.fail('An unexpected docker error occurred: {0}'.format(e), exception=traceback.format_exc()) + except RequestException as e: + client.fail('An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}'.format(e), exception=traceback.format_exc()) if __name__ == '__main__':