errors.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. from __future__ import absolute_import
  2. from __future__ import unicode_literals
  3. import contextlib
  4. import logging
  5. import socket
  6. from textwrap import dedent
  7. from docker.errors import APIError
  8. from requests.exceptions import ConnectionError as RequestsConnectionError
  9. from requests.exceptions import ReadTimeout
  10. from requests.exceptions import SSLError
  11. from requests.packages.urllib3.exceptions import ReadTimeoutError
  12. from ..const import API_VERSION_TO_ENGINE_VERSION
  13. from .utils import call_silently
  14. from .utils import is_mac
  15. from .utils import is_ubuntu
  16. log = logging.getLogger(__name__)
  17. class UserError(Exception):
  18. def __init__(self, msg):
  19. self.msg = dedent(msg).strip()
  20. def __unicode__(self):
  21. return self.msg
  22. __str__ = __unicode__
  23. class ConnectionError(Exception):
  24. pass
  25. @contextlib.contextmanager
  26. def handle_connection_errors(client):
  27. try:
  28. yield
  29. except SSLError as e:
  30. log.error('SSL error: %s' % e)
  31. raise ConnectionError()
  32. except RequestsConnectionError as e:
  33. if e.args and isinstance(e.args[0], ReadTimeoutError):
  34. log_timeout_error(client.timeout)
  35. raise ConnectionError()
  36. if call_silently(['which', 'docker']) != 0:
  37. if is_mac():
  38. exit_with_error(docker_not_found_mac)
  39. if is_ubuntu():
  40. exit_with_error(docker_not_found_ubuntu)
  41. exit_with_error(docker_not_found_generic)
  42. if call_silently(['which', 'docker-machine']) == 0:
  43. exit_with_error(conn_error_docker_machine)
  44. exit_with_error(conn_error_generic.format(url=client.base_url))
  45. except APIError as e:
  46. log_api_error(e, client.api_version)
  47. raise ConnectionError()
  48. except (ReadTimeout, socket.timeout) as e:
  49. log_timeout_error()
  50. raise ConnectionError()
  51. def log_timeout_error(timeout):
  52. log.error(
  53. "An HTTP request took too long to complete. Retry with --verbose to "
  54. "obtain debug information.\n"
  55. "If you encounter this issue regularly because of slow network "
  56. "conditions, consider setting COMPOSE_HTTP_TIMEOUT to a higher "
  57. "value (current value: %s)." % timeout)
  58. def log_api_error(e, client_version):
  59. if b'client is newer than server' not in e.explanation:
  60. log.error(e.explanation)
  61. return
  62. version = API_VERSION_TO_ENGINE_VERSION.get(client_version)
  63. if not version:
  64. # They've set a custom API version
  65. log.error(e.explanation)
  66. return
  67. log.error(
  68. "The Docker Engine version is less than the minimum required by "
  69. "Compose. Your current project requires a Docker Engine of "
  70. "version {version} or greater.".format(version=version))
  71. def exit_with_error(msg):
  72. log.error(dedent(msg).strip())
  73. raise ConnectionError()
  74. docker_not_found_mac = """
  75. Couldn't connect to Docker daemon. You might need to install Docker:
  76. https://docs.docker.com/engine/installation/mac/
  77. """
  78. docker_not_found_ubuntu = """
  79. Couldn't connect to Docker daemon. You might need to install Docker:
  80. https://docs.docker.com/engine/installation/ubuntulinux/
  81. """
  82. docker_not_found_generic = """
  83. Couldn't connect to Docker daemon. You might need to install Docker:
  84. https://docs.docker.com/engine/installation/
  85. """
  86. conn_error_docker_machine = """
  87. Couldn't connect to Docker daemon - you might need to run `docker-machine start default`.
  88. """
  89. conn_error_generic = """
  90. Couldn't connect to Docker daemon at {url} - is it running?
  91. If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable.
  92. """