fix linting issues
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

This commit is contained in:
Robert Kaussow 2021-05-16 15:24:15 +02:00
parent af571cfb7f
commit f685450037
No known key found for this signature in database
GPG Key ID: 65362AE74AF98B61

View File

@ -1,12 +1,13 @@
#!/usr/bin/python # -*- coding: utf-8 -*-#
#
# Copyright 2016 Red Hat | Ansible # Copyright 2016 Red Hat | Ansible
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Module for Docker Compose."""
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
DOCUMENTATION = ''' DOCUMENTATION = """
module: docker_compose module: docker_compose
@ -76,7 +77,7 @@ options:
type: dict type: dict
hostname_check: hostname_check:
description: description:
- Whether or not to check the Docker daemon's hostname against the name provided in the client certificate. - Whether or not to check the Docker daemon"s hostname against the name provided in the client certificate.
type: bool type: bool
default: no default: no
recreate: recreate:
@ -116,8 +117,8 @@ options:
- Use with I(state) C(absent) to remove all images or only local images. - Use with I(state) C(absent) to remove all images or only local images.
type: str type: str
choices: choices:
- 'all' - "all"
- 'local' - "local"
remove_volumes: remove_volumes:
description: description:
- Use with I(state) C(absent) to remove data volumes. - Use with I(state) C(absent) to remove data volumes.
@ -159,9 +160,9 @@ requirements:
- "docker-compose >= 1.7.0" - "docker-compose >= 1.7.0"
- "Docker API >= 1.20" - "Docker API >= 1.20"
- "PyYAML >= 3.11" - "PyYAML >= 3.11"
''' """ # noqa
EXAMPLES = ''' EXAMPLES = """
# Examples use the django example at https://docs.docker.com/compose/django. Follow it to create the # Examples use the django example at https://docs.docker.com/compose/django. Follow it to create the
# flask directory # flask directory
@ -248,7 +249,7 @@ EXAMPLES = '''
- community.docker.docker_compose: - community.docker.docker_compose:
project_name: flask project_name: flask
definition: definition:
version: '2' version: "2"
services: services:
db: db:
image: postgres image: postgres
@ -302,12 +303,12 @@ EXAMPLES = '''
that: that:
- "web.flask_web_1.state.running" - "web.flask_web_1.state.running"
- "db.flask_db_1.state.running" - "db.flask_db_1.state.running"
''' """ # noqa
RETURN = ''' RETURN = """
services: services:
description: description:
- A dictionary mapping the service's name to a dictionary of containers. - A dictionary mapping the service"s name to a dictionary of containers.
returned: success returned: success
type: complex type: complex
contains: contains:
@ -353,12 +354,12 @@ services:
returned: success returned: success
type: list type: list
elements: str elements: str
example: ['db'] example: ["db"]
globalIPv6: globalIPv6:
description: IPv6 address assigned to the container. description: IPv6 address assigned to the container.
returned: success returned: success
type: str type: str
example: '' example: ""
globalIPv6PrefixLen: globalIPv6PrefixLen:
description: IPv6 subnet length. description: IPv6 subnet length.
returned: success returned: success
@ -429,24 +430,24 @@ actions:
type: str type: str
action: action:
description: A descriptive name of the action to be performed on the service's containers. description: A descriptive name of the action to be performed on the service"s containers.
returned: always returned: always
type: list type: list
elements: str elements: str
contains: contains:
id: id:
description: the container's long ID description: the container"s long ID
returned: always returned: always
type: str type: str
name: name:
description: the container's name description: the container"s name
returned: always returned: always
type: str type: str
short_id: short_id:
description: the container's short ID description: the container"s short ID
returned: always returned: always
type: str type: str
''' """ # noqa
import os import os
import re import re
@ -460,7 +461,7 @@ try:
import yaml import yaml
HAS_YAML = True HAS_YAML = True
HAS_YAML_EXC = None HAS_YAML_EXC = None
except ImportError as dummy: except ImportError:
HAS_YAML = False HAS_YAML = False
HAS_YAML_EXC = traceback.format_exc() HAS_YAML_EXC = traceback.format_exc()
@ -474,12 +475,14 @@ try:
from compose import __version__ as compose_version from compose import __version__ as compose_version
from compose.cli.command import project_from_options from compose.cli.command import project_from_options
from compose.service import NoSuchImageError from compose.service import NoSuchImageError
from compose.cli.main import convergence_strategy_from_opts, build_action_from_opts, image_type_from_opt from compose.cli.main import convergence_strategy_from_opts
from compose.cli.main import build_action_from_opts
from compose.cli.main import image_type_from_opt
from compose.const import DEFAULT_TIMEOUT, LABEL_SERVICE, LABEL_PROJECT, LABEL_ONE_OFF from compose.const import DEFAULT_TIMEOUT, LABEL_SERVICE, LABEL_PROJECT, LABEL_ONE_OFF
HAS_COMPOSE = True HAS_COMPOSE = True
HAS_COMPOSE_EXC = None HAS_COMPOSE_EXC = None
MINIMUM_COMPOSE_VERSION = '1.7.0' MINIMUM_COMPOSE_VERSION = "1.7.0"
except ImportError as dummy: except ImportError:
HAS_COMPOSE = False HAS_COMPOSE = False
HAS_COMPOSE_EXC = traceback.format_exc() HAS_COMPOSE_EXC = traceback.format_exc()
DEFAULT_TIMEOUT = 10 DEFAULT_TIMEOUT = 10
@ -493,19 +496,19 @@ from ansible_collections.community.docker.plugins.module_utils.common import (
) )
AUTH_PARAM_MAPPING = { AUTH_PARAM_MAPPING = {
u'docker_host': u'--host', u"docker_host": u"--host",
u'tls': u'--tls', u"tls": u"--tls",
u'cacert_path': u'--tlscacert', u"cacert_path": u"--tlscacert",
u'cert_path': u'--tlscert', u"cert_path": u"--tlscert",
u'key_path': u'--tlskey', u"key_path": u"--tlskey",
u'tls_verify': u'--tlsverify' u"tls_verify": u"--tlsverify"
} }
@contextmanager @contextmanager
def stdout_redirector(path_name): def stdout_redirector(path_name):
old_stdout = sys.stdout old_stdout = sys.stdout
fd = open(path_name, 'w') fd = open(path_name, "w")
sys.stdout = fd sys.stdout = fd
try: try:
yield yield
@ -516,7 +519,7 @@ def stdout_redirector(path_name):
@contextmanager @contextmanager
def stderr_redirector(path_name): def stderr_redirector(path_name):
old_fh = sys.stderr old_fh = sys.stderr
fd = open(path_name, 'w') fd = open(path_name, "w")
sys.stderr = fd sys.stderr = fd
try: try:
yield yield
@ -537,42 +540,42 @@ def cleanup_redirection_tempfiles(out_name, err_name):
def get_redirected_output(path_name): def get_redirected_output(path_name):
output = [] output = []
with open(path_name, 'r') as fd: with open(path_name, "r") as fd:
for line in fd: for line in fd:
# strip terminal format/color chars # strip terminal format/color chars
new_line = re.sub(r'\x1b\[.+m', '', line) new_line = re.sub(r"\x1b\[.+m", "", line)
output.append(new_line) output.append(new_line)
os.remove(path_name) os.remove(path_name)
return output return output
def attempt_extract_errors(exc_str, stdout, stderr): def attempt_extract_errors(exc_str, stdout, stderr):
errors = [l.strip() for l in stderr if l.strip().startswith('ERROR:')] errors = [line.strip() for line in stderr if line.strip().startswith("ERROR:")]
errors.extend([l.strip() for l in stdout if l.strip().startswith('ERROR:')]) errors.extend([line.strip() for line in stdout if line.strip().startswith("ERROR:")])
warnings = [l.strip() for l in stderr if l.strip().startswith('WARNING:')] warnings = [line.strip() for line in stderr if line.strip().startswith("WARNING:")]
warnings.extend([l.strip() for l in stdout if l.strip().startswith('WARNING:')]) warnings.extend([line.strip() for line in stdout if line.strip().startswith("WARNING:")])
# assume either the exception body (if present) or the last warning was the 'most' # assume either the exception body (if present) or the last warning was the "most"
# fatal. # fatal.
if exc_str.strip(): if exc_str.strip():
msg = exc_str.strip() msg = exc_str.strip()
elif errors: elif errors:
msg = errors[-1].encode('utf-8') msg = errors[-1].encode("utf-8")
else: else:
msg = 'unknown cause' msg = "unknown cause"
return { return {
'warnings': [w.encode('utf-8') for w in warnings], "warnings": [w.encode("utf-8") for w in warnings],
'errors': [e.encode('utf-8') for e in errors], "errors": [e.encode("utf-8") for e in errors],
'msg': msg, "msg": msg,
'module_stderr': ''.join(stderr), "module_stderr": "".join(stderr),
'module_stdout': ''.join(stdout) "module_stdout": "".join(stdout)
} }
def get_failure_info(exc, out_name, err_name=None, msg_format='%s'): def get_failure_info(exc, out_name, err_name=None, msg_format="{}"):
if err_name is None: if err_name is None:
stderr = [] stderr = []
else: else:
@ -580,7 +583,7 @@ def get_failure_info(exc, out_name, err_name=None, msg_format='%s'):
stdout = get_redirected_output(out_name) stdout = get_redirected_output(out_name)
reason = attempt_extract_errors(str(exc), stdout, stderr) reason = attempt_extract_errors(str(exc), stdout, stderr)
reason['msg'] = msg_format % reason['msg'] reason["msg"] = msg_format.format(reason["msg"])
return reason return reason
@ -622,25 +625,26 @@ class ContainerManager(DockerBaseClass):
self.options = dict() self.options = dict()
self.options.update(self._get_auth_options()) self.options.update(self._get_auth_options())
self.options[u'--skip-hostname-check'] = (not self.hostname_check) self.options[u"--skip-hostname-check"] = (not self.hostname_check)
if self.project_name: if self.project_name:
self.options[u'--project-name'] = self.project_name self.options[u"--project-name"] = self.project_name
if self.files: if self.files:
self.options[u'--file'] = self.files self.options[u"--file"] = self.files
if not HAS_COMPOSE: if not HAS_COMPOSE:
self.client.fail( self.client.fail(
"Unable to load docker-compose. Try `pip install docker-compose`. Error: %s" % "Unable to load docker-compose. Try `pip install docker-compose`. Error: {}".
to_native(HAS_COMPOSE_EXC) format(to_native(HAS_COMPOSE_EXC))
) )
if LooseVersion(compose_version) < LooseVersion(MINIMUM_COMPOSE_VERSION): if LooseVersion(compose_version) < LooseVersion(MINIMUM_COMPOSE_VERSION):
self.client.fail( self.client.fail(
"Found docker-compose version %s. Minimum required version is %s. " "Found docker-compose version {}. Minimum required version is {}. "
"Upgrade docker-compose to a min version of %s." % "Upgrade docker-compose to a min version of {}.".format(
(compose_version, MINIMUM_COMPOSE_VERSION, MINIMUM_COMPOSE_VERSION) compose_version, MINIMUM_COMPOSE_VERSION, MINIMUM_COMPOSE_VERSION
)
) )
if self.restarted and self.stopped: if self.restarted and self.stopped:
@ -652,8 +656,9 @@ class ContainerManager(DockerBaseClass):
if self.definition: if self.definition:
if not HAS_YAML: if not HAS_YAML:
self.client.fail( self.client.fail(
"Unable to load yaml. Try `pip install PyYAML`. Error: %s" % "Unable to load yaml. Try `pip install PyYAML`. Error: {}".format(
to_native(HAS_YAML_EXC) to_native(HAS_YAML_EXC)
)
) )
if not self.project_name: if not self.project_name:
@ -664,39 +669,39 @@ class ContainerManager(DockerBaseClass):
self.project_src = tempfile.mkdtemp(prefix="ansible") self.project_src = tempfile.mkdtemp(prefix="ansible")
compose_file = os.path.join(self.project_src, "docker-compose.yml") compose_file = os.path.join(self.project_src, "docker-compose.yml")
try: try:
self.log('writing: ') self.log("writing: ")
self.log(yaml.dump(self.definition, default_flow_style=False)) self.log(yaml.dump(self.definition, default_flow_style=False))
with open(compose_file, 'w') as f: with open(compose_file, "w") as f:
f.write(yaml.dump(self.definition, default_flow_style=False)) f.write(yaml.dump(self.definition, default_flow_style=False))
except Exception as exc: except Exception as exc:
self.client.fail("Error writing to %s - %s" % (compose_file, to_native(exc))) self.client.fail("Error writing to {} - {}".format(compose_file, to_native(exc)))
else: else:
if not self.project_src: if not self.project_src:
self.client.fail("Parameter error - project_src required.") self.client.fail("Parameter error - project_src required.")
try: try:
self.log("project_src: %s" % self.project_src) self.log("project_src: {}".format(self.project_src))
self.project = project_from_options(self.project_src, self.options) self.project = project_from_options(self.project_src, self.options)
except Exception as exc: except Exception as exc:
self.client.fail("Configuration error - %s" % to_native(exc)) self.client.fail("Configuration error - {}".format(to_native(exc)))
def exec_module(self): def exec_module(self):
result = dict() result = dict()
if self.state == 'present': if self.state == "present":
result = self.cmd_up() result = self.cmd_up()
elif self.state == 'absent': elif self.state == "absent":
result = self.cmd_down() result = self.cmd_down()
if self.definition: if self.definition:
compose_file = os.path.join(self.project_src, "docker-compose.yml") compose_file = os.path.join(self.project_src, "docker-compose.yml")
self.log("removing %s" % compose_file) self.log("removing {}".format(compose_file))
os.remove(compose_file) os.remove(compose_file)
self.log("removing %s" % self.project_src) self.log("removing {}".format(self.project_src))
os.rmdir(self.project_src) os.rmdir(self.project_src)
if not self.check_mode and not self.debug and result.get('actions'): if not self.check_mode and not self.debug and result.get("actions"):
result.pop('actions') result.pop("actions")
return result return result
@ -717,58 +722,58 @@ class ContainerManager(DockerBaseClass):
result = dict(changed=False, actions=[], services=dict()) result = dict(changed=False, actions=[], services=dict())
up_options = { up_options = {
u'--no-recreate': False, u"--no-recreate": False,
u'--build': False, u"--build": False,
u'--no-build': False, u"--no-build": False,
u'--no-deps': False, u"--no-deps": False,
u'--force-recreate': False, u"--force-recreate": False,
} }
if self.recreate == 'never': if self.recreate == "never":
up_options[u'--no-recreate'] = True up_options[u"--no-recreate"] = True
elif self.recreate == 'always': elif self.recreate == "always":
up_options[u'--force-recreate'] = True up_options[u"--force-recreate"] = True
if self.remove_orphans: if self.remove_orphans:
up_options[u'--remove-orphans'] = True up_options[u"--remove-orphans"] = True
converge = convergence_strategy_from_opts(up_options) converge = convergence_strategy_from_opts(up_options)
self.log("convergence strategy: %s" % converge) self.log("convergence strategy: {}".format(converge))
if self.pull: if self.pull:
pull_output = self.cmd_pull() pull_output = self.cmd_pull()
result['changed'] = pull_output['changed'] result["changed"] = pull_output["changed"]
result['actions'] += pull_output['actions'] result["actions"] += pull_output["actions"]
if self.build: if self.build:
build_output = self.cmd_build() build_output = self.cmd_build()
result['changed'] = build_output['changed'] result["changed"] = build_output["changed"]
result['actions'] += build_output['actions'] result["actions"] += build_output["actions"]
if self.remove_orphans: if self.remove_orphans:
containers = self.client.containers( containers = self.client.containers(
filters={ filters={
'label': [ "label": [
'{0}={1}'.format(LABEL_PROJECT, self.project.name), "{0}={1}".format(LABEL_PROJECT, self.project.name),
'{0}={1}'.format(LABEL_ONE_OFF, "False") "{0}={1}".format(LABEL_ONE_OFF, "False")
], ],
} }
) )
orphans = [] orphans = []
for container in containers: for container in containers:
service_name = container.get('Labels', {}).get(LABEL_SERVICE) service_name = container.get("Labels", {}).get(LABEL_SERVICE)
if service_name not in self.project.service_names: if service_name not in self.project.service_names:
orphans.append(service_name) orphans.append(service_name)
if orphans: if orphans:
result['changed'] = True result["changed"] = True
for service in self.project.services: for service in self.project.services:
if not service_names or service.name in service_names: if not service_names or service.name in service_names:
plan = service.convergence_plan(strategy=converge) plan = service.convergence_plan(strategy=converge)
if plan.action != 'noop': if plan.action != "noop":
result['changed'] = True result["changed"] = True
result_action = dict(service=service.name) result_action = dict(service=service.name)
result_action[plan.action] = [] result_action[plan.action] = []
for container in plan.containers: for container in plan.containers:
@ -779,15 +784,15 @@ class ContainerManager(DockerBaseClass):
short_id=container.short_id, short_id=container.short_id,
) )
) )
result['actions'].append(result_action) result["actions"].append(result_action)
if not self.check_mode and result['changed']: if not self.check_mode and result["changed"]:
out_redir_name, err_redir_name = make_redirection_tempfiles() out_redir_name, err_redir_name = make_redirection_tempfiles()
try: try:
with stdout_redirector(out_redir_name): with stdout_redirector(out_redir_name):
with stderr_redirector(err_redir_name): with stderr_redirector(err_redir_name):
do_build = build_action_from_opts(up_options) do_build = build_action_from_opts(up_options)
self.log('Setting do_build to %s' % do_build) self.log("Setting do_build to {}".format(do_build))
self.project.up( self.project.up(
service_names=service_names, service_names=service_names,
start_deps=start_deps, start_deps=start_deps,
@ -800,7 +805,7 @@ class ContainerManager(DockerBaseClass):
) )
except Exception as exc: except Exception as exc:
fail_reason = get_failure_info( fail_reason = get_failure_info(
exc, out_redir_name, err_redir_name, msg_format="Error starting project %s" exc, out_redir_name, err_redir_name, msg_format="Error starting project {}"
) )
self.client.fail(**fail_reason) self.client.fail(**fail_reason)
else: else:
@ -808,22 +813,22 @@ class ContainerManager(DockerBaseClass):
if self.stopped: if self.stopped:
stop_output = self.cmd_stop(service_names) stop_output = self.cmd_stop(service_names)
result['changed'] = stop_output['changed'] result["changed"] = stop_output["changed"]
result['actions'] += stop_output['actions'] result["actions"] += stop_output["actions"]
if self.restarted: if self.restarted:
restart_output = self.cmd_restart(service_names) restart_output = self.cmd_restart(service_names)
result['changed'] = restart_output['changed'] result["changed"] = restart_output["changed"]
result['actions'] += restart_output['actions'] result["actions"] += restart_output["actions"]
if self.scale: if self.scale:
scale_output = self.cmd_scale() scale_output = self.cmd_scale()
result['changed'] = scale_output['changed'] result["changed"] = scale_output["changed"]
result['actions'] += scale_output['actions'] result["actions"] += scale_output["actions"]
for service in self.project.services: for service in self.project.services:
service_facts = dict() service_facts = dict()
result['services'][service.name] = service_facts result["services"][service.name] = service_facts
for container in service.containers(stopped=True): for container in service.containers(stopped=True):
inspection = container.inspect() inspection = container.inspect()
# pare down the inspection data to the most useful bits # pare down the inspection data to the most useful bits
@ -834,22 +839,24 @@ class ContainerManager(DockerBaseClass):
state=dict(running=None, status=None), state=dict(running=None, status=None),
networks=dict() networks=dict()
) )
if inspection['Config'].get('Cmd', None) is not None: if inspection["Config"].get("Cmd", None) is not None:
facts['cmd'] = inspection['Config']['Cmd'] facts["cmd"] = inspection["Config"]["Cmd"]
if inspection['Config'].get('Labels', None) is not None: if inspection["Config"].get("Labels", None) is not None:
facts['labels'] = inspection['Config']['Labels'] facts["labels"] = inspection["Config"]["Labels"]
if inspection['Config'].get('Image', None) is not None: if inspection["Config"].get("Image", None) is not None:
facts['image'] = inspection['Config']['Image'] facts["image"] = inspection["Config"]["Image"]
if inspection['State'].get('Running', None) is not None: if inspection["State"].get("Running", None) is not None:
facts['state']['running'] = inspection['State']['Running'] facts["state"]["running"] = inspection["State"]["Running"]
if inspection['State'].get('Status', None) is not None: if inspection["State"].get("Status", None) is not None:
facts['state']['status'] = inspection['State']['Status'] facts["state"]["status"] = inspection["State"]["Status"]
if inspection.get('NetworkSettings' if (
) and inspection['NetworkSettings'].get('Networks'): inspection.get("NetworkSettings")
networks = inspection['NetworkSettings']['Networks'] and inspection["NetworkSettings"].get("Networks")
):
networks = inspection["NetworkSettings"]["Networks"]
for key in networks: for key in networks:
facts['networks'][key] = dict( facts["networks"][key] = dict(
aliases=[], aliases=[],
globalIPv6=None, globalIPv6=None,
globalIPv6PrefixLen=0, globalIPv6PrefixLen=0,
@ -858,22 +865,22 @@ class ContainerManager(DockerBaseClass):
links=None, links=None,
macAddress=None, macAddress=None,
) )
if networks[key].get('Aliases', None) is not None: if networks[key].get("Aliases", None) is not None:
facts['networks'][key]['aliases'] = networks[key]['Aliases'] facts["networks"][key]["aliases"] = networks[key]["Aliases"]
if networks[key].get('GlobalIPv6Address', None) is not None: if networks[key].get("GlobalIPv6Address", None) is not None:
facts['networks'][key]['globalIPv6'] = networks[key][ facts["networks"][key]["globalIPv6"] = networks[key][
'GlobalIPv6Address'] "GlobalIPv6Address"]
if networks[key].get('GlobalIPv6PrefixLen', None) is not None: if networks[key].get("GlobalIPv6PrefixLen", None) is not None:
facts['networks'][key]['globalIPv6PrefixLen'] = networks[key][ facts["networks"][key]["globalIPv6PrefixLen"] = networks[key][
'GlobalIPv6PrefixLen'] "GlobalIPv6PrefixLen"]
if networks[key].get('IPAddress', None) is not None: if networks[key].get("IPAddress", None) is not None:
facts['networks'][key]['IPAddress'] = networks[key]['IPAddress'] facts["networks"][key]["IPAddress"] = networks[key]["IPAddress"]
if networks[key].get('IPPrefixLen', None) is not None: if networks[key].get("IPPrefixLen", None) is not None:
facts['networks'][key]['IPPrefixLen'] = networks[key]['IPPrefixLen'] facts["networks"][key]["IPPrefixLen"] = networks[key]["IPPrefixLen"]
if networks[key].get('Links', None) is not None: if networks[key].get("Links", None) is not None:
facts['networks'][key]['links'] = networks[key]['Links'] facts["networks"][key]["links"] = networks[key]["Links"]
if networks[key].get('MacAddress', None) is not None: if networks[key].get("MacAddress", None) is not None:
facts['networks'][key]['macAddress'] = networks[key]['MacAddress'] facts["networks"][key]["macAddress"] = networks[key]["MacAddress"]
service_facts[container.name] = facts service_facts[container.name] = facts
@ -887,20 +894,22 @@ class ContainerManager(DockerBaseClass):
if not self.check_mode: if not self.check_mode:
for service in self.project.get_services(self.services, include_deps=False): for service in self.project.get_services(self.services, include_deps=False):
if 'image' not in service.options: if "image" not in service.options:
continue continue
self.log('Pulling image for service %s' % service.name) self.log("Pulling image for service {}".format(service.name))
# store the existing image ID # store the existing image ID
old_image_id = '' old_image_id = ""
try: try:
image = service.image() image = service.image()
if image and image.get('Id'): if image and image.get("Id"):
old_image_id = image['Id'] old_image_id = image["Id"]
except NoSuchImageError: except NoSuchImageError:
pass pass
except Exception as exc: except Exception as exc:
self.client.fail("Error: service image lookup failed - %s" % to_native(exc)) self.client.fail(
"Error: service image lookup failed - {}".format(to_native(exc))
)
out_redir_name, err_redir_name = make_redirection_tempfiles() out_redir_name, err_redir_name = make_redirection_tempfiles()
# pull the image # pull the image
@ -913,27 +922,29 @@ class ContainerManager(DockerBaseClass):
exc, exc,
out_redir_name, out_redir_name,
err_redir_name, err_redir_name,
msg_format="Error: pull failed with %s" msg_format="Error: pull failed with {}"
) )
self.client.fail(**fail_reason) self.client.fail(**fail_reason)
else: else:
cleanup_redirection_tempfiles(out_redir_name, err_redir_name) cleanup_redirection_tempfiles(out_redir_name, err_redir_name)
# store the new image ID # store the new image ID
new_image_id = '' new_image_id = ""
try: try:
image = service.image() image = service.image()
if image and image.get('Id'): if image and image.get("Id"):
new_image_id = image['Id'] new_image_id = image["Id"]
except NoSuchImageError as exc: except NoSuchImageError as exc:
self.client.fail( self.client.fail(
"Error: service image lookup failed after pull - %s" % to_native(exc) "Error: service image lookup failed after pull - {}".format(
to_native(exc)
)
) )
if new_image_id != old_image_id: if new_image_id != old_image_id:
# if a new image was pulled # if a new image was pulled
result['changed'] = True result["changed"] = True
result['actions'].append( result["actions"].append(
dict( dict(
service=service.name, service=service.name,
pulled_image=dict(name=service.image_name, id=new_image_id) pulled_image=dict(name=service.image_name, id=new_image_id)
@ -946,18 +957,18 @@ class ContainerManager(DockerBaseClass):
if not self.check_mode: if not self.check_mode:
for service in self.project.get_services(self.services, include_deps=False): for service in self.project.get_services(self.services, include_deps=False):
if service.can_be_built(): if service.can_be_built():
self.log('Building image for service %s' % service.name) self.log("Building image for service {}".format(service.name))
# store the existing image ID # store the existing image ID
old_image_id = '' old_image_id = ""
try: try:
image = service.image() image = service.image()
if image and image.get('Id'): if image and image.get("Id"):
old_image_id = image['Id'] old_image_id = image["Id"]
except NoSuchImageError: except NoSuchImageError:
pass pass
except Exception as exc: except Exception as exc:
self.client.fail( self.client.fail(
"Error: service image lookup failed - %s" % to_native(exc) "Error: service image lookup failed - {}".format(to_native(exc))
) )
out_redir_name, err_redir_name = make_redirection_tempfiles() out_redir_name, err_redir_name = make_redirection_tempfiles()
@ -971,7 +982,7 @@ class ContainerManager(DockerBaseClass):
exc, exc,
out_redir_name, out_redir_name,
err_redir_name, err_redir_name,
msg_format="Error: build failed with %s" msg_format="Error: build failed with {}"
) )
self.client.fail(**fail_reason) self.client.fail(**fail_reason)
else: else:
@ -979,8 +990,8 @@ class ContainerManager(DockerBaseClass):
if new_image_id not in old_image_id: if new_image_id not in old_image_id:
# if a new image was built # if a new image was built
result['changed'] = True result["changed"] = True
result['actions'].append( result["actions"].append(
dict( dict(
service=service.name, service=service.name,
built_image=dict(name=service.image_name, id=new_image_id) built_image=dict(name=service.image_name, id=new_image_id)
@ -993,12 +1004,12 @@ class ContainerManager(DockerBaseClass):
for service in self.project.services: for service in self.project.services:
containers = service.containers(stopped=True) containers = service.containers(stopped=True)
if len(containers): if len(containers):
result['changed'] = True result["changed"] = True
result['actions'].append( result["actions"].append(
dict(service=service.name, deleted=[container.name for container in containers]) dict(service=service.name, deleted=[container.name for container in containers])
) )
if not self.check_mode and result['changed']: if not self.check_mode and result["changed"]:
image_type = image_type_from_opt('--rmi', self.remove_images) image_type = image_type_from_opt("--rmi", self.remove_images)
out_redir_name, err_redir_name = make_redirection_tempfiles() out_redir_name, err_redir_name = make_redirection_tempfiles()
try: try:
with stdout_redirector(out_redir_name): with stdout_redirector(out_redir_name):
@ -1006,7 +1017,7 @@ class ContainerManager(DockerBaseClass):
self.project.down(image_type, self.remove_volumes, self.remove_orphans) self.project.down(image_type, self.remove_volumes, self.remove_orphans)
except Exception as exc: except Exception as exc:
fail_reason = get_failure_info( fail_reason = get_failure_info(
exc, out_redir_name, err_redir_name, msg_format="Error stopping project - %s" exc, out_redir_name, err_redir_name, msg_format="Error stopping project - {}"
) )
self.client.fail(**fail_reason) self.client.fail(**fail_reason)
else: else:
@ -1019,12 +1030,12 @@ class ContainerManager(DockerBaseClass):
if not service_names or service.name in service_names: if not service_names or service.name in service_names:
service_res = dict(service=service.name, stop=[]) service_res = dict(service=service.name, stop=[])
for container in service.containers(stopped=False): for container in service.containers(stopped=False):
result['changed'] = True result["changed"] = True
service_res['stop'].append( service_res["stop"].append(
dict(id=container.id, name=container.name, short_id=container.short_id) dict(id=container.id, name=container.name, short_id=container.short_id)
) )
result['actions'].append(service_res) result["actions"].append(service_res)
if not self.check_mode and result['changed']: if not self.check_mode and result["changed"]:
out_redir_name, err_redir_name = make_redirection_tempfiles() out_redir_name, err_redir_name = make_redirection_tempfiles()
try: try:
with stdout_redirector(out_redir_name): with stdout_redirector(out_redir_name):
@ -1032,7 +1043,7 @@ class ContainerManager(DockerBaseClass):
self.project.stop(service_names=service_names, timeout=self.timeout) self.project.stop(service_names=service_names, timeout=self.timeout)
except Exception as exc: except Exception as exc:
fail_reason = get_failure_info( fail_reason = get_failure_info(
exc, out_redir_name, err_redir_name, msg_format="Error stopping project %s" exc, out_redir_name, err_redir_name, msg_format="Error stopping project {}"
) )
self.client.fail(**fail_reason) self.client.fail(**fail_reason)
else: else:
@ -1046,13 +1057,13 @@ class ContainerManager(DockerBaseClass):
if not service_names or service.name in service_names: if not service_names or service.name in service_names:
service_res = dict(service=service.name, restart=[]) service_res = dict(service=service.name, restart=[])
for container in service.containers(stopped=True): for container in service.containers(stopped=True):
result['changed'] = True result["changed"] = True
service_res['restart'].append( service_res["restart"].append(
dict(id=container.id, name=container.name, short_id=container.short_id) dict(id=container.id, name=container.name, short_id=container.short_id)
) )
result['actions'].append(service_res) result["actions"].append(service_res)
if not self.check_mode and result['changed']: if not self.check_mode and result["changed"]:
out_redir_name, err_redir_name = make_redirection_tempfiles() out_redir_name, err_redir_name = make_redirection_tempfiles()
try: try:
with stdout_redirector(out_redir_name): with stdout_redirector(out_redir_name):
@ -1060,7 +1071,7 @@ class ContainerManager(DockerBaseClass):
self.project.restart(service_names=service_names, timeout=self.timeout) self.project.restart(service_names=service_names, timeout=self.timeout)
except Exception as exc: except Exception as exc:
fail_reason = get_failure_info( fail_reason = get_failure_info(
exc, out_redir_name, err_redir_name, msg_format="Error restarting project %s" exc, out_redir_name, err_redir_name, msg_format="Error restarting project {}"
) )
self.client.fail(**fail_reason) self.client.fail(**fail_reason)
else: else:
@ -1075,8 +1086,8 @@ class ContainerManager(DockerBaseClass):
containers = service.containers(stopped=True) containers = service.containers(stopped=True)
scale = self.parse_scale(service.name) scale = self.parse_scale(service.name)
if len(containers) != scale: if len(containers) != scale:
result['changed'] = True result["changed"] = True
service_res['scale'] = scale - len(containers) service_res["scale"] = scale - len(containers)
if not self.check_mode: if not self.check_mode:
out_redir_name, err_redir_name = make_redirection_tempfiles() out_redir_name, err_redir_name = make_redirection_tempfiles()
try: try:
@ -1088,12 +1099,12 @@ class ContainerManager(DockerBaseClass):
exc, exc,
out_redir_name, out_redir_name,
err_redir_name, err_redir_name,
msg_format="Error scaling {0} - %s".format(service.name) msg_format="Error scaling {}".format(service.name) + " - {}"
) )
self.client.fail(**fail_reason) self.client.fail(**fail_reason)
else: else:
cleanup_redirection_tempfiles(out_redir_name, err_redir_name) cleanup_redirection_tempfiles(out_redir_name, err_redir_name)
result['actions'].append(service_res) result["actions"].append(service_res)
return result return result
def parse_scale(self, service_name): def parse_scale(self, service_name):
@ -1101,42 +1112,42 @@ class ContainerManager(DockerBaseClass):
return int(self.scale[service_name]) return int(self.scale[service_name])
except ValueError: except ValueError:
self.client.fail( self.client.fail(
"Error scaling %s - expected int, got %s", service_name, "Error scaling {} - expected int, got {}", service_name,
to_native(type(self.scale[service_name])) to_native(type(self.scale[service_name]))
) )
def main(): def main():
argument_spec = dict( argument_spec = dict(
project_src=dict(type='path'), project_src=dict(type="path"),
project_name=dict(type='str',), project_name=dict(type="str",),
files=dict(type='list', elements='path'), files=dict(type="list", elements="path"),
state=dict(type='str', default='present', choices=['absent', 'present']), state=dict(type="str", default="present", choices=["absent", "present"]),
definition=dict(type='dict'), definition=dict(type="dict"),
hostname_check=dict(type='bool', default=False), hostname_check=dict(type="bool", default=False),
recreate=dict(type='str', default='smart', choices=['always', 'never', 'smart']), recreate=dict(type="str", default="smart", choices=["always", "never", "smart"]),
build=dict(type='bool', default=False), build=dict(type="bool", default=False),
remove_images=dict(type='str', choices=['all', 'local']), remove_images=dict(type="str", choices=["all", "local"]),
remove_volumes=dict(type='bool', default=False), remove_volumes=dict(type="bool", default=False),
remove_orphans=dict(type='bool', default=False), remove_orphans=dict(type="bool", default=False),
stopped=dict(type='bool', default=False), stopped=dict(type="bool", default=False),
restarted=dict(type='bool', default=False), restarted=dict(type="bool", default=False),
scale=dict(type='dict'), scale=dict(type="dict"),
services=dict(type='list', elements='str'), services=dict(type="list", elements="str"),
dependencies=dict(type='bool', default=True), dependencies=dict(type="bool", default=True),
pull=dict(type='bool', default=False), pull=dict(type="bool", default=False),
nocache=dict(type='bool', default=False), nocache=dict(type="bool", default=False),
debug=dict(type='bool', default=False), debug=dict(type="bool", default=False),
timeout=dict(type='int', default=DEFAULT_TIMEOUT) timeout=dict(type="int", default=DEFAULT_TIMEOUT)
) )
mutually_exclusive = [('definition', 'project_src'), ('definition', 'files')] mutually_exclusive = [("definition", "project_src"), ("definition", "files")]
client = AnsibleDockerClient( client = AnsibleDockerClient(
argument_spec=argument_spec, argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive, mutually_exclusive=mutually_exclusive,
supports_check_mode=True, supports_check_mode=True,
min_docker_api_version='1.20', min_docker_api_version="1.20",
) )
try: try:
@ -1144,16 +1155,16 @@ def main():
client.module.exit_json(**result) client.module.exit_json(**result)
except DockerException as e: except DockerException as e:
client.fail( client.fail(
'An unexpected docker error occurred: {0}'.format(to_native(e)), "An unexpected docker error occurred: {0}".format(to_native(e)),
exception=traceback.format_exc() exception=traceback.format_exc()
) )
except RequestException as e: except RequestException as e:
client.fail( client.fail(
'An unexpected requests error occurred when docker-py tried to talk to the docker daemon: {0}' "An unexpected requests error occurred when docker-py"
.format(to_native(e)), "tried to talk to the docker daemon: {0}".format(to_native(e)),
exception=traceback.format_exc() exception=traceback.format_exc()
) )
if __name__ == '__main__': if __name__ == "__main__":
main() main()