mirror of
https://github.com/ansible-collections/community.docker.git
synced 2025-12-16 20:08:41 +00:00
Python code modernization, 4/n (#1162)
* Address attribute-defined-outside-init. * Address broad-exception-raised. * Address broad-exception-caught. * Address consider-iterating-dictionary. * Address consider-using-dict-comprehension. * Address consider-using-f-string. * Address consider-using-in. * Address consider-using-max-builtin. * Address some consider-using-with. * Address invalid-name. * Address keyword-arg-before-vararg. * Address line-too-long. * Address no-else-continue. * Address no-else-raise. * Address no-else-return. * Remove broken dead code. * Make consider-using-f-string changes compatible with older Python versions. * Python 3.11 and earlier apparently do not like multi-line f-strings.
This commit is contained in:
parent
33c8a49191
commit
cad22de628
14
.pylintrc
14
.pylintrc
@ -381,23 +381,9 @@ disable=raw-checker-failed,
|
|||||||
# To clean up:
|
# To clean up:
|
||||||
abstract-method,
|
abstract-method,
|
||||||
arguments-differ,
|
arguments-differ,
|
||||||
attribute-defined-outside-init,
|
|
||||||
broad-exception-caught,
|
|
||||||
broad-exception-raised,
|
|
||||||
consider-iterating-dictionary,
|
|
||||||
consider-using-dict-comprehension,
|
|
||||||
consider-using-f-string,
|
|
||||||
consider-using-in,
|
|
||||||
consider-using-max-builtin,
|
|
||||||
consider-using-with,
|
consider-using-with,
|
||||||
fixme,
|
fixme,
|
||||||
import-error, # TODO figure out why pylint cannot find the module
|
import-error, # TODO figure out why pylint cannot find the module
|
||||||
invalid-name,
|
|
||||||
keyword-arg-before-vararg,
|
|
||||||
line-too-long,
|
|
||||||
no-else-continue,
|
|
||||||
no-else-raise,
|
|
||||||
no-else-return,
|
|
||||||
no-member,
|
no-member,
|
||||||
no-name-in-module, # TODO figure out why pylint cannot find the module
|
no-name-in-module, # TODO figure out why pylint cannot find the module
|
||||||
not-an-iterable, # TODO: needs better typing info
|
not-an-iterable, # TODO: needs better typing info
|
||||||
|
|||||||
@ -155,6 +155,8 @@ class Connection(ConnectionBase):
|
|||||||
self._docker_args = []
|
self._docker_args = []
|
||||||
self._container_user_cache = {}
|
self._container_user_cache = {}
|
||||||
self._version = None
|
self._version = None
|
||||||
|
self.remote_user = None
|
||||||
|
self.timeout = None
|
||||||
|
|
||||||
# Windows uses Powershell modules
|
# Windows uses Powershell modules
|
||||||
if getattr(self._shell, "_IS_WINDOWS", False):
|
if getattr(self._shell, "_IS_WINDOWS", False):
|
||||||
@ -180,9 +182,9 @@ class Connection(ConnectionBase):
|
|||||||
old_version_subcommand = ["version"]
|
old_version_subcommand = ["version"]
|
||||||
|
|
||||||
old_docker_cmd = [self.docker_cmd] + cmd_args + old_version_subcommand
|
old_docker_cmd = [self.docker_cmd] + cmd_args + old_version_subcommand
|
||||||
p = subprocess.Popen(
|
with subprocess.Popen(
|
||||||
old_docker_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
old_docker_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||||
)
|
) as p:
|
||||||
cmd_output, err = p.communicate()
|
cmd_output, err = p.communicate()
|
||||||
|
|
||||||
return old_docker_cmd, to_native(cmd_output), err, p.returncode
|
return old_docker_cmd, to_native(cmd_output), err, p.returncode
|
||||||
@ -194,9 +196,9 @@ class Connection(ConnectionBase):
|
|||||||
new_version_subcommand = ["version", "--format", "'{{.Server.Version}}'"]
|
new_version_subcommand = ["version", "--format", "'{{.Server.Version}}'"]
|
||||||
|
|
||||||
new_docker_cmd = [self.docker_cmd] + cmd_args + new_version_subcommand
|
new_docker_cmd = [self.docker_cmd] + cmd_args + new_version_subcommand
|
||||||
p = subprocess.Popen(
|
with subprocess.Popen(
|
||||||
new_docker_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
new_docker_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||||
)
|
) as p:
|
||||||
cmd_output, err = p.communicate()
|
cmd_output, err = p.communicate()
|
||||||
return new_docker_cmd, to_native(cmd_output), err, p.returncode
|
return new_docker_cmd, to_native(cmd_output), err, p.returncode
|
||||||
|
|
||||||
@ -221,12 +223,11 @@ class Connection(ConnectionBase):
|
|||||||
container = self.get_option("remote_addr")
|
container = self.get_option("remote_addr")
|
||||||
if container in self._container_user_cache:
|
if container in self._container_user_cache:
|
||||||
return self._container_user_cache[container]
|
return self._container_user_cache[container]
|
||||||
p = subprocess.Popen(
|
with subprocess.Popen(
|
||||||
[self.docker_cmd, "inspect", "--format", "{{.Config.User}}", container],
|
[self.docker_cmd, "inspect", "--format", "{{.Config.User}}", container],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
)
|
) as p:
|
||||||
|
|
||||||
out, err = p.communicate()
|
out, err = p.communicate()
|
||||||
out = to_text(out, errors="surrogate_or_strict")
|
out = to_text(out, errors="surrogate_or_strict")
|
||||||
|
|
||||||
@ -348,7 +349,6 @@ class Connection(ConnectionBase):
|
|||||||
) >= LooseVersion("1.7"):
|
) >= LooseVersion("1.7"):
|
||||||
# Support for specifying the exec user was added in docker 1.7
|
# Support for specifying the exec user was added in docker 1.7
|
||||||
return self.remote_user
|
return self.remote_user
|
||||||
else:
|
|
||||||
self.remote_user = None
|
self.remote_user = None
|
||||||
actual_user = self._get_docker_remote_user()
|
actual_user = self._get_docker_remote_user()
|
||||||
if actual_user != self.get_option("remote_user"):
|
if actual_user != self.get_option("remote_user"):
|
||||||
@ -356,12 +356,11 @@ class Connection(ConnectionBase):
|
|||||||
f'docker {self.docker_version} does not support remote_user, using container default: {actual_user or "?"}'
|
f'docker {self.docker_version} does not support remote_user, using container default: {actual_user or "?"}'
|
||||||
)
|
)
|
||||||
return actual_user
|
return actual_user
|
||||||
elif self._display.verbosity > 2:
|
if self._display.verbosity > 2:
|
||||||
# Since we are not setting the actual_user, look it up so we have it for logging later
|
# Since we are not setting the actual_user, look it up so we have it for logging later
|
||||||
# Only do this if display verbosity is high enough that we'll need the value
|
# Only do this if display verbosity is high enough that we'll need the value
|
||||||
# This saves overhead from calling into docker when we do not need to.
|
# This saves overhead from calling into docker when we do not need to.
|
||||||
return self._get_docker_remote_user()
|
return self._get_docker_remote_user()
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _connect(self, port=None):
|
def _connect(self, port=None):
|
||||||
@ -390,12 +389,12 @@ class Connection(ConnectionBase):
|
|||||||
|
|
||||||
local_cmd = [to_bytes(i, errors="surrogate_or_strict") for i in local_cmd]
|
local_cmd = [to_bytes(i, errors="surrogate_or_strict") for i in local_cmd]
|
||||||
|
|
||||||
p = subprocess.Popen(
|
with subprocess.Popen(
|
||||||
local_cmd,
|
local_cmd,
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
)
|
) as p:
|
||||||
display.debug("done running command with Popen()")
|
display.debug("done running command with Popen()")
|
||||||
|
|
||||||
if self.become and self.become.expect_prompt() and sudoable:
|
if self.become and self.become.expect_prompt() and sudoable:
|
||||||
@ -486,7 +485,6 @@ class Connection(ConnectionBase):
|
|||||||
import ntpath
|
import ntpath
|
||||||
|
|
||||||
return ntpath.normpath(remote_path)
|
return ntpath.normpath(remote_path)
|
||||||
else:
|
|
||||||
if not remote_path.startswith(os.path.sep):
|
if not remote_path.startswith(os.path.sep):
|
||||||
remote_path = os.path.join(os.path.sep, remote_path)
|
remote_path = os.path.join(os.path.sep, remote_path)
|
||||||
return os.path.normpath(remote_path)
|
return os.path.normpath(remote_path)
|
||||||
@ -557,9 +555,9 @@ class Connection(ConnectionBase):
|
|||||||
]
|
]
|
||||||
args = [to_bytes(i, errors="surrogate_or_strict") for i in args]
|
args = [to_bytes(i, errors="surrogate_or_strict") for i in args]
|
||||||
|
|
||||||
p = subprocess.Popen(
|
with subprocess.Popen(
|
||||||
args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||||
)
|
) as p:
|
||||||
p.communicate()
|
p.communicate()
|
||||||
|
|
||||||
if getattr(self._shell, "_IS_WINDOWS", False):
|
if getattr(self._shell, "_IS_WINDOWS", False):
|
||||||
@ -573,14 +571,18 @@ class Connection(ConnectionBase):
|
|||||||
# Older docker does not have native support for fetching files command `cp`
|
# Older docker does not have native support for fetching files command `cp`
|
||||||
# If `cp` fails, try to use `dd` instead
|
# If `cp` fails, try to use `dd` instead
|
||||||
args = self._build_exec_cmd(
|
args = self._build_exec_cmd(
|
||||||
[self._play_context.executable, "-c", f"dd if={in_path} bs={BUFSIZE}"]
|
[
|
||||||
|
self._play_context.executable,
|
||||||
|
"-c",
|
||||||
|
f"dd if={in_path} bs={BUFSIZE}",
|
||||||
|
]
|
||||||
)
|
)
|
||||||
args = [to_bytes(i, errors="surrogate_or_strict") for i in args]
|
args = [to_bytes(i, errors="surrogate_or_strict") for i in args]
|
||||||
with open(
|
with open(
|
||||||
to_bytes(actual_out_path, errors="surrogate_or_strict"), "wb"
|
to_bytes(actual_out_path, errors="surrogate_or_strict"), "wb"
|
||||||
) as out_file:
|
) as out_file:
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(
|
pp = subprocess.Popen(
|
||||||
args,
|
args,
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
stdout=out_file,
|
stdout=out_file,
|
||||||
@ -590,9 +592,9 @@ class Connection(ConnectionBase):
|
|||||||
raise AnsibleError(
|
raise AnsibleError(
|
||||||
"docker connection requires dd command in the container to put files"
|
"docker connection requires dd command in the container to put files"
|
||||||
)
|
)
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = pp.communicate()
|
||||||
|
|
||||||
if p.returncode != 0:
|
if pp.returncode != 0:
|
||||||
raise AnsibleError(
|
raise AnsibleError(
|
||||||
f"failed to fetch file {in_path} to {out_path}:\n{stdout}\n{stderr}"
|
f"failed to fetch file {in_path} to {out_path}:\n{stdout}\n{stderr}"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -159,7 +159,6 @@ class Connection(ConnectionBase):
|
|||||||
raise AnsibleConnectionFailure(
|
raise AnsibleConnectionFailure(
|
||||||
f'Could not find container "{remote_addr}" or resource in it ({e})'
|
f'Could not find container "{remote_addr}" or resource in it ({e})'
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
raise AnsibleConnectionFailure(
|
raise AnsibleConnectionFailure(
|
||||||
f'Could not find container "{remote_addr}" ({e})'
|
f'Could not find container "{remote_addr}" ({e})'
|
||||||
)
|
)
|
||||||
@ -370,7 +369,6 @@ class Connection(ConnectionBase):
|
|||||||
import ntpath
|
import ntpath
|
||||||
|
|
||||||
return ntpath.normpath(remote_path)
|
return ntpath.normpath(remote_path)
|
||||||
else:
|
|
||||||
if not remote_path.startswith(os.path.sep):
|
if not remote_path.startswith(os.path.sep):
|
||||||
remote_path = os.path.join(os.path.sep, remote_path)
|
remote_path = os.path.join(os.path.sep, remote_path)
|
||||||
return os.path.normpath(remote_path)
|
return os.path.normpath(remote_path)
|
||||||
|
|||||||
@ -66,6 +66,7 @@ class Connection(ConnectionBase):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.cwd = None
|
self.cwd = None
|
||||||
|
self._nsenter_pid = None
|
||||||
|
|
||||||
def _connect(self):
|
def _connect(self):
|
||||||
self._nsenter_pid = self.get_option("nsenter_pid")
|
self._nsenter_pid = self.get_option("nsenter_pid")
|
||||||
@ -133,7 +134,7 @@ class Connection(ConnectionBase):
|
|||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
display.debug(f"Unable to open pty: {e}")
|
display.debug(f"Unable to open pty: {e}")
|
||||||
|
|
||||||
p = subprocess.Popen(
|
with subprocess.Popen(
|
||||||
cmd,
|
cmd,
|
||||||
shell=isinstance(cmd, (str, bytes)),
|
shell=isinstance(cmd, (str, bytes)),
|
||||||
executable=executable if isinstance(cmd, (str, bytes)) else None,
|
executable=executable if isinstance(cmd, (str, bytes)) else None,
|
||||||
@ -141,8 +142,7 @@ class Connection(ConnectionBase):
|
|||||||
stdin=stdin,
|
stdin=stdin,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
)
|
) as p:
|
||||||
|
|
||||||
# if we created a master, we can close the other half of the pty now, otherwise master is stdin
|
# if we created a master, we can close the other half of the pty now, otherwise master is stdin
|
||||||
if master is not None:
|
if master is not None:
|
||||||
os.close(stdin)
|
os.close(stdin)
|
||||||
|
|||||||
@ -125,16 +125,16 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
|
|
||||||
NAME = "community.docker.docker_machine"
|
NAME = "community.docker.docker_machine"
|
||||||
|
|
||||||
DOCKER_MACHINE_PATH = None
|
docker_machine_path = None
|
||||||
|
|
||||||
def _run_command(self, args):
|
def _run_command(self, args):
|
||||||
if not self.DOCKER_MACHINE_PATH:
|
if not self.docker_machine_path:
|
||||||
try:
|
try:
|
||||||
self.DOCKER_MACHINE_PATH = get_bin_path("docker-machine")
|
self.docker_machine_path = get_bin_path("docker-machine")
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise AnsibleError(to_native(e))
|
raise AnsibleError(to_native(e))
|
||||||
|
|
||||||
command = [self.DOCKER_MACHINE_PATH]
|
command = [self.docker_machine_path]
|
||||||
command.extend(args)
|
command.extend(args)
|
||||||
display.debug(f"Executing command {command}")
|
display.debug(f"Executing command {command}")
|
||||||
try:
|
try:
|
||||||
@ -217,11 +217,11 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
if daemon_env == "require":
|
if daemon_env == "require":
|
||||||
display.warning(f"{warning_prefix}: host will be skipped")
|
display.warning(f"{warning_prefix}: host will be skipped")
|
||||||
return True
|
return True
|
||||||
else: # 'optional', 'optional-silently'
|
|
||||||
if daemon_env == "optional":
|
if daemon_env == "optional":
|
||||||
display.warning(
|
display.warning(
|
||||||
f"{warning_prefix}: host will lack dm_DOCKER_xxx variables"
|
f"{warning_prefix}: host will lack dm_DOCKER_xxx variables"
|
||||||
)
|
)
|
||||||
|
# daemon_env is 'optional-silently'
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _populate(self):
|
def _populate(self):
|
||||||
|
|||||||
@ -199,7 +199,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
|||||||
)
|
)
|
||||||
update_tls_hostname(raw_params)
|
update_tls_hostname(raw_params)
|
||||||
connect_params = get_connect_params(raw_params, fail_function=self._fail)
|
connect_params = get_connect_params(raw_params, fail_function=self._fail)
|
||||||
self.client = docker.DockerClient(**connect_params)
|
client = docker.DockerClient(**connect_params)
|
||||||
self.inventory.add_group("all")
|
self.inventory.add_group("all")
|
||||||
self.inventory.add_group("manager")
|
self.inventory.add_group("manager")
|
||||||
self.inventory.add_group("worker")
|
self.inventory.add_group("worker")
|
||||||
@ -217,9 +217,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
|||||||
host_uri_port = "2375"
|
host_uri_port = "2375"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.nodes = self.client.nodes.list()
|
nodes = client.nodes.list()
|
||||||
for node in self.nodes:
|
for node in nodes:
|
||||||
node_attrs = self.client.nodes.get(node.id).attrs
|
node_attrs = client.nodes.get(node.id).attrs
|
||||||
unsafe_node_attrs = make_unsafe(node_attrs)
|
unsafe_node_attrs = make_unsafe(node_attrs)
|
||||||
if not filter_host(
|
if not filter_host(
|
||||||
self, unsafe_node_attrs["ID"], unsafe_node_attrs, filters
|
self, unsafe_node_attrs["ID"], unsafe_node_attrs, filters
|
||||||
|
|||||||
@ -70,14 +70,16 @@ except ImportError:
|
|||||||
self.connection = self
|
self.connection = self
|
||||||
self.connectionpool = self
|
self.connectionpool = self
|
||||||
|
|
||||||
self.RecentlyUsedContainer = object()
|
self.RecentlyUsedContainer = object() # pylint: disable=invalid-name
|
||||||
self.PoolManager = object()
|
self.PoolManager = object() # pylint: disable=invalid-name
|
||||||
self.match_hostname = object()
|
self.match_hostname = object()
|
||||||
self.HTTPConnectionPool = _HTTPConnectionPool
|
self.HTTPConnectionPool = ( # pylint: disable=invalid-name
|
||||||
|
_HTTPConnectionPool
|
||||||
|
)
|
||||||
|
|
||||||
class FakeURLLIB3Connection:
|
class FakeURLLIB3Connection:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.HTTPConnection = _HTTPConnection
|
self.HTTPConnection = _HTTPConnection # pylint: disable=invalid-name
|
||||||
|
|
||||||
urllib3 = FakeURLLIB3()
|
urllib3 = FakeURLLIB3()
|
||||||
urllib3_connection = FakeURLLIB3Connection()
|
urllib3_connection = FakeURLLIB3Connection()
|
||||||
|
|||||||
@ -47,7 +47,7 @@ from ..transport.sshconn import PARAMIKO_IMPORT_ERROR, SSHHTTPAdapter
|
|||||||
from ..transport.ssladapter import SSLHTTPAdapter
|
from ..transport.ssladapter import SSLHTTPAdapter
|
||||||
from ..transport.unixconn import UnixHTTPAdapter
|
from ..transport.unixconn import UnixHTTPAdapter
|
||||||
from ..utils import config, json_stream, utils
|
from ..utils import config, json_stream, utils
|
||||||
from ..utils.decorators import check_resource, update_headers
|
from ..utils.decorators import update_headers
|
||||||
from ..utils.proxy import ProxyConfig
|
from ..utils.proxy import ProxyConfig
|
||||||
from ..utils.socket import consume_socket_output, demux_adaptor, frames_iter
|
from ..utils.socket import consume_socket_output, demux_adaptor, frames_iter
|
||||||
from .daemon import DaemonApiMixin
|
from .daemon import DaemonApiMixin
|
||||||
@ -278,7 +278,6 @@ class APIClient(_Session, DaemonApiMixin):
|
|||||||
|
|
||||||
if kwargs.get("versioned_api", True):
|
if kwargs.get("versioned_api", True):
|
||||||
return f"{self.base_url}/v{self._version}{pathfmt.format(*args)}"
|
return f"{self.base_url}/v{self._version}{pathfmt.format(*args)}"
|
||||||
else:
|
|
||||||
return f"{self.base_url}{pathfmt.format(*args)}"
|
return f"{self.base_url}{pathfmt.format(*args)}"
|
||||||
|
|
||||||
def _raise_for_status(self, response):
|
def _raise_for_status(self, response):
|
||||||
@ -427,7 +426,6 @@ class APIClient(_Session, DaemonApiMixin):
|
|||||||
|
|
||||||
if stream:
|
if stream:
|
||||||
return gen
|
return gen
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
# Wait for all the frames, concatenate them, and return the result
|
# Wait for all the frames, concatenate them, and return the result
|
||||||
return consume_socket_output(gen, demux=demux)
|
return consume_socket_output(gen, demux=demux)
|
||||||
@ -462,14 +460,6 @@ class APIClient(_Session, DaemonApiMixin):
|
|||||||
|
|
||||||
s.settimeout(None)
|
s.settimeout(None)
|
||||||
|
|
||||||
@check_resource("container")
|
|
||||||
def _check_is_tty(self, container):
|
|
||||||
cont = self.inspect_container(container)
|
|
||||||
return cont["Config"]["Tty"]
|
|
||||||
|
|
||||||
def _get_result(self, container, stream, res):
|
|
||||||
return self._get_result_tty(stream, res, self._check_is_tty(container))
|
|
||||||
|
|
||||||
def _get_result_tty(self, stream, res, is_tty):
|
def _get_result_tty(self, stream, res, is_tty):
|
||||||
# We should also use raw streaming (without keep-alive)
|
# We should also use raw streaming (without keep-alive)
|
||||||
# if we are dealing with a tty-enabled container.
|
# if we are dealing with a tty-enabled container.
|
||||||
@ -484,7 +474,6 @@ class APIClient(_Session, DaemonApiMixin):
|
|||||||
sep = b""
|
sep = b""
|
||||||
if stream:
|
if stream:
|
||||||
return self._multiplexed_response_stream_helper(res)
|
return self._multiplexed_response_stream_helper(res)
|
||||||
else:
|
|
||||||
return sep.join(list(self._multiplexed_buffer_helper(res)))
|
return sep.join(list(self._multiplexed_buffer_helper(res)))
|
||||||
|
|
||||||
def _unmount(self, *args):
|
def _unmount(self, *args):
|
||||||
@ -497,7 +486,6 @@ class APIClient(_Session, DaemonApiMixin):
|
|||||||
except _InvalidSchema as e:
|
except _InvalidSchema as e:
|
||||||
if self._custom_adapter:
|
if self._custom_adapter:
|
||||||
return self._custom_adapter
|
return self._custom_adapter
|
||||||
else:
|
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@ -368,7 +368,7 @@ def _load_legacy_config(config_file):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
log.debug(e)
|
log.debug(e)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ def get_current_context_name_with_source():
|
|||||||
json.load(f).get("currentContext", "default"),
|
json.load(f).get("currentContext", "default"),
|
||||||
f"configuration file {docker_cfg_path}",
|
f"configuration file {docker_cfg_path}",
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception: # pylint: disable=broad-exception-caught
|
||||||
pass
|
pass
|
||||||
return "default", "fallback value"
|
return "default", "fallback value"
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ def write_context_name_to_docker_config(name=None):
|
|||||||
try:
|
try:
|
||||||
with open(docker_cfg_path, "rt", encoding="utf-8") as f:
|
with open(docker_cfg_path, "rt", encoding="utf-8") as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
except Exception as e:
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
return e
|
return e
|
||||||
current_context = config.get("currentContext", None)
|
current_context = config.get("currentContext", None)
|
||||||
if current_context and not name:
|
if current_context and not name:
|
||||||
@ -68,7 +68,7 @@ def write_context_name_to_docker_config(name=None):
|
|||||||
try:
|
try:
|
||||||
with open(docker_cfg_path, "wt", encoding="utf-8") as f:
|
with open(docker_cfg_path, "wt", encoding="utf-8") as f:
|
||||||
json.dump(config, f, indent=4)
|
json.dump(config, f, indent=4)
|
||||||
except Exception as e:
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
return e
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ class Context:
|
|||||||
description=None,
|
description=None,
|
||||||
):
|
):
|
||||||
if not name:
|
if not name:
|
||||||
raise Exception("Name not provided")
|
raise ValueError("Name not provided")
|
||||||
self.name = name
|
self.name = name
|
||||||
self.context_type = None
|
self.context_type = None
|
||||||
self.orchestrator = orchestrator
|
self.orchestrator = orchestrator
|
||||||
@ -136,7 +136,7 @@ class Context:
|
|||||||
metadata = json.load(f)
|
metadata = json.load(f)
|
||||||
except (OSError, KeyError, ValueError) as e:
|
except (OSError, KeyError, ValueError) as e:
|
||||||
# unknown format
|
# unknown format
|
||||||
raise Exception(
|
raise RuntimeError(
|
||||||
f"Detected corrupted meta file for context {name} : {e}"
|
f"Detected corrupted meta file for context {name} : {e}"
|
||||||
) from e
|
) from e
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ class Context:
|
|||||||
def _load_certs(self):
|
def _load_certs(self):
|
||||||
certs = {}
|
certs = {}
|
||||||
tls_dir = get_tls_dir(self.name)
|
tls_dir = get_tls_dir(self.name)
|
||||||
for endpoint in self.endpoints.keys():
|
for endpoint in self.endpoints:
|
||||||
if not os.path.isdir(os.path.join(tls_dir, endpoint)):
|
if not os.path.isdir(os.path.join(tls_dir, endpoint)):
|
||||||
continue
|
continue
|
||||||
ca_cert = None
|
ca_cert = None
|
||||||
@ -238,11 +238,11 @@ class Context:
|
|||||||
return self.context_type is None
|
return self.context_type is None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Name(self):
|
def Name(self): # pylint: disable=invalid-name
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Host(self):
|
def Host(self): # pylint: disable=invalid-name
|
||||||
if not self.orchestrator or self.orchestrator == "swarm":
|
if not self.orchestrator or self.orchestrator == "swarm":
|
||||||
endpoint = self.endpoints.get("docker", None)
|
endpoint = self.endpoints.get("docker", None)
|
||||||
if endpoint:
|
if endpoint:
|
||||||
@ -252,27 +252,27 @@ class Context:
|
|||||||
return self.endpoints[self.orchestrator].get("Host", None)
|
return self.endpoints[self.orchestrator].get("Host", None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Orchestrator(self):
|
def Orchestrator(self): # pylint: disable=invalid-name
|
||||||
return self.orchestrator
|
return self.orchestrator
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Metadata(self):
|
def Metadata(self): # pylint: disable=invalid-name
|
||||||
meta = {}
|
meta = {}
|
||||||
if self.orchestrator:
|
if self.orchestrator:
|
||||||
meta = {"StackOrchestrator": self.orchestrator}
|
meta = {"StackOrchestrator": self.orchestrator}
|
||||||
return {"Name": self.name, "Metadata": meta, "Endpoints": self.endpoints}
|
return {"Name": self.name, "Metadata": meta, "Endpoints": self.endpoints}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def TLSConfig(self):
|
def TLSConfig(self): # pylint: disable=invalid-name
|
||||||
key = self.orchestrator
|
key = self.orchestrator
|
||||||
if not key or key == "swarm":
|
if not key or key == "swarm":
|
||||||
key = "docker"
|
key = "docker"
|
||||||
if key in self.tls_cfg.keys():
|
if key in self.tls_cfg:
|
||||||
return self.tls_cfg[key]
|
return self.tls_cfg[key]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def TLSMaterial(self):
|
def TLSMaterial(self): # pylint: disable=invalid-name
|
||||||
certs = {}
|
certs = {}
|
||||||
for endpoint, tls in self.tls_cfg.items():
|
for endpoint, tls in self.tls_cfg.items():
|
||||||
cert, key = tls.cert
|
cert, key = tls.cert
|
||||||
@ -280,5 +280,5 @@ class Context:
|
|||||||
return {"TLSMaterial": certs}
|
return {"TLSMaterial": certs}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Storage(self):
|
def Storage(self): # pylint: disable=invalid-name
|
||||||
return {"Storage": {"MetadataPath": self.meta_path, "TLSPath": self.tls_path}}
|
return {"Storage": {"MetadataPath": self.meta_path, "TLSPath": self.tls_path}}
|
||||||
|
|||||||
@ -91,7 +91,6 @@ class Store:
|
|||||||
raise errors.StoreError(
|
raise errors.StoreError(
|
||||||
f"{self.program} not installed or not available in PATH"
|
f"{self.program} not installed or not available in PATH"
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
raise errors.StoreError(
|
raise errors.StoreError(
|
||||||
f'Unexpected OS error "{e.strerror}", errno={e.errno}'
|
f'Unexpected OS error "{e.strerror}", errno={e.errno}'
|
||||||
)
|
)
|
||||||
|
|||||||
@ -28,9 +28,9 @@ except ImportError:
|
|||||||
PYWIN32_IMPORT_ERROR = traceback.format_exc()
|
PYWIN32_IMPORT_ERROR = traceback.format_exc()
|
||||||
|
|
||||||
|
|
||||||
cERROR_PIPE_BUSY = 0xE7
|
ERROR_PIPE_BUSY = 0xE7
|
||||||
cSECURITY_SQOS_PRESENT = 0x100000
|
SECURITY_SQOS_PRESENT = 0x100000
|
||||||
cSECURITY_ANONYMOUS = 0
|
SECURITY_ANONYMOUS = 0
|
||||||
|
|
||||||
MAXIMUM_RETRY_COUNT = 10
|
MAXIMUM_RETRY_COUNT = 10
|
||||||
|
|
||||||
@ -55,7 +55,9 @@ class NpipeSocket:
|
|||||||
def __init__(self, handle=None):
|
def __init__(self, handle=None):
|
||||||
self._timeout = win32pipe.NMPWAIT_USE_DEFAULT_WAIT
|
self._timeout = win32pipe.NMPWAIT_USE_DEFAULT_WAIT
|
||||||
self._handle = handle
|
self._handle = handle
|
||||||
|
self._address = None
|
||||||
self._closed = False
|
self._closed = False
|
||||||
|
self.flags = None
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -77,8 +79,8 @@ class NpipeSocket:
|
|||||||
None,
|
None,
|
||||||
win32file.OPEN_EXISTING,
|
win32file.OPEN_EXISTING,
|
||||||
(
|
(
|
||||||
cSECURITY_ANONYMOUS
|
SECURITY_ANONYMOUS
|
||||||
| cSECURITY_SQOS_PRESENT
|
| SECURITY_SQOS_PRESENT
|
||||||
| win32file.FILE_FLAG_OVERLAPPED
|
| win32file.FILE_FLAG_OVERLAPPED
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
@ -86,7 +88,7 @@ class NpipeSocket:
|
|||||||
except win32pipe.error as e:
|
except win32pipe.error as e:
|
||||||
# See Remarks:
|
# See Remarks:
|
||||||
# https://msdn.microsoft.com/en-us/library/aa365800.aspx
|
# https://msdn.microsoft.com/en-us/library/aa365800.aspx
|
||||||
if e.winerror == cERROR_PIPE_BUSY:
|
if e.winerror == ERROR_PIPE_BUSY:
|
||||||
# Another program or thread has grabbed our pipe instance
|
# Another program or thread has grabbed our pipe instance
|
||||||
# before we got to it. Wait for availability and attempt to
|
# before we got to it. Wait for availability and attempt to
|
||||||
# connect again.
|
# connect again.
|
||||||
|
|||||||
@ -72,7 +72,7 @@ class SSHSocket(socket.socket):
|
|||||||
env.pop("LD_LIBRARY_PATH", None)
|
env.pop("LD_LIBRARY_PATH", None)
|
||||||
env.pop("SSL_CERT_FILE", None)
|
env.pop("SSL_CERT_FILE", None)
|
||||||
|
|
||||||
self.proc = subprocess.Popen(
|
self.proc = subprocess.Popen( # pylint: disable=consider-using-with
|
||||||
args,
|
args,
|
||||||
env=env,
|
env=env,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
@ -82,7 +82,7 @@ class SSHSocket(socket.socket):
|
|||||||
|
|
||||||
def _write(self, data):
|
def _write(self, data):
|
||||||
if not self.proc or self.proc.stdin.closed:
|
if not self.proc or self.proc.stdin.closed:
|
||||||
raise Exception(
|
raise RuntimeError(
|
||||||
"SSH subprocess not initiated. connect() must be called first."
|
"SSH subprocess not initiated. connect() must be called first."
|
||||||
)
|
)
|
||||||
written = self.proc.stdin.write(data)
|
written = self.proc.stdin.write(data)
|
||||||
@ -97,7 +97,7 @@ class SSHSocket(socket.socket):
|
|||||||
|
|
||||||
def recv(self, n):
|
def recv(self, n):
|
||||||
if not self.proc:
|
if not self.proc:
|
||||||
raise Exception(
|
raise RuntimeError(
|
||||||
"SSH subprocess not initiated. connect() must be called first."
|
"SSH subprocess not initiated. connect() must be called first."
|
||||||
)
|
)
|
||||||
return self.proc.stdout.read(n)
|
return self.proc.stdout.read(n)
|
||||||
|
|||||||
@ -125,19 +125,22 @@ def create_archive(root, files=None, fileobj=None, gzip=False, extra_files=None)
|
|||||||
|
|
||||||
|
|
||||||
def mkbuildcontext(dockerfile):
|
def mkbuildcontext(dockerfile):
|
||||||
f = tempfile.NamedTemporaryFile()
|
f = tempfile.NamedTemporaryFile() # pylint: disable=consider-using-with
|
||||||
t = tarfile.open(mode="w", fileobj=f)
|
try:
|
||||||
|
with tarfile.open(mode="w", fileobj=f) as t:
|
||||||
if isinstance(dockerfile, io.StringIO):
|
if isinstance(dockerfile, io.StringIO):
|
||||||
raise TypeError("Please use io.BytesIO to create in-memory Dockerfiles")
|
raise TypeError("Please use io.BytesIO to create in-memory Dockerfiles")
|
||||||
elif isinstance(dockerfile, io.BytesIO):
|
if isinstance(dockerfile, io.BytesIO):
|
||||||
dfinfo = tarfile.TarInfo("Dockerfile")
|
dfinfo = tarfile.TarInfo("Dockerfile")
|
||||||
dfinfo.size = len(dockerfile.getvalue())
|
dfinfo.size = len(dockerfile.getvalue())
|
||||||
dockerfile.seek(0)
|
dockerfile.seek(0)
|
||||||
else:
|
else:
|
||||||
dfinfo = t.gettarinfo(fileobj=dockerfile, arcname="Dockerfile")
|
dfinfo = t.gettarinfo(fileobj=dockerfile, arcname="Dockerfile")
|
||||||
t.addfile(dfinfo, dockerfile)
|
t.addfile(dfinfo, dockerfile)
|
||||||
t.close()
|
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
|
except Exception: # noqa: E722
|
||||||
|
f.close()
|
||||||
|
raise
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -68,7 +68,6 @@ def home_dir():
|
|||||||
"""
|
"""
|
||||||
if IS_WINDOWS_PLATFORM:
|
if IS_WINDOWS_PLATFORM:
|
||||||
return os.environ.get("USERPROFILE", "")
|
return os.environ.get("USERPROFILE", "")
|
||||||
else:
|
|
||||||
return os.path.expanduser("~")
|
return os.path.expanduser("~")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -17,23 +17,6 @@ from .. import errors
|
|||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
|
|
||||||
def check_resource(resource_name):
|
|
||||||
def decorator(f):
|
|
||||||
@functools.wraps(f)
|
|
||||||
def wrapped(self, resource_id=None, *args, **kwargs):
|
|
||||||
if resource_id is None and kwargs.get(resource_name):
|
|
||||||
resource_id = kwargs.pop(resource_name)
|
|
||||||
if isinstance(resource_id, dict):
|
|
||||||
resource_id = resource_id.get("Id", resource_id.get("ID"))
|
|
||||||
if not resource_id:
|
|
||||||
raise errors.NullResource("Resource ID was not provided")
|
|
||||||
return f(self, resource_id, *args, **kwargs)
|
|
||||||
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
|
|
||||||
def minimum_version(version):
|
def minimum_version(version):
|
||||||
def decorator(f):
|
def decorator(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
|
|||||||
@ -90,7 +90,6 @@ def split_port(port):
|
|||||||
if external is not None and len(internal) != len(external):
|
if external is not None and len(internal) != len(external):
|
||||||
raise ValueError("Port ranges don't match in length")
|
raise ValueError("Port ranges don't match in length")
|
||||||
return internal, external
|
return internal, external
|
||||||
else:
|
|
||||||
if not external:
|
if not external:
|
||||||
external = [None] * len(internal)
|
external = [None] * len(internal)
|
||||||
elif len(internal) != len(external):
|
elif len(internal) != len(external):
|
||||||
|
|||||||
@ -111,7 +111,6 @@ def frames_iter(socket, tty):
|
|||||||
"""
|
"""
|
||||||
if tty:
|
if tty:
|
||||||
return ((STDOUT, frame) for frame in frames_iter_tty(socket))
|
return ((STDOUT, frame) for frame in frames_iter_tty(socket))
|
||||||
else:
|
|
||||||
return frames_iter_no_tty(socket)
|
return frames_iter_no_tty(socket)
|
||||||
|
|
||||||
|
|
||||||
@ -194,7 +193,6 @@ def demux_adaptor(stream_id, data):
|
|||||||
"""
|
"""
|
||||||
if stream_id == STDOUT:
|
if stream_id == STDOUT:
|
||||||
return (data, None)
|
return (data, None)
|
||||||
elif stream_id == STDERR:
|
if stream_id == STDERR:
|
||||||
return (None, data)
|
return (None, data)
|
||||||
else:
|
|
||||||
raise ValueError(f"{stream_id} is not a valid stream")
|
raise ValueError(f"{stream_id} is not a valid stream")
|
||||||
|
|||||||
@ -75,9 +75,8 @@ def compare_version(v1, v2):
|
|||||||
s2 = StrictVersion(v2)
|
s2 = StrictVersion(v2)
|
||||||
if s1 == s2:
|
if s1 == s2:
|
||||||
return 0
|
return 0
|
||||||
elif s1 > s2:
|
if s1 > s2:
|
||||||
return -1
|
return -1
|
||||||
else:
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
@ -250,7 +249,7 @@ def parse_host(addr, is_win32=False, tls=False):
|
|||||||
|
|
||||||
# These protos are valid aliases for our library but not for the
|
# These protos are valid aliases for our library but not for the
|
||||||
# official spec
|
# official spec
|
||||||
if proto == "http" or proto == "https":
|
if proto in ("http", "https"):
|
||||||
tls = proto == "https"
|
tls = proto == "https"
|
||||||
proto = "tcp"
|
proto = "tcp"
|
||||||
elif proto == "http+unix":
|
elif proto == "http+unix":
|
||||||
@ -273,7 +272,6 @@ def parse_host(addr, is_win32=False, tls=False):
|
|||||||
raise errors.DockerException(
|
raise errors.DockerException(
|
||||||
f"Invalid bind address format: no path allowed for this protocol: {addr}"
|
f"Invalid bind address format: no path allowed for this protocol: {addr}"
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
path = parsed_url.path
|
path = parsed_url.path
|
||||||
if proto == "unix" and parsed_url.hostname is not None:
|
if proto == "unix" and parsed_url.hostname is not None:
|
||||||
# For legacy reasons, we consider unix://path
|
# For legacy reasons, we consider unix://path
|
||||||
@ -419,7 +417,7 @@ def parse_bytes(s):
|
|||||||
else:
|
else:
|
||||||
digits_part = s[:-1]
|
digits_part = s[:-1]
|
||||||
|
|
||||||
if suffix in units.keys() or suffix.isdigit():
|
if suffix in units or suffix.isdigit():
|
||||||
try:
|
try:
|
||||||
digits = float(digits_part)
|
digits = float(digits_part)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|||||||
@ -98,7 +98,7 @@ MIN_DOCKER_VERSION = "1.8.0"
|
|||||||
|
|
||||||
|
|
||||||
if not HAS_DOCKER_PY:
|
if not HAS_DOCKER_PY:
|
||||||
docker_version = None
|
docker_version = None # pylint: disable=invalid-name
|
||||||
|
|
||||||
# No Docker SDK for Python. Create a place holder client to allow
|
# No Docker SDK for Python. Create a place holder client to allow
|
||||||
# instantiation of AnsibleModule and proper error handing
|
# instantiation of AnsibleModule and proper error handing
|
||||||
@ -194,7 +194,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
def __init__(self, min_docker_version=None, min_docker_api_version=None):
|
def __init__(self, min_docker_version=None, min_docker_api_version=None):
|
||||||
if min_docker_version is None:
|
if min_docker_version is None:
|
||||||
min_docker_version = MIN_DOCKER_VERSION
|
min_docker_version = MIN_DOCKER_VERSION
|
||||||
NEEDS_DOCKER_PY2 = LooseVersion(min_docker_version) >= LooseVersion("2.0.0")
|
needs_docker_py2 = LooseVersion(min_docker_version) >= LooseVersion("2.0.0")
|
||||||
|
|
||||||
self.docker_py_version = LooseVersion(docker_version)
|
self.docker_py_version = LooseVersion(docker_version)
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
f"Error: Docker SDK for Python version is {docker_version} ({platform.node()}'s Python {sys.executable})."
|
f"Error: Docker SDK for Python version is {docker_version} ({platform.node()}'s Python {sys.executable})."
|
||||||
f" Minimum version required is {min_docker_version}."
|
f" Minimum version required is {min_docker_version}."
|
||||||
)
|
)
|
||||||
if not NEEDS_DOCKER_PY2:
|
if not needs_docker_py2:
|
||||||
# The minimal required version is < 2.0 (and the current version as well).
|
# The minimal required version is < 2.0 (and the current version as well).
|
||||||
# Advertise docker (instead of docker-py).
|
# Advertise docker (instead of docker-py).
|
||||||
msg += DOCKERPYUPGRADE_RECOMMEND_DOCKER
|
msg += DOCKERPYUPGRADE_RECOMMEND_DOCKER
|
||||||
@ -237,7 +237,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
self.docker_api_version_str = self.api_version
|
self.docker_api_version_str = self.api_version
|
||||||
except APIError as exc:
|
except APIError as exc:
|
||||||
self.fail(f"Docker API error: {exc}")
|
self.fail(f"Docker API error: {exc}")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error connecting: {exc}")
|
self.fail(f"Error connecting: {exc}")
|
||||||
|
|
||||||
self.docker_api_version = LooseVersion(self.docker_api_version_str)
|
self.docker_api_version = LooseVersion(self.docker_api_version_str)
|
||||||
@ -409,7 +409,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
return result
|
return result
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting container: {exc}")
|
self.fail(f"Error inspecting container: {exc}")
|
||||||
|
|
||||||
def get_container(self, name=None):
|
def get_container(self, name=None):
|
||||||
@ -441,7 +441,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
break
|
break
|
||||||
except SSLError as exc:
|
except SSLError as exc:
|
||||||
self._handle_ssl_error(exc)
|
self._handle_ssl_error(exc)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error retrieving container list: {exc}")
|
self.fail(f"Error retrieving container list: {exc}")
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
@ -470,7 +470,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
break
|
break
|
||||||
except SSLError as exc:
|
except SSLError as exc:
|
||||||
self._handle_ssl_error(exc)
|
self._handle_ssl_error(exc)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error retrieving network list: {exc}")
|
self.fail(f"Error retrieving network list: {exc}")
|
||||||
|
|
||||||
if result is not None:
|
if result is not None:
|
||||||
@ -483,7 +483,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
self.log("Completed network inspection")
|
self.log("Completed network inspection")
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting network: {exc}")
|
self.fail(f"Error inspecting network: {exc}")
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -533,7 +533,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
except NotFound:
|
except NotFound:
|
||||||
self.log(f"Image {name}:{tag} not found.")
|
self.log(f"Image {name}:{tag} not found.")
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting image {name}:{tag} - {exc}")
|
self.fail(f"Error inspecting image {name}:{tag} - {exc}")
|
||||||
return inspection
|
return inspection
|
||||||
|
|
||||||
@ -555,7 +555,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
self.fail(f"Error inspecting image ID {image_id} - {exc}")
|
self.fail(f"Error inspecting image ID {image_id} - {exc}")
|
||||||
self.log(f"Image {image_id} not found.")
|
self.log(f"Image {image_id} not found.")
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting image ID {image_id} - {exc}")
|
self.fail(f"Error inspecting image ID {image_id} - {exc}")
|
||||||
return inspection
|
return inspection
|
||||||
|
|
||||||
@ -567,7 +567,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
response = self.images(name=name)
|
response = self.images(name=name)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error searching for image {name} - {exc}")
|
self.fail(f"Error searching for image {name} - {exc}")
|
||||||
images = response
|
images = response
|
||||||
if tag:
|
if tag:
|
||||||
@ -606,7 +606,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.fail(f"Error pulling {name} - {line.get('error')}")
|
self.fail(f"Error pulling {name} - {line.get('error')}")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error pulling image {name}:{tag} - {exc}")
|
self.fail(f"Error pulling image {name}:{tag} - {exc}")
|
||||||
|
|
||||||
new_tag = self.find_image(name, tag)
|
new_tag = self.find_image(name, tag)
|
||||||
|
|||||||
@ -128,7 +128,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
)
|
)
|
||||||
except APIError as exc:
|
except APIError as exc:
|
||||||
self.fail(f"Docker API error: {exc}")
|
self.fail(f"Docker API error: {exc}")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error connecting: {exc}")
|
self.fail(f"Error connecting: {exc}")
|
||||||
|
|
||||||
self.docker_api_version = LooseVersion(self.docker_api_version_str)
|
self.docker_api_version = LooseVersion(self.docker_api_version_str)
|
||||||
@ -308,7 +308,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
return result
|
return result
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting container: {exc}")
|
self.fail(f"Error inspecting container: {exc}")
|
||||||
|
|
||||||
def get_container(self, name=None):
|
def get_container(self, name=None):
|
||||||
@ -347,7 +347,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
break
|
break
|
||||||
except SSLError as exc:
|
except SSLError as exc:
|
||||||
self._handle_ssl_error(exc)
|
self._handle_ssl_error(exc)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error retrieving container list: {exc}")
|
self.fail(f"Error retrieving container list: {exc}")
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
@ -377,7 +377,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
break
|
break
|
||||||
except SSLError as exc:
|
except SSLError as exc:
|
||||||
self._handle_ssl_error(exc)
|
self._handle_ssl_error(exc)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error retrieving network list: {exc}")
|
self.fail(f"Error retrieving network list: {exc}")
|
||||||
|
|
||||||
if result is not None:
|
if result is not None:
|
||||||
@ -390,7 +390,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
self.log("Completed network inspection")
|
self.log("Completed network inspection")
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting network: {exc}")
|
self.fail(f"Error inspecting network: {exc}")
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -412,7 +412,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
else:
|
else:
|
||||||
params["filters"] = convert_filters({"reference": name})
|
params["filters"] = convert_filters({"reference": name})
|
||||||
images = self.get_json("/images/json", params=params)
|
images = self.get_json("/images/json", params=params)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error searching for image {name} - {exc}")
|
self.fail(f"Error searching for image {name} - {exc}")
|
||||||
if tag:
|
if tag:
|
||||||
lookup = f"{name}:{tag}"
|
lookup = f"{name}:{tag}"
|
||||||
@ -472,7 +472,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
except NotFound:
|
except NotFound:
|
||||||
self.log(f"Image {name}:{tag} not found.")
|
self.log(f"Image {name}:{tag} not found.")
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting image {name}:{tag} - {exc}")
|
self.fail(f"Error inspecting image {name}:{tag} - {exc}")
|
||||||
|
|
||||||
self.log(f"Image {name}:{tag} not found.")
|
self.log(f"Image {name}:{tag} not found.")
|
||||||
@ -493,7 +493,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
self.fail(f"Error inspecting image ID {image_id} - {exc}")
|
self.fail(f"Error inspecting image ID {image_id} - {exc}")
|
||||||
self.log(f"Image {image_id} not found.")
|
self.log(f"Image {image_id} not found.")
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting image ID {image_id} - {exc}")
|
self.fail(f"Error inspecting image ID {image_id} - {exc}")
|
||||||
|
|
||||||
def pull_image(self, name, tag="latest", image_platform=None):
|
def pull_image(self, name, tag="latest", image_platform=None):
|
||||||
@ -535,7 +535,7 @@ class AnsibleDockerClientBase(Client):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.fail(f"Error pulling {name} - {line.get('error')}")
|
self.fail(f"Error pulling {name} - {line.get('error')}")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error pulling image {name}:{tag} - {exc}")
|
self.fail(f"Error pulling image {name}:{tag} - {exc}")
|
||||||
|
|
||||||
new_tag = self.find_image(name, tag)
|
new_tag = self.find_image(name, tag)
|
||||||
|
|||||||
@ -159,7 +159,7 @@ class AnsibleDockerClientBase:
|
|||||||
self.warn(to_native(stderr))
|
self.warn(to_native(stderr))
|
||||||
try:
|
try:
|
||||||
data = json.loads(stdout)
|
data = json.loads(stdout)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Error while parsing JSON output of {self._compose_cmd_str(args)}: {exc}\nJSON output: {to_native(stdout)}"
|
f"Error while parsing JSON output of {self._compose_cmd_str(args)}: {exc}\nJSON output: {to_native(stdout)}"
|
||||||
)
|
)
|
||||||
@ -177,7 +177,7 @@ class AnsibleDockerClientBase:
|
|||||||
line = line.strip()
|
line = line.strip()
|
||||||
if line.startswith(b"{"):
|
if line.startswith(b"{"):
|
||||||
result.append(json.loads(line))
|
result.append(json.loads(line))
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Error while parsing JSON output of {self._compose_cmd_str(args)}: {exc}\nJSON output: {to_native(stdout)}"
|
f"Error while parsing JSON output of {self._compose_cmd_str(args)}: {exc}\nJSON output: {to_native(stdout)}"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -176,9 +176,13 @@ _RE_PULL_EVENT = re.compile(
|
|||||||
r"\s*"
|
r"\s*"
|
||||||
r"(?P<service>\S+)"
|
r"(?P<service>\S+)"
|
||||||
r"\s+"
|
r"\s+"
|
||||||
r"(?P<status>%s)"
|
f"(?P<status>{'|'.join(re.escape(status) for status in DOCKER_STATUS_PULL)})"
|
||||||
r"\s*"
|
r"\s*"
|
||||||
r"$" % "|".join(re.escape(status) for status in DOCKER_STATUS_PULL)
|
r"$"
|
||||||
|
)
|
||||||
|
|
||||||
|
_DOCKER_PULL_PROGRESS_WD = sorted(
|
||||||
|
DOCKER_PULL_PROGRESS_DONE | DOCKER_PULL_PROGRESS_WORKING
|
||||||
)
|
)
|
||||||
|
|
||||||
_RE_PULL_PROGRESS = re.compile(
|
_RE_PULL_PROGRESS = re.compile(
|
||||||
@ -186,14 +190,10 @@ _RE_PULL_PROGRESS = re.compile(
|
|||||||
r"\s*"
|
r"\s*"
|
||||||
r"(?P<layer>\S+)"
|
r"(?P<layer>\S+)"
|
||||||
r"\s+"
|
r"\s+"
|
||||||
r"(?P<status>%s)"
|
f"(?P<status>{'|'.join(re.escape(status) for status in _DOCKER_PULL_PROGRESS_WD)})"
|
||||||
r"\s*"
|
r"\s*"
|
||||||
r"(?:|\s\[[^]]+\]\s+\S+\s*|\s+[0-9.kKmMgGbB]+/[0-9.kKmMgGbB]+\s*)"
|
r"(?:|\s\[[^]]+\]\s+\S+\s*|\s+[0-9.kKmMgGbB]+/[0-9.kKmMgGbB]+\s*)"
|
||||||
r"$"
|
r"$"
|
||||||
% "|".join(
|
|
||||||
re.escape(status)
|
|
||||||
for status in sorted(DOCKER_PULL_PROGRESS_DONE | DOCKER_PULL_PROGRESS_WORKING)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_RE_ERROR_EVENT = re.compile(
|
_RE_ERROR_EVENT = re.compile(
|
||||||
@ -201,10 +201,10 @@ _RE_ERROR_EVENT = re.compile(
|
|||||||
r"\s*"
|
r"\s*"
|
||||||
r"(?P<resource_id>\S+)"
|
r"(?P<resource_id>\S+)"
|
||||||
r"\s+"
|
r"\s+"
|
||||||
r"(?P<status>%s)"
|
f"(?P<status>{'|'.join(re.escape(status) for status in DOCKER_STATUS_ERROR)})"
|
||||||
r"\s*"
|
r"\s*"
|
||||||
r"(?P<msg>\S.*\S)?"
|
r"(?P<msg>\S.*\S)?"
|
||||||
r"$" % "|".join(re.escape(status) for status in DOCKER_STATUS_ERROR)
|
r"$"
|
||||||
)
|
)
|
||||||
|
|
||||||
_RE_WARNING_EVENT = re.compile(
|
_RE_WARNING_EVENT = re.compile(
|
||||||
@ -212,10 +212,10 @@ _RE_WARNING_EVENT = re.compile(
|
|||||||
r"\s*"
|
r"\s*"
|
||||||
r"(?P<resource_id>\S+)"
|
r"(?P<resource_id>\S+)"
|
||||||
r"\s+"
|
r"\s+"
|
||||||
r"(?P<status>%s)"
|
f"(?P<status>{'|'.join(re.escape(status) for status in DOCKER_STATUS_WARNING)})"
|
||||||
r"\s*"
|
r"\s*"
|
||||||
r"(?P<msg>\S.*\S)?"
|
r"(?P<msg>\S.*\S)?"
|
||||||
r"$" % "|".join(re.escape(status) for status in DOCKER_STATUS_WARNING)
|
r"$"
|
||||||
)
|
)
|
||||||
|
|
||||||
_RE_CONTINUE_EVENT = re.compile(r"^\s*(?P<resource_id>\S+)\s+-\s*(?P<msg>\S(?:|.*\S))$")
|
_RE_CONTINUE_EVENT = re.compile(r"^\s*(?P<resource_id>\S+)\s+-\s*(?P<msg>\S(?:|.*\S))$")
|
||||||
@ -405,7 +405,7 @@ def parse_json_events(stderr, warn_function=None):
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
line_data = json.loads(line)
|
line_data = json.loads(line)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
if warn_function:
|
if warn_function:
|
||||||
warn_function(
|
warn_function(
|
||||||
f"Cannot parse event from line: {line!r}: {exc}. Please report this at "
|
f"Cannot parse event from line: {line!r}: {exc}. Please report this at "
|
||||||
@ -544,7 +544,7 @@ def parse_events(stderr, dry_run=False, warn_function=None, nonzero_rc=False):
|
|||||||
line, warn_missing_dry_run_prefix, warn_function
|
line, warn_missing_dry_run_prefix, warn_function
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
elif parsed:
|
if parsed:
|
||||||
continue
|
continue
|
||||||
match = _RE_BUILD_PROGRESS_EVENT.match(line)
|
match = _RE_BUILD_PROGRESS_EVENT.match(line)
|
||||||
if match:
|
if match:
|
||||||
@ -748,7 +748,7 @@ class BaseComposeManager(DockerBaseClass):
|
|||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
Dumper=_SafeDumper,
|
Dumper=_SafeDumper,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error writing to {compose_file} - {exc}")
|
self.fail(f"Error writing to {compose_file} - {exc}")
|
||||||
else:
|
else:
|
||||||
self.project_src = os.path.abspath(parameters["project_src"])
|
self.project_src = os.path.abspath(parameters["project_src"])
|
||||||
@ -804,7 +804,7 @@ class BaseComposeManager(DockerBaseClass):
|
|||||||
if version == "dev":
|
if version == "dev":
|
||||||
return None
|
return None
|
||||||
return version.lstrip("v")
|
return version.lstrip("v")
|
||||||
except Exception:
|
except Exception: # pylint: disable=broad-exception-caught
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_compose_version_from_api(self):
|
def get_compose_version_from_api(self):
|
||||||
@ -946,6 +946,6 @@ class BaseComposeManager(DockerBaseClass):
|
|||||||
for directory in self.cleanup_dirs:
|
for directory in self.cleanup_dirs:
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(directory, True)
|
shutil.rmtree(directory, True)
|
||||||
except Exception:
|
except Exception: # pylint: disable=broad-exception-caught
|
||||||
# should not happen, but simply ignore to be on the safe side
|
# should not happen, but simply ignore to be on the safe side
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -133,10 +133,9 @@ def parse_line(line, logrus_mode=False):
|
|||||||
key.append(cur)
|
key.append(cur)
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.KEY
|
return _Mode.KEY
|
||||||
elif cur == "=":
|
if cur == "=":
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.EQUAL
|
return _Mode.EQUAL
|
||||||
else:
|
|
||||||
if logrus_mode:
|
if logrus_mode:
|
||||||
raise InvalidLogFmt('Key must always be followed by "=" in logrus mode')
|
raise InvalidLogFmt('Key must always be followed by "=" in logrus mode')
|
||||||
handle_kv(has_no_value=True)
|
handle_kv(has_no_value=True)
|
||||||
@ -148,10 +147,9 @@ def parse_line(line, logrus_mode=False):
|
|||||||
value.append(cur)
|
value.append(cur)
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.IDENT_VALUE
|
return _Mode.IDENT_VALUE
|
||||||
elif cur == '"':
|
if cur == '"':
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.QUOTED_VALUE
|
return _Mode.QUOTED_VALUE
|
||||||
else:
|
|
||||||
handle_kv()
|
handle_kv()
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.GARBAGE
|
return _Mode.GARBAGE
|
||||||
@ -161,7 +159,6 @@ def parse_line(line, logrus_mode=False):
|
|||||||
value.append(cur)
|
value.append(cur)
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.IDENT_VALUE
|
return _Mode.IDENT_VALUE
|
||||||
else:
|
|
||||||
handle_kv()
|
handle_kv()
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.GARBAGE
|
return _Mode.GARBAGE
|
||||||
@ -182,13 +179,12 @@ def parse_line(line, logrus_mode=False):
|
|||||||
value.append(parser.parse_unicode_sequence())
|
value.append(parser.parse_unicode_sequence())
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.QUOTED_VALUE
|
return _Mode.QUOTED_VALUE
|
||||||
elif cur == '"':
|
if cur == '"':
|
||||||
handle_kv()
|
handle_kv()
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.GARBAGE
|
return _Mode.GARBAGE
|
||||||
elif cur < " ":
|
if cur < " ":
|
||||||
raise InvalidLogFmt("Control characters in quoted string are not allowed")
|
raise InvalidLogFmt("Control characters in quoted string are not allowed")
|
||||||
else:
|
|
||||||
value.append(cur)
|
value.append(cur)
|
||||||
parser.next()
|
parser.next()
|
||||||
return _Mode.QUOTED_VALUE
|
return _Mode.QUOTED_VALUE
|
||||||
@ -204,7 +200,7 @@ def parse_line(line, logrus_mode=False):
|
|||||||
mode = parsers[mode](parser.cur())
|
mode = parsers[mode](parser.cur())
|
||||||
if mode == _Mode.KEY and logrus_mode:
|
if mode == _Mode.KEY and logrus_mode:
|
||||||
raise InvalidLogFmt('Key must always be followed by "=" in logrus mode')
|
raise InvalidLogFmt('Key must always be followed by "=" in logrus mode')
|
||||||
if mode == _Mode.KEY or mode == _Mode.EQUAL:
|
if mode in (_Mode.KEY, _Mode.EQUAL):
|
||||||
handle_kv(has_no_value=True)
|
handle_kv(has_no_value=True)
|
||||||
elif mode == _Mode.IDENT_VALUE:
|
elif mode == _Mode.IDENT_VALUE:
|
||||||
handle_kv()
|
handle_kv()
|
||||||
|
|||||||
@ -58,7 +58,7 @@ def _get_ansible_type(value_type):
|
|||||||
if value_type == "set":
|
if value_type == "set":
|
||||||
return "list"
|
return "list"
|
||||||
if value_type not in ("list", "dict", "bool", "int", "float", "str"):
|
if value_type not in ("list", "dict", "bool", "int", "float", "str"):
|
||||||
raise Exception(f'Invalid type "{value_type}"')
|
raise ValueError(f'Invalid type "{value_type}"')
|
||||||
return value_type
|
return value_type
|
||||||
|
|
||||||
|
|
||||||
@ -87,13 +87,13 @@ class Option:
|
|||||||
needs_elements = self.value_type in ("list", "set")
|
needs_elements = self.value_type in ("list", "set")
|
||||||
needs_ansible_elements = self.ansible_type in ("list",)
|
needs_ansible_elements = self.ansible_type in ("list",)
|
||||||
if elements is not None and not needs_elements:
|
if elements is not None and not needs_elements:
|
||||||
raise Exception("elements only allowed for lists/sets")
|
raise ValueError("elements only allowed for lists/sets")
|
||||||
if elements is None and needs_elements:
|
if elements is None and needs_elements:
|
||||||
raise Exception("elements required for lists/sets")
|
raise ValueError("elements required for lists/sets")
|
||||||
if ansible_elements is not None and not needs_ansible_elements:
|
if ansible_elements is not None and not needs_ansible_elements:
|
||||||
raise Exception("Ansible elements only allowed for Ansible lists")
|
raise ValueError("Ansible elements only allowed for Ansible lists")
|
||||||
if (elements is None and ansible_elements is None) and needs_ansible_elements:
|
if (elements is None and ansible_elements is None) and needs_ansible_elements:
|
||||||
raise Exception("Ansible elements required for Ansible lists")
|
raise ValueError("Ansible elements required for Ansible lists")
|
||||||
self.elements = elements if needs_elements else None
|
self.elements = elements if needs_elements else None
|
||||||
self.ansible_elements = (
|
self.ansible_elements = (
|
||||||
(ansible_elements or _get_ansible_type(elements))
|
(ansible_elements or _get_ansible_type(elements))
|
||||||
@ -104,7 +104,7 @@ class Option:
|
|||||||
self.ansible_type == "list" and self.ansible_elements == "dict"
|
self.ansible_type == "list" and self.ansible_elements == "dict"
|
||||||
) or (self.ansible_type == "dict")
|
) or (self.ansible_type == "dict")
|
||||||
if ansible_suboptions is not None and not needs_suboptions:
|
if ansible_suboptions is not None and not needs_suboptions:
|
||||||
raise Exception(
|
raise ValueError(
|
||||||
"suboptions only allowed for Ansible lists with dicts, or Ansible dicts"
|
"suboptions only allowed for Ansible lists with dicts, or Ansible dicts"
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
@ -113,7 +113,7 @@ class Option:
|
|||||||
and not needs_no_suboptions
|
and not needs_no_suboptions
|
||||||
and not not_an_ansible_option
|
and not not_an_ansible_option
|
||||||
):
|
):
|
||||||
raise Exception(
|
raise ValueError(
|
||||||
"suboptions required for Ansible lists with dicts, or Ansible dicts"
|
"suboptions required for Ansible lists with dicts, or Ansible dicts"
|
||||||
)
|
)
|
||||||
self.ansible_suboptions = ansible_suboptions if needs_suboptions else None
|
self.ansible_suboptions = ansible_suboptions if needs_suboptions else None
|
||||||
@ -431,15 +431,14 @@ def _parse_port_range(range_or_port, module):
|
|||||||
if "-" in range_or_port:
|
if "-" in range_or_port:
|
||||||
try:
|
try:
|
||||||
start, end = [int(port) for port in range_or_port.split("-")]
|
start, end = [int(port) for port in range_or_port.split("-")]
|
||||||
except Exception:
|
except ValueError:
|
||||||
module.fail_json(msg=f'Invalid port range: "{range_or_port}"')
|
module.fail_json(msg=f'Invalid port range: "{range_or_port}"')
|
||||||
if end < start:
|
if end < start:
|
||||||
module.fail_json(msg=f'Invalid port range: "{range_or_port}"')
|
module.fail_json(msg=f'Invalid port range: "{range_or_port}"')
|
||||||
return list(range(start, end + 1))
|
return list(range(start, end + 1))
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
return [int(range_or_port)]
|
return [int(range_or_port)]
|
||||||
except Exception:
|
except ValueError:
|
||||||
module.fail_json(msg=f'Invalid port: "{range_or_port}"')
|
module.fail_json(msg=f'Invalid port: "{range_or_port}"')
|
||||||
|
|
||||||
|
|
||||||
@ -707,7 +706,7 @@ def _preprocess_mounts(module, values):
|
|||||||
if mount_dict["tmpfs_mode"] is not None:
|
if mount_dict["tmpfs_mode"] is not None:
|
||||||
try:
|
try:
|
||||||
mount_dict["tmpfs_mode"] = int(mount_dict["tmpfs_mode"], 8)
|
mount_dict["tmpfs_mode"] = int(mount_dict["tmpfs_mode"], 8)
|
||||||
except Exception:
|
except ValueError:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=f'tmp_fs mode of mount "{target}" is not an octal string!'
|
msg=f'tmp_fs mode of mount "{target}" is not an octal string!'
|
||||||
)
|
)
|
||||||
@ -747,7 +746,7 @@ def _preprocess_mounts(module, values):
|
|||||||
check_collision(container, "volumes")
|
check_collision(container, "volumes")
|
||||||
new_vols.append(f"{host}:{container}:{mode}")
|
new_vols.append(f"{host}:{container}:{mode}")
|
||||||
continue
|
continue
|
||||||
elif len(parts) == 2:
|
if len(parts) == 2:
|
||||||
if not _is_volume_permissions(parts[1]) and re.match(
|
if not _is_volume_permissions(parts[1]) and re.match(
|
||||||
r"[.~]", parts[0]
|
r"[.~]", parts[0]
|
||||||
):
|
):
|
||||||
|
|||||||
@ -124,7 +124,7 @@ def _get_ansible_type(our_type):
|
|||||||
if our_type == "set":
|
if our_type == "set":
|
||||||
return "list"
|
return "list"
|
||||||
if our_type not in ("list", "dict", "bool", "int", "float", "str"):
|
if our_type not in ("list", "dict", "bool", "int", "float", "str"):
|
||||||
raise Exception(f'Invalid type "{our_type}"')
|
raise ValueError(f'Invalid type "{our_type}"')
|
||||||
return our_type
|
return our_type
|
||||||
|
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ class DockerAPIEngineDriver(EngineDriver):
|
|||||||
# Ensure driver_opts values are strings
|
# Ensure driver_opts values are strings
|
||||||
for key, val in value.items():
|
for key, val in value.items():
|
||||||
if not isinstance(val, str):
|
if not isinstance(val, str):
|
||||||
raise Exception(
|
raise ValueError(
|
||||||
f"driver_opts values must be strings, got {type(val).__name__} for key '{key}'"
|
f"driver_opts values must be strings, got {type(val).__name__} for key '{key}'"
|
||||||
)
|
)
|
||||||
params[dest_para] = value
|
params[dest_para] = value
|
||||||
@ -278,7 +278,7 @@ class DockerAPIEngineDriver(EngineDriver):
|
|||||||
params[dest_para] = value
|
params[dest_para] = value
|
||||||
if parameters:
|
if parameters:
|
||||||
ups = ", ".join([f'"{p}"' for p in sorted(parameters)])
|
ups = ", ".join([f'"{p}"' for p in sorted(parameters)])
|
||||||
raise Exception(
|
raise ValueError(
|
||||||
f"Unknown parameter(s) for connect_container_to_network for Docker API driver: {ups}"
|
f"Unknown parameter(s) for connect_container_to_network for Docker API driver: {ups}"
|
||||||
)
|
)
|
||||||
ipam_config = {}
|
ipam_config = {}
|
||||||
@ -347,7 +347,6 @@ class DockerAPIEngineDriver(EngineDriver):
|
|||||||
)
|
)
|
||||||
output = client._get_result_tty(False, res, config["Config"]["Tty"])
|
output = client._get_result_tty(False, res, config["Config"]["Tty"])
|
||||||
return output, True
|
return output, True
|
||||||
else:
|
|
||||||
return f"Result logged using `{logging_driver}` driver", False
|
return f"Result logged using `{logging_driver}` driver", False
|
||||||
|
|
||||||
def update_container(self, client, container_id, update_parameters):
|
def update_container(self, client, container_id, update_parameters):
|
||||||
@ -399,13 +398,13 @@ class DockerAPIEngineDriver(EngineDriver):
|
|||||||
# New docker daemon versions do not allow containers to be removed
|
# New docker daemon versions do not allow containers to be removed
|
||||||
# if they are paused. Make sure we do not end up in an infinite loop.
|
# if they are paused. Make sure we do not end up in an infinite loop.
|
||||||
if count == 3:
|
if count == 3:
|
||||||
raise Exception(f"{exc} [tried to unpause three times]")
|
raise RuntimeError(f"{exc} [tried to unpause three times]")
|
||||||
count += 1
|
count += 1
|
||||||
# Unpause
|
# Unpause
|
||||||
try:
|
try:
|
||||||
self.unpause_container(client, container_id)
|
self.unpause_container(client, container_id)
|
||||||
except Exception as exc2:
|
except Exception as exc2:
|
||||||
raise Exception(f"{exc2} [while unpausing]")
|
raise RuntimeError(f"{exc2} [while unpausing]")
|
||||||
# Now try again
|
# Now try again
|
||||||
continue
|
continue
|
||||||
raise
|
raise
|
||||||
@ -430,13 +429,13 @@ class DockerAPIEngineDriver(EngineDriver):
|
|||||||
# New docker daemon versions do not allow containers to be removed
|
# New docker daemon versions do not allow containers to be removed
|
||||||
# if they are paused. Make sure we do not end up in an infinite loop.
|
# if they are paused. Make sure we do not end up in an infinite loop.
|
||||||
if count == 3:
|
if count == 3:
|
||||||
raise Exception(f"{exc} [tried to unpause three times]")
|
raise RuntimeError(f"{exc} [tried to unpause three times]")
|
||||||
count += 1
|
count += 1
|
||||||
# Unpause
|
# Unpause
|
||||||
try:
|
try:
|
||||||
self.unpause_container(client, container_id)
|
self.unpause_container(client, container_id)
|
||||||
except Exception as exc2:
|
except Exception as exc2:
|
||||||
raise Exception(f"{exc2} [while unpausing]")
|
raise RuntimeError(f"{exc2} [while unpausing]")
|
||||||
# Now try again
|
# Now try again
|
||||||
continue
|
continue
|
||||||
if (
|
if (
|
||||||
@ -1060,7 +1059,7 @@ def _get_network_id(module, client, network_name):
|
|||||||
network_id = network["Id"]
|
network_id = network["Id"]
|
||||||
break
|
break
|
||||||
return network_id
|
return network_id
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
client.fail(f"Error getting network id for {network_name} - {exc}")
|
client.fail(f"Error getting network id for {network_name} - {exc}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -134,6 +134,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
"The value of default_host_ip must be an empty string, an IPv4 address, "
|
"The value of default_host_ip must be an empty string, an IPv4 address, "
|
||||||
f'or an IPv6 address. Got "{self.param_default_host_ip}" instead.'
|
f'or an IPv6 address. Got "{self.param_default_host_ip}" instead.'
|
||||||
)
|
)
|
||||||
|
self.parameters = None
|
||||||
|
|
||||||
def _collect_all_options(self, active_options):
|
def _collect_all_options(self, active_options):
|
||||||
all_options = {}
|
all_options = {}
|
||||||
@ -480,7 +481,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.engine_driver.unpause_container(
|
self.engine_driver.unpause_container(
|
||||||
self.client, container.id
|
self.client, container.id
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Error {'pausing' if self.param_paused else 'unpausing'} container {container.id}: {exc}"
|
f"Error {'pausing' if self.param_paused else 'unpausing'} container {container.id}: {exc}"
|
||||||
)
|
)
|
||||||
@ -567,13 +568,13 @@ class ContainerManager(DockerBaseClass):
|
|||||||
if not image or self.param_pull == "always":
|
if not image or self.param_pull == "always":
|
||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
self.log("Pull the image.")
|
self.log("Pull the image.")
|
||||||
image, alreadyToLatest = self.engine_driver.pull_image(
|
image, already_to_latest = self.engine_driver.pull_image(
|
||||||
self.client,
|
self.client,
|
||||||
repository,
|
repository,
|
||||||
tag,
|
tag,
|
||||||
image_platform=self.module.params["platform"],
|
image_platform=self.module.params["platform"],
|
||||||
)
|
)
|
||||||
if alreadyToLatest:
|
if already_to_latest:
|
||||||
self.results["changed"] = False
|
self.results["changed"] = False
|
||||||
self.results["actions"].append(
|
self.results["actions"].append(
|
||||||
dict(pulled_image=f"{repository}:{tag}", changed=False)
|
dict(pulled_image=f"{repository}:{tag}", changed=False)
|
||||||
@ -950,7 +951,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.engine_driver.disconnect_container_from_network(
|
self.engine_driver.disconnect_container_from_network(
|
||||||
self.client, container.id, diff["parameter"]["id"]
|
self.client, container.id, diff["parameter"]["id"]
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Error disconnecting container from network {diff['parameter']['name']} - {exc}"
|
f"Error disconnecting container from network {diff['parameter']['name']} - {exc}"
|
||||||
)
|
)
|
||||||
@ -975,7 +976,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.engine_driver.connect_container_to_network(
|
self.engine_driver.connect_container_to_network(
|
||||||
self.client, container.id, diff["parameter"]["id"], params
|
self.client, container.id, diff["parameter"]["id"], params
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Error connecting container to network {diff['parameter']['name']} - {exc}"
|
f"Error connecting container to network {diff['parameter']['name']} - {exc}"
|
||||||
)
|
)
|
||||||
@ -989,7 +990,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.engine_driver.disconnect_container_from_network(
|
self.engine_driver.disconnect_container_from_network(
|
||||||
self.client, container.id, network["name"]
|
self.client, container.id, network["name"]
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Error disconnecting container from network {network['name']} - {exc}"
|
f"Error disconnecting container from network {network['name']} - {exc}"
|
||||||
)
|
)
|
||||||
@ -1027,7 +1028,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
container_id = self.engine_driver.create_container(
|
container_id = self.engine_driver.create_container(
|
||||||
self.client, self.param_name, create_parameters, networks=networks
|
self.client, self.param_name, create_parameters, networks=networks
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error creating container: {exc}")
|
self.fail(f"Error creating container: {exc}")
|
||||||
return self._get_container(container_id)
|
return self._get_container(container_id)
|
||||||
return new_container
|
return new_container
|
||||||
@ -1039,7 +1040,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
try:
|
try:
|
||||||
self.engine_driver.start_container(self.client, container_id)
|
self.engine_driver.start_container(self.client, container_id)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error starting container {container_id}: {exc}")
|
self.fail(f"Error starting container {container_id}: {exc}")
|
||||||
|
|
||||||
if self.module.params["detach"] is False:
|
if self.module.params["detach"] is False:
|
||||||
@ -1096,7 +1097,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
link=link,
|
link=link,
|
||||||
force=force,
|
force=force,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.client.fail(f"Error removing container {container_id}: {exc}")
|
self.client.fail(f"Error removing container {container_id}: {exc}")
|
||||||
|
|
||||||
def container_update(self, container_id, update_parameters):
|
def container_update(self, container_id, update_parameters):
|
||||||
@ -1112,7 +1113,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.engine_driver.update_container(
|
self.engine_driver.update_container(
|
||||||
self.client, container_id, update_parameters
|
self.client, container_id, update_parameters
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error updating container {container_id}: {exc}")
|
self.fail(f"Error updating container {container_id}: {exc}")
|
||||||
return self._get_container(container_id)
|
return self._get_container(container_id)
|
||||||
|
|
||||||
@ -1126,7 +1127,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.engine_driver.kill_container(
|
self.engine_driver.kill_container(
|
||||||
self.client, container_id, kill_signal=self.param_kill_signal
|
self.client, container_id, kill_signal=self.param_kill_signal
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error killing container {container_id}: {exc}")
|
self.fail(f"Error killing container {container_id}: {exc}")
|
||||||
|
|
||||||
def container_restart(self, container_id):
|
def container_restart(self, container_id):
|
||||||
@ -1139,7 +1140,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.engine_driver.restart_container(
|
self.engine_driver.restart_container(
|
||||||
self.client, container_id, self.module.params["stop_timeout"] or 10
|
self.client, container_id, self.module.params["stop_timeout"] or 10
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error restarting container {container_id}: {exc}")
|
self.fail(f"Error restarting container {container_id}: {exc}")
|
||||||
return self._get_container(container_id)
|
return self._get_container(container_id)
|
||||||
|
|
||||||
@ -1156,7 +1157,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.engine_driver.stop_container(
|
self.engine_driver.stop_container(
|
||||||
self.client, container_id, self.module.params["stop_timeout"]
|
self.client, container_id, self.module.params["stop_timeout"]
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error stopping container {container_id}: {exc}")
|
self.fail(f"Error stopping container {container_id}: {exc}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -78,14 +78,13 @@ class DockerSocketHandlerBase:
|
|||||||
if hasattr(self._sock, "recv"):
|
if hasattr(self._sock, "recv"):
|
||||||
try:
|
try:
|
||||||
data = self._sock.recv(262144)
|
data = self._sock.recv(262144)
|
||||||
except Exception as e:
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
# After calling self._sock.shutdown(), OpenSSL's/urllib3's
|
# After calling self._sock.shutdown(), OpenSSL's/urllib3's
|
||||||
# WrappedSocket seems to eventually raise ZeroReturnError in
|
# WrappedSocket seems to eventually raise ZeroReturnError in
|
||||||
# case of EOF
|
# case of EOF
|
||||||
if "OpenSSL.SSL.ZeroReturnError" in str(type(e)):
|
if "OpenSSL.SSL.ZeroReturnError" in str(type(e)):
|
||||||
self._eof = True
|
self._eof = True
|
||||||
return
|
return
|
||||||
else:
|
|
||||||
raise
|
raise
|
||||||
elif isinstance(self._sock, getattr(pysocket, "SocketIO")):
|
elif isinstance(self._sock, getattr(pysocket, "SocketIO")):
|
||||||
data = self._sock.read()
|
data = self._sock.read()
|
||||||
|
|||||||
@ -67,7 +67,6 @@ def write_to_socket(sock, data):
|
|||||||
# WrappedSocket (urllib3/contrib/pyopenssl) does not have `send`, but
|
# WrappedSocket (urllib3/contrib/pyopenssl) does not have `send`, but
|
||||||
# only `sendall`, which uses `_send_until_done` under the hood.
|
# only `sendall`, which uses `_send_until_done` under the hood.
|
||||||
return sock._send_until_done(data)
|
return sock._send_until_done(data)
|
||||||
elif hasattr(sock, "send"):
|
if hasattr(sock, "send"):
|
||||||
return sock.send(data)
|
return sock.send(data)
|
||||||
else:
|
|
||||||
return os.write(sock.fileno(), data)
|
return os.write(sock.fileno(), data)
|
||||||
|
|||||||
@ -74,22 +74,18 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient):
|
|||||||
swarm_info = json.loads(json_str)
|
swarm_info = json.loads(json_str)
|
||||||
if swarm_info["Swarm"]["NodeID"]:
|
if swarm_info["Swarm"]["NodeID"]:
|
||||||
return True
|
return True
|
||||||
if swarm_info["Swarm"]["LocalNodeState"] in (
|
return swarm_info["Swarm"]["LocalNodeState"] in (
|
||||||
"active",
|
"active",
|
||||||
"pending",
|
"pending",
|
||||||
"locked",
|
"locked",
|
||||||
):
|
)
|
||||||
return True
|
|
||||||
return False
|
return False
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
node_info = self.get_node_inspect(node_id=node_id)
|
node_info = self.get_node_inspect(node_id=node_id)
|
||||||
except APIError:
|
except APIError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if node_info["ID"] is not None:
|
return node_info["ID"] is not None
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_if_swarm_manager(self):
|
def check_if_swarm_manager(self):
|
||||||
"""
|
"""
|
||||||
@ -138,8 +134,7 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient):
|
|||||||
True if node is part of swarm but its state is down, False otherwise
|
True if node is part of swarm but its state is down, False otherwise
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if repeat_check < 1:
|
repeat_check = max(1, repeat_check)
|
||||||
repeat_check = 1
|
|
||||||
|
|
||||||
if node_id is None:
|
if node_id is None:
|
||||||
node_id = self.get_swarm_node_id()
|
node_id = self.get_swarm_node_id()
|
||||||
@ -179,7 +174,7 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient):
|
|||||||
if skip_missing:
|
if skip_missing:
|
||||||
return None
|
return None
|
||||||
self.fail(f"Error while reading from Swarm manager: {exc}")
|
self.fail(f"Error while reading from Swarm manager: {exc}")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting swarm node: {exc}")
|
self.fail(f"Error inspecting swarm node: {exc}")
|
||||||
|
|
||||||
json_str = json.dumps(node_info, ensure_ascii=False)
|
json_str = json.dumps(node_info, ensure_ascii=False)
|
||||||
@ -215,7 +210,7 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient):
|
|||||||
"Cannot inspect node: To inspect node execute module on Swarm Manager"
|
"Cannot inspect node: To inspect node execute module on Swarm Manager"
|
||||||
)
|
)
|
||||||
self.fail(f"Error while reading from Swarm manager: {exc}")
|
self.fail(f"Error while reading from Swarm manager: {exc}")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting swarm node: {exc}")
|
self.fail(f"Error inspecting swarm node: {exc}")
|
||||||
|
|
||||||
json_str = json.dumps(node_info, ensure_ascii=False)
|
json_str = json.dumps(node_info, ensure_ascii=False)
|
||||||
@ -295,7 +290,7 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient):
|
|||||||
"Cannot inspect service: To inspect service execute module on Swarm Manager"
|
"Cannot inspect service: To inspect service execute module on Swarm Manager"
|
||||||
)
|
)
|
||||||
self.fail(f"Error inspecting swarm service: {exc}")
|
self.fail(f"Error inspecting swarm service: {exc}")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting swarm service: {exc}")
|
self.fail(f"Error inspecting swarm service: {exc}")
|
||||||
|
|
||||||
json_str = json.dumps(service_info, ensure_ascii=False)
|
json_str = json.dumps(service_info, ensure_ascii=False)
|
||||||
|
|||||||
@ -56,13 +56,11 @@ DOCKER_COMMON_ARGS = dict(
|
|||||||
debug=dict(type="bool", default=False),
|
debug=dict(type="bool", default=False),
|
||||||
)
|
)
|
||||||
|
|
||||||
DOCKER_COMMON_ARGS_VARS = dict(
|
DOCKER_COMMON_ARGS_VARS = {
|
||||||
[
|
option_name: f"ansible_docker_{option_name}"
|
||||||
[option_name, f"ansible_docker_{option_name}"]
|
|
||||||
for option_name in DOCKER_COMMON_ARGS
|
for option_name in DOCKER_COMMON_ARGS
|
||||||
if option_name != "debug"
|
if option_name != "debug"
|
||||||
]
|
}
|
||||||
)
|
|
||||||
|
|
||||||
DOCKER_MUTUALLY_EXCLUSIVE = []
|
DOCKER_MUTUALLY_EXCLUSIVE = []
|
||||||
|
|
||||||
@ -100,9 +98,8 @@ def sanitize_result(data):
|
|||||||
"""
|
"""
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
return dict((k, sanitize_result(v)) for k, v in data.items())
|
return dict((k, sanitize_result(v)) for k, v in data.items())
|
||||||
elif isinstance(data, (list, tuple)):
|
if isinstance(data, (list, tuple)):
|
||||||
return [sanitize_result(v) for v in data]
|
return [sanitize_result(v) for v in data]
|
||||||
else:
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@ -196,10 +193,9 @@ def compare_generic(a, b, method, datatype):
|
|||||||
# Do proper comparison (both objects not None)
|
# Do proper comparison (both objects not None)
|
||||||
if datatype == "value":
|
if datatype == "value":
|
||||||
return a == b
|
return a == b
|
||||||
elif datatype == "list":
|
if datatype == "list":
|
||||||
if method == "strict":
|
if method == "strict":
|
||||||
return a == b
|
return a == b
|
||||||
else:
|
|
||||||
i = 0
|
i = 0
|
||||||
for v in a:
|
for v in a:
|
||||||
while i < len(b) and b[i] != v:
|
while i < len(b) and b[i] != v:
|
||||||
@ -208,19 +204,17 @@ def compare_generic(a, b, method, datatype):
|
|||||||
return False
|
return False
|
||||||
i += 1
|
i += 1
|
||||||
return True
|
return True
|
||||||
elif datatype == "dict":
|
if datatype == "dict":
|
||||||
if method == "strict":
|
if method == "strict":
|
||||||
return a == b
|
return a == b
|
||||||
else:
|
|
||||||
return compare_dict_allow_more_present(a, b)
|
return compare_dict_allow_more_present(a, b)
|
||||||
elif datatype == "set":
|
if datatype == "set":
|
||||||
set_a = set(a)
|
set_a = set(a)
|
||||||
set_b = set(b)
|
set_b = set(b)
|
||||||
if method == "strict":
|
if method == "strict":
|
||||||
return set_a == set_b
|
return set_a == set_b
|
||||||
else:
|
|
||||||
return set_b >= set_a
|
return set_b >= set_a
|
||||||
elif datatype == "set(dict)":
|
if datatype == "set(dict)":
|
||||||
for av in a:
|
for av in a:
|
||||||
found = False
|
found = False
|
||||||
for bv in b:
|
for bv in b:
|
||||||
@ -337,9 +331,8 @@ def clean_dict_booleans_for_docker_api(data, allow_sequences=False):
|
|||||||
def sanitize(value):
|
def sanitize(value):
|
||||||
if value is True:
|
if value is True:
|
||||||
return "true"
|
return "true"
|
||||||
elif value is False:
|
if value is False:
|
||||||
return "false"
|
return "false"
|
||||||
else:
|
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
result = dict()
|
result = dict()
|
||||||
|
|||||||
@ -243,7 +243,7 @@ class ConfigManager(DockerBaseClass):
|
|||||||
try:
|
try:
|
||||||
with open(data_src, "rb") as f:
|
with open(data_src, "rb") as f:
|
||||||
self.data = f.read()
|
self.data = f.read()
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.client.fail(f"Error while reading {data_src}: {exc}")
|
self.client.fail(f"Error while reading {data_src}: {exc}")
|
||||||
self.labels = parameters.get("labels")
|
self.labels = parameters.get("labels")
|
||||||
self.force = parameters.get("force")
|
self.force = parameters.get("force")
|
||||||
|
|||||||
@ -343,31 +343,31 @@ def retrieve_diff(
|
|||||||
diff["before_header"] = container_path
|
diff["before_header"] = container_path
|
||||||
diff["before"] = "(directory)"
|
diff["before"] = "(directory)"
|
||||||
return
|
return
|
||||||
elif regular_stat["mode"] & (1 << (32 - 4)) != 0:
|
if regular_stat["mode"] & (1 << (32 - 4)) != 0:
|
||||||
diff["before_header"] = container_path
|
diff["before_header"] = container_path
|
||||||
diff["before"] = "(temporary file)"
|
diff["before"] = "(temporary file)"
|
||||||
return
|
return
|
||||||
elif regular_stat["mode"] & (1 << (32 - 5)) != 0:
|
if regular_stat["mode"] & (1 << (32 - 5)) != 0:
|
||||||
diff["before_header"] = container_path
|
diff["before_header"] = container_path
|
||||||
diff["before"] = link_target
|
diff["before"] = link_target
|
||||||
return
|
return
|
||||||
elif regular_stat["mode"] & (1 << (32 - 6)) != 0:
|
if regular_stat["mode"] & (1 << (32 - 6)) != 0:
|
||||||
diff["before_header"] = container_path
|
diff["before_header"] = container_path
|
||||||
diff["before"] = "(device)"
|
diff["before"] = "(device)"
|
||||||
return
|
return
|
||||||
elif regular_stat["mode"] & (1 << (32 - 7)) != 0:
|
if regular_stat["mode"] & (1 << (32 - 7)) != 0:
|
||||||
diff["before_header"] = container_path
|
diff["before_header"] = container_path
|
||||||
diff["before"] = "(named pipe)"
|
diff["before"] = "(named pipe)"
|
||||||
return
|
return
|
||||||
elif regular_stat["mode"] & (1 << (32 - 8)) != 0:
|
if regular_stat["mode"] & (1 << (32 - 8)) != 0:
|
||||||
diff["before_header"] = container_path
|
diff["before_header"] = container_path
|
||||||
diff["before"] = "(socket)"
|
diff["before"] = "(socket)"
|
||||||
return
|
return
|
||||||
elif regular_stat["mode"] & (1 << (32 - 11)) != 0:
|
if regular_stat["mode"] & (1 << (32 - 11)) != 0:
|
||||||
diff["before_header"] = container_path
|
diff["before_header"] = container_path
|
||||||
diff["before"] = "(character device)"
|
diff["before"] = "(character device)"
|
||||||
return
|
return
|
||||||
elif regular_stat["mode"] & (1 << (32 - 13)) != 0:
|
if regular_stat["mode"] & (1 << (32 - 13)) != 0:
|
||||||
diff["before_header"] = container_path
|
diff["before_header"] = container_path
|
||||||
diff["before"] = "(unknown filesystem object)"
|
diff["before"] = "(unknown filesystem object)"
|
||||||
return
|
return
|
||||||
@ -1084,9 +1084,7 @@ def main():
|
|||||||
if client.module.params["content_is_b64"]:
|
if client.module.params["content_is_b64"]:
|
||||||
try:
|
try:
|
||||||
content = base64.b64decode(content)
|
content = base64.b64decode(content)
|
||||||
except (
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
Exception
|
|
||||||
) as e: # depending on Python version and error, multiple different exceptions can be raised
|
|
||||||
client.fail(f"Cannot Base64 decode the content option: {e}")
|
client.fail(f"Cannot Base64 decode the content option: {e}")
|
||||||
else:
|
else:
|
||||||
content = to_bytes(content)
|
content = to_bytes(content)
|
||||||
|
|||||||
@ -271,7 +271,6 @@ class DockerHostManager(DockerBaseClass):
|
|||||||
try:
|
try:
|
||||||
if self.verbose_output:
|
if self.verbose_output:
|
||||||
return self.client.df()
|
return self.client.df()
|
||||||
else:
|
|
||||||
return dict(LayersSize=self.client.df()["LayersSize"])
|
return dict(LayersSize=self.client.df()["LayersSize"])
|
||||||
except APIError as exc:
|
except APIError as exc:
|
||||||
self.client.fail(f"Error inspecting docker host: {exc}")
|
self.client.fail(f"Error inspecting docker host: {exc}")
|
||||||
|
|||||||
@ -618,7 +618,7 @@ class ImageManager(DockerBaseClass):
|
|||||||
except NotFound:
|
except NotFound:
|
||||||
# If the image vanished while we were trying to remove it, do not fail
|
# If the image vanished while we were trying to remove it, do not fail
|
||||||
pass
|
pass
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error removing image {name} - {exc}")
|
self.fail(f"Error removing image {name} - {exc}")
|
||||||
|
|
||||||
self.results["changed"] = True
|
self.results["changed"] = True
|
||||||
@ -656,12 +656,11 @@ class ImageManager(DockerBaseClass):
|
|||||||
|
|
||||||
if archived is None:
|
if archived is None:
|
||||||
return build_msg("since none present")
|
return build_msg("since none present")
|
||||||
elif (
|
if (
|
||||||
current_image_id == api_image_id(archived.image_id)
|
current_image_id == api_image_id(archived.image_id)
|
||||||
and [current_image_name] == archived.repo_tags
|
and [current_image_name] == archived.repo_tags
|
||||||
):
|
):
|
||||||
return None
|
return None
|
||||||
else:
|
|
||||||
name = ", ".join(archived.repo_tags)
|
name = ", ".join(archived.repo_tags)
|
||||||
|
|
||||||
return build_msg(
|
return build_msg(
|
||||||
@ -714,14 +713,14 @@ class ImageManager(DockerBaseClass):
|
|||||||
DEFAULT_DATA_CHUNK_SIZE,
|
DEFAULT_DATA_CHUNK_SIZE,
|
||||||
False,
|
False,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error getting image {image_name} - {exc}")
|
self.fail(f"Error getting image {image_name} - {exc}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(self.archive_path, "wb") as fd:
|
with open(self.archive_path, "wb") as fd:
|
||||||
for chunk in saved_image:
|
for chunk in saved_image:
|
||||||
fd.write(chunk)
|
fd.write(chunk)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error writing image archive {self.archive_path} - {exc}")
|
self.fail(f"Error writing image archive {self.archive_path} - {exc}")
|
||||||
|
|
||||||
self.results["image"] = image
|
self.results["image"] = image
|
||||||
@ -779,12 +778,12 @@ class ImageManager(DockerBaseClass):
|
|||||||
for line in self.client._stream_helper(response, decode=True):
|
for line in self.client._stream_helper(response, decode=True):
|
||||||
self.log(line, pretty_print=True)
|
self.log(line, pretty_print=True)
|
||||||
if line.get("errorDetail"):
|
if line.get("errorDetail"):
|
||||||
raise Exception(line["errorDetail"]["message"])
|
raise RuntimeError(line["errorDetail"]["message"])
|
||||||
status = line.get("status")
|
status = line.get("status")
|
||||||
if status == "Pushing":
|
if status == "Pushing":
|
||||||
changed = True
|
changed = True
|
||||||
self.results["changed"] = changed
|
self.results["changed"] = changed
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
if "unauthorized" in str(exc):
|
if "unauthorized" in str(exc):
|
||||||
if "authentication required" in str(exc):
|
if "authentication required" in str(exc):
|
||||||
self.fail(
|
self.fail(
|
||||||
@ -842,8 +841,8 @@ class ImageManager(DockerBaseClass):
|
|||||||
)
|
)
|
||||||
self.client._raise_for_status(res)
|
self.client._raise_for_status(res)
|
||||||
if res.status_code != 201:
|
if res.status_code != 201:
|
||||||
raise Exception("Tag operation failed.")
|
raise RuntimeError("Tag operation failed.")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error: failed to tag image - {exc}")
|
self.fail(f"Error: failed to tag image - {exc}")
|
||||||
self.results["image"] = self.client.find_image(name=repo, tag=repo_tag)
|
self.results["image"] = self.client.find_image(name=repo, tag=repo_tag)
|
||||||
if image and image["Id"] == self.results["image"]["Id"]:
|
if image and image["Id"] == self.results["image"]["Id"]:
|
||||||
@ -969,9 +968,9 @@ class ImageManager(DockerBaseClass):
|
|||||||
|
|
||||||
if line.get("error"):
|
if line.get("error"):
|
||||||
if line.get("errorDetail"):
|
if line.get("errorDetail"):
|
||||||
errorDetail = line.get("errorDetail")
|
error_detail = line.get("errorDetail")
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Error building {self.name} - code: {errorDetail.get('code')}, message: {errorDetail.get('message')}, logs: {build_output}"
|
f"Error building {self.name} - code: {error_detail.get('code')}, message: {error_detail.get('message')}, logs: {build_output}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.fail(
|
self.fail(
|
||||||
@ -1019,7 +1018,7 @@ class ImageManager(DockerBaseClass):
|
|||||||
f"Error loading image {self.name} - {exc}",
|
f"Error loading image {self.name} - {exc}",
|
||||||
stdout="\n".join(load_output),
|
stdout="\n".join(load_output),
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.client.fail(
|
self.client.fail(
|
||||||
f"Error loading image {self.name} - {exc}",
|
f"Error loading image {self.name} - {exc}",
|
||||||
stdout="\n".join(load_output),
|
stdout="\n".join(load_output),
|
||||||
@ -1076,7 +1075,6 @@ class ImageManager(DockerBaseClass):
|
|||||||
|
|
||||||
if is_image_name_id(self.name):
|
if is_image_name_id(self.name):
|
||||||
return self.client.find_image_by_id(self.name, accept_missing_image=True)
|
return self.client.find_image_by_id(self.name, accept_missing_image=True)
|
||||||
else:
|
|
||||||
return self.client.find_image(self.name, self.tag)
|
return self.client.find_image(self.name, self.tag)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -189,7 +189,7 @@ class ImageExportManager(DockerBaseClass):
|
|||||||
with open(self.path, "wb") as fd:
|
with open(self.path, "wb") as fd:
|
||||||
for chunk in chunks:
|
for chunk in chunks:
|
||||||
fd.write(chunk)
|
fd.write(chunk)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error writing image archive {self.path} - {exc}")
|
self.fail(f"Error writing image archive {self.path} - {exc}")
|
||||||
|
|
||||||
def export_images(self):
|
def export_images(self):
|
||||||
@ -205,7 +205,7 @@ class ImageExportManager(DockerBaseClass):
|
|||||||
DEFAULT_DATA_CHUNK_SIZE,
|
DEFAULT_DATA_CHUNK_SIZE,
|
||||||
False,
|
False,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error getting image {image_names[0]} - {exc}")
|
self.fail(f"Error getting image {image_names[0]} - {exc}")
|
||||||
else:
|
else:
|
||||||
self.log(f"Getting archive of images {image_names_str}")
|
self.log(f"Getting archive of images {image_names_str}")
|
||||||
@ -219,7 +219,7 @@ class ImageExportManager(DockerBaseClass):
|
|||||||
DEFAULT_DATA_CHUNK_SIZE,
|
DEFAULT_DATA_CHUNK_SIZE,
|
||||||
False,
|
False,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error getting images {image_names_str} - {exc}")
|
self.fail(f"Error getting images {image_names_str} - {exc}")
|
||||||
|
|
||||||
self.write_chunks(chunks)
|
self.write_chunks(chunks)
|
||||||
|
|||||||
@ -212,7 +212,7 @@ class ImageManager(DockerBaseClass):
|
|||||||
inspection = self.client.get_json("/images/{0}/json", image["Id"])
|
inspection = self.client.get_json("/images/{0}/json", image["Id"])
|
||||||
except NotFound:
|
except NotFound:
|
||||||
inspection = None
|
inspection = None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error inspecting image {image['Id']} - {exc}")
|
self.fail(f"Error inspecting image {image['Id']} - {exc}")
|
||||||
results.append(inspection)
|
results.append(inspection)
|
||||||
return results
|
return results
|
||||||
|
|||||||
@ -141,7 +141,7 @@ class ImageManager(DockerBaseClass):
|
|||||||
f"Error loading archive {self.path} - {exc}",
|
f"Error loading archive {self.path} - {exc}",
|
||||||
stdout="\n".join(load_output),
|
stdout="\n".join(load_output),
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.client.fail(
|
self.client.fail(
|
||||||
f"Error loading archive {self.path} - {exc}",
|
f"Error loading archive {self.path} - {exc}",
|
||||||
stdout="\n".join(load_output),
|
stdout="\n".join(load_output),
|
||||||
|
|||||||
@ -155,11 +155,11 @@ class ImagePusher(DockerBaseClass):
|
|||||||
for line in self.client._stream_helper(response, decode=True):
|
for line in self.client._stream_helper(response, decode=True):
|
||||||
self.log(line, pretty_print=True)
|
self.log(line, pretty_print=True)
|
||||||
if line.get("errorDetail"):
|
if line.get("errorDetail"):
|
||||||
raise Exception(line["errorDetail"]["message"])
|
raise RuntimeError(line["errorDetail"]["message"])
|
||||||
status = line.get("status")
|
status = line.get("status")
|
||||||
if status == "Pushing":
|
if status == "Pushing":
|
||||||
results["changed"] = True
|
results["changed"] = True
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
if "unauthorized" in str(exc):
|
if "unauthorized" in str(exc):
|
||||||
if "authentication required" in str(exc):
|
if "authentication required" in str(exc):
|
||||||
self.client.fail(
|
self.client.fail(
|
||||||
|
|||||||
@ -194,7 +194,7 @@ class ImageRemover(DockerBaseClass):
|
|||||||
except NotFound:
|
except NotFound:
|
||||||
# If the image vanished while we were trying to remove it, do not fail
|
# If the image vanished while we were trying to remove it, do not fail
|
||||||
res = []
|
res = []
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error removing image {name} - {exc}")
|
self.fail(f"Error removing image {name} - {exc}")
|
||||||
|
|
||||||
for entry in res:
|
for entry in res:
|
||||||
|
|||||||
@ -214,8 +214,8 @@ class ImageTagger(DockerBaseClass):
|
|||||||
)
|
)
|
||||||
self.client._raise_for_status(res)
|
self.client._raise_for_status(res)
|
||||||
if res.status_code != 201:
|
if res.status_code != 201:
|
||||||
raise Exception("Tag operation failed.")
|
raise RuntimeError("Tag operation failed.")
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(f"Error: failed to tag image as {name}:{tag} - {exc}")
|
self.fail(f"Error: failed to tag image as {name}:{tag} - {exc}")
|
||||||
|
|
||||||
return True, msg, tagged_image
|
return True, msg, tagged_image
|
||||||
|
|||||||
@ -309,7 +309,7 @@ class LoginManager(DockerBaseClass):
|
|||||||
self.log(f"Log into {self.registry_url} with username {self.username}")
|
self.log(f"Log into {self.registry_url} with username {self.username}")
|
||||||
try:
|
try:
|
||||||
response = self._login(self.reauthorize)
|
response = self._login(self.reauthorize)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Logging into {self.registry_url} for user {self.username} failed - {exc}"
|
f"Logging into {self.registry_url} for user {self.username} failed - {exc}"
|
||||||
)
|
)
|
||||||
@ -322,7 +322,7 @@ class LoginManager(DockerBaseClass):
|
|||||||
if not self.reauthorize and response["password"] != self.password:
|
if not self.reauthorize and response["password"] != self.password:
|
||||||
try:
|
try:
|
||||||
response = self._login(True)
|
response = self._login(True)
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.fail(
|
self.fail(
|
||||||
f"Logging into {self.registry_url} for user {self.username} failed - {exc}"
|
f"Logging into {self.registry_url} for user {self.username} failed - {exc}"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -359,7 +359,7 @@ def validate_cidr(cidr):
|
|||||||
"""
|
"""
|
||||||
if CIDR_IPV4.match(cidr):
|
if CIDR_IPV4.match(cidr):
|
||||||
return "ipv4"
|
return "ipv4"
|
||||||
elif CIDR_IPV6.match(cidr):
|
if CIDR_IPV6.match(cidr):
|
||||||
return "ipv6"
|
return "ipv6"
|
||||||
raise ValueError(f'"{cidr}" is not a valid CIDR')
|
raise ValueError(f'"{cidr}" is not a valid CIDR')
|
||||||
|
|
||||||
|
|||||||
@ -235,7 +235,7 @@ class SecretManager(DockerBaseClass):
|
|||||||
try:
|
try:
|
||||||
with open(data_src, "rb") as f:
|
with open(data_src, "rb") as f:
|
||||||
self.data = f.read()
|
self.data = f.read()
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
self.client.fail(f"Error while reading {data_src}: {exc}")
|
self.client.fail(f"Error while reading {data_src}: {exc}")
|
||||||
self.labels = parameters.get("labels")
|
self.labels = parameters.get("labels")
|
||||||
self.force = parameters.get("force")
|
self.force = parameters.get("force")
|
||||||
|
|||||||
@ -196,7 +196,6 @@ def docker_service_inspect(client, service_name):
|
|||||||
rc, out, err = client.call_cli("service", "inspect", service_name)
|
rc, out, err = client.call_cli("service", "inspect", service_name)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
return None
|
return None
|
||||||
else:
|
|
||||||
ret = json.loads(out)[0]["Spec"]
|
ret = json.loads(out)[0]["Spec"]
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|||||||
@ -323,6 +323,7 @@ class TaskParameters(DockerBaseClass):
|
|||||||
self.join_token = None
|
self.join_token = None
|
||||||
self.data_path_addr = None
|
self.data_path_addr = None
|
||||||
self.data_path_port = None
|
self.data_path_port = None
|
||||||
|
self.spec = None
|
||||||
|
|
||||||
# Spec
|
# Spec
|
||||||
self.snapshot_interval = None
|
self.snapshot_interval = None
|
||||||
|
|||||||
@ -932,7 +932,6 @@ def get_docker_environment(env, env_files):
|
|||||||
if not env_list:
|
if not env_list:
|
||||||
if env is not None or env_files is not None:
|
if env is not None or env_files is not None:
|
||||||
return []
|
return []
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
return sorted(env_list)
|
return sorted(env_list)
|
||||||
|
|
||||||
@ -992,14 +991,13 @@ def get_docker_networks(networks, network_ids):
|
|||||||
def get_nanoseconds_from_raw_option(name, value):
|
def get_nanoseconds_from_raw_option(name, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
elif isinstance(value, int):
|
if isinstance(value, int):
|
||||||
return value
|
return value
|
||||||
elif isinstance(value, str):
|
if isinstance(value, str):
|
||||||
try:
|
try:
|
||||||
return int(value)
|
return int(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return convert_duration_to_nanosecond(value)
|
return convert_duration_to_nanosecond(value)
|
||||||
else:
|
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Invalid type for {name} {value} ({type(value)}). Only string or int allowed."
|
f"Invalid type for {name} {value} ({type(value)}). Only string or int allowed."
|
||||||
)
|
)
|
||||||
@ -1046,8 +1044,7 @@ def has_list_changed(new_list, old_list, sort_lists=True, sort_key=None):
|
|||||||
|
|
||||||
if unsorted_list and isinstance(unsorted_list[0], dict):
|
if unsorted_list and isinstance(unsorted_list[0], dict):
|
||||||
if not sort_key:
|
if not sort_key:
|
||||||
raise Exception("A sort key was not specified when sorting list")
|
raise ValueError("A sort key was not specified when sorting list")
|
||||||
else:
|
|
||||||
return sorted(unsorted_list, key=lambda k: k[sort_key])
|
return sorted(unsorted_list, key=lambda k: k[sort_key])
|
||||||
|
|
||||||
# Either the list is empty or does not contain dictionaries
|
# Either the list is empty or does not contain dictionaries
|
||||||
@ -1081,7 +1078,6 @@ def has_list_changed(new_list, old_list, sort_lists=True, sort_key=None):
|
|||||||
old_item_casted = new_item_type(old_item)
|
old_item_casted = new_item_type(old_item)
|
||||||
if new_item != old_item_casted:
|
if new_item != old_item_casted:
|
||||||
return True
|
return True
|
||||||
else:
|
|
||||||
continue
|
continue
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
# Fallback to assuming the strings are different
|
# Fallback to assuming the strings are different
|
||||||
@ -1374,7 +1370,7 @@ class DockerService(DockerBaseClass):
|
|||||||
try:
|
try:
|
||||||
memory = human_to_bytes(memory)
|
memory = human_to_bytes(memory)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
raise Exception(f"Failed to convert limit_memory to bytes: {exc}")
|
raise ValueError(f"Failed to convert limit_memory to bytes: {exc}")
|
||||||
return {
|
return {
|
||||||
"limit_cpu": cpus,
|
"limit_cpu": cpus,
|
||||||
"limit_memory": memory,
|
"limit_memory": memory,
|
||||||
@ -1396,7 +1392,7 @@ class DockerService(DockerBaseClass):
|
|||||||
try:
|
try:
|
||||||
memory = human_to_bytes(memory)
|
memory = human_to_bytes(memory)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
raise Exception(f"Failed to convert reserve_memory to bytes: {exc}")
|
raise ValueError(f"Failed to convert reserve_memory to bytes: {exc}")
|
||||||
return {
|
return {
|
||||||
"reserve_cpu": cpus,
|
"reserve_cpu": cpus,
|
||||||
"reserve_memory": memory,
|
"reserve_memory": memory,
|
||||||
@ -1470,7 +1466,7 @@ class DockerService(DockerBaseClass):
|
|||||||
for index, item in invalid_items
|
for index, item in invalid_items
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
raise Exception(
|
raise ValueError(
|
||||||
"All items in a command list need to be strings. "
|
"All items in a command list need to be strings. "
|
||||||
f"Check quoting. Invalid items: {errors}."
|
f"Check quoting. Invalid items: {errors}."
|
||||||
)
|
)
|
||||||
@ -2339,7 +2335,7 @@ class DockerServiceManager:
|
|||||||
ds.mode = to_text("replicated-job", encoding="utf-8")
|
ds.mode = to_text("replicated-job", encoding="utf-8")
|
||||||
ds.replicas = mode["ReplicatedJob"]["TotalCompletions"]
|
ds.replicas = mode["ReplicatedJob"]["TotalCompletions"]
|
||||||
else:
|
else:
|
||||||
raise Exception(f"Unknown service mode: {mode}")
|
raise ValueError(f"Unknown service mode: {mode}")
|
||||||
|
|
||||||
raw_data_mounts = task_template_data["ContainerSpec"].get("Mounts")
|
raw_data_mounts = task_template_data["ContainerSpec"].get("Mounts")
|
||||||
if raw_data_mounts:
|
if raw_data_mounts:
|
||||||
@ -2510,7 +2506,7 @@ class DockerServiceManager:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
current_service = self.get_service(module.params["name"])
|
current_service = self.get_service(module.params["name"])
|
||||||
except Exception as e:
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
self.client.fail(
|
self.client.fail(
|
||||||
f"Error looking for service named {module.params['name']}: {e}"
|
f"Error looking for service named {module.params['name']}: {e}"
|
||||||
)
|
)
|
||||||
@ -2527,7 +2523,7 @@ class DockerServiceManager:
|
|||||||
network_ids,
|
network_ids,
|
||||||
self.client,
|
self.client,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
return self.client.fail(f"Error parsing module parameters: {e}")
|
return self.client.fail(f"Error parsing module parameters: {e}")
|
||||||
|
|
||||||
changed = False
|
changed = False
|
||||||
|
|||||||
@ -87,7 +87,7 @@ def get_existing_volume(client, volume_name):
|
|||||||
return client.get_json("/volumes/{0}", volume_name)
|
return client.get_json("/volumes/{0}", volume_name)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||||
client.fail(f"Error inspecting volume: {exc}")
|
client.fail(f"Error inspecting volume: {exc}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,4 @@ class AnsibleDockerClient(AnsibleDockerClientBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _get_params(self):
|
def _get_params(self):
|
||||||
return dict(
|
return {option: self.plugin.get_option(option) for option in DOCKER_COMMON_ARGS}
|
||||||
[(option, self.plugin.get_option(option)) for option in DOCKER_COMMON_ARGS]
|
|
||||||
)
|
|
||||||
|
|||||||
@ -37,6 +37,4 @@ class AnsibleDockerClient(AnsibleDockerClientBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _get_params(self):
|
def _get_params(self):
|
||||||
return dict(
|
return {option: self.plugin.get_option(option) for option in DOCKER_COMMON_ARGS}
|
||||||
[(option, self.plugin.get_option(option)) for option in DOCKER_COMMON_ARGS]
|
|
||||||
)
|
|
||||||
|
|||||||
@ -27,15 +27,15 @@ def make_unsafe(value):
|
|||||||
|
|
||||||
if isinstance(value, Mapping):
|
if isinstance(value, Mapping):
|
||||||
return dict((make_unsafe(key), make_unsafe(val)) for key, val in value.items())
|
return dict((make_unsafe(key), make_unsafe(val)) for key, val in value.items())
|
||||||
elif isinstance(value, Set):
|
if isinstance(value, Set):
|
||||||
return set(make_unsafe(elt) for elt in value)
|
return set(make_unsafe(elt) for elt in value)
|
||||||
elif is_sequence(value):
|
if is_sequence(value):
|
||||||
return type(value)(make_unsafe(elt) for elt in value)
|
return type(value)(make_unsafe(elt) for elt in value)
|
||||||
elif isinstance(value, bytes):
|
if isinstance(value, bytes):
|
||||||
if _RE_TEMPLATE_CHARS_BYTES.search(value):
|
if _RE_TEMPLATE_CHARS_BYTES.search(value):
|
||||||
value = _make_unsafe(value)
|
value = _make_unsafe(value)
|
||||||
return value
|
return value
|
||||||
elif isinstance(value, str):
|
if isinstance(value, str):
|
||||||
if _RE_TEMPLATE_CHARS.search(value):
|
if _RE_TEMPLATE_CHARS.search(value):
|
||||||
value = _make_unsafe(value)
|
value = _make_unsafe(value)
|
||||||
return value
|
return value
|
||||||
|
|||||||
@ -72,7 +72,9 @@ def response(
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def fake_resolve_authconfig(authconfig, registry=None, *args, **kwargs):
|
def fake_resolve_authconfig(
|
||||||
|
authconfig, registry=None, *args, **kwargs
|
||||||
|
): # pylint: disable=keyword-arg-before-vararg
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@ -87,7 +89,7 @@ def fake_resp(method, url, *args, **kwargs):
|
|||||||
elif (url, method) in fake_api.fake_responses:
|
elif (url, method) in fake_api.fake_responses:
|
||||||
key = (url, method)
|
key = (url, method)
|
||||||
if not key:
|
if not key:
|
||||||
raise Exception(f"{method} {url}")
|
raise NotImplementedError(f"{method} {url}")
|
||||||
status_code, content = fake_api.fake_responses[key]()
|
status_code, content = fake_api.fake_responses[key]()
|
||||||
return response(status_code=status_code, content=content)
|
return response(status_code=status_code, content=content)
|
||||||
|
|
||||||
@ -115,8 +117,8 @@ def fake_read_from_socket(self, response, stream, tty=False, demux=False):
|
|||||||
return b""
|
return b""
|
||||||
|
|
||||||
|
|
||||||
url_base = f"{fake_api.prefix}/"
|
url_base = f"{fake_api.prefix}/" # pylint: disable=invalid-name
|
||||||
url_prefix = f"{url_base}v{DEFAULT_DOCKER_API_VERSION}/"
|
url_prefix = f"{url_base}v{DEFAULT_DOCKER_API_VERSION}/" # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
class BaseAPIClientTest(unittest.TestCase):
|
class BaseAPIClientTest(unittest.TestCase):
|
||||||
@ -482,7 +484,7 @@ class TCPSocketStreamTest(unittest.TestCase):
|
|||||||
stderr_data = cls.stderr_data
|
stderr_data = cls.stderr_data
|
||||||
|
|
||||||
class Handler(BaseHTTPRequestHandler):
|
class Handler(BaseHTTPRequestHandler):
|
||||||
def do_POST(self):
|
def do_POST(self): # pylint: disable=invalid-name
|
||||||
resp_data = self.get_resp_data()
|
resp_data = self.get_resp_data()
|
||||||
self.send_response(101)
|
self.send_response(101)
|
||||||
self.send_header("Content-Type", "application/vnd.docker.raw-stream")
|
self.send_header("Content-Type", "application/vnd.docker.raw-stream")
|
||||||
@ -498,15 +500,14 @@ class TCPSocketStreamTest(unittest.TestCase):
|
|||||||
path = self.path.split("/")[-1]
|
path = self.path.split("/")[-1]
|
||||||
if path == "tty":
|
if path == "tty":
|
||||||
return stdout_data + stderr_data
|
return stdout_data + stderr_data
|
||||||
elif path == "no-tty":
|
if path == "no-tty":
|
||||||
data = b""
|
data = b""
|
||||||
data += self.frame_header(1, stdout_data)
|
data += self.frame_header(1, stdout_data)
|
||||||
data += stdout_data
|
data += stdout_data
|
||||||
data += self.frame_header(2, stderr_data)
|
data += self.frame_header(2, stderr_data)
|
||||||
data += stderr_data
|
data += stderr_data
|
||||||
return data
|
return data
|
||||||
else:
|
raise NotImplementedError(f"Unknown path {path}")
|
||||||
raise Exception(f"Unknown path {path}")
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def frame_header(stream, data):
|
def frame_header(stream, data):
|
||||||
@ -604,6 +605,7 @@ class DisableSocketTest(unittest.TestCase):
|
|||||||
class DummySocket:
|
class DummySocket:
|
||||||
def __init__(self, timeout=60):
|
def __init__(self, timeout=60):
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
self._sock = None
|
||||||
|
|
||||||
def settimeout(self, timeout):
|
def settimeout(self, timeout):
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
|||||||
@ -537,9 +537,9 @@ def post_fake_secret():
|
|||||||
|
|
||||||
|
|
||||||
# Maps real api url to fake response callback
|
# Maps real api url to fake response callback
|
||||||
prefix = "http+docker://localhost"
|
prefix = "http+docker://localhost" # pylint: disable=invalid-name
|
||||||
if constants.IS_WINDOWS_PLATFORM:
|
if constants.IS_WINDOWS_PLATFORM:
|
||||||
prefix = "http+docker://localnpipe"
|
prefix = "http+docker://localnpipe" # pylint: disable=invalid-name
|
||||||
|
|
||||||
fake_responses = {
|
fake_responses = {
|
||||||
f"{prefix}/version": get_fake_version,
|
f"{prefix}/version": get_fake_version,
|
||||||
|
|||||||
@ -417,7 +417,7 @@ class TarTest(unittest.TestCase):
|
|||||||
self.addCleanup(shutil.rmtree, base)
|
self.addCleanup(shutil.rmtree, base)
|
||||||
|
|
||||||
with tar(base, exclude=exclude) as archive:
|
with tar(base, exclude=exclude) as archive:
|
||||||
tar_data = tarfile.open(fileobj=archive)
|
with tarfile.open(fileobj=archive) as tar_data:
|
||||||
assert sorted(tar_data.getnames()) == sorted(expected_names)
|
assert sorted(tar_data.getnames()) == sorted(expected_names)
|
||||||
|
|
||||||
def test_tar_with_empty_directory(self):
|
def test_tar_with_empty_directory(self):
|
||||||
@ -426,7 +426,7 @@ class TarTest(unittest.TestCase):
|
|||||||
for d in ["foo", "bar"]:
|
for d in ["foo", "bar"]:
|
||||||
os.makedirs(os.path.join(base, d))
|
os.makedirs(os.path.join(base, d))
|
||||||
with tar(base) as archive:
|
with tar(base) as archive:
|
||||||
tar_data = tarfile.open(fileobj=archive)
|
with tarfile.open(fileobj=archive) as tar_data:
|
||||||
assert sorted(tar_data.getnames()) == ["bar", "foo"]
|
assert sorted(tar_data.getnames()) == ["bar", "foo"]
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
@ -454,7 +454,7 @@ class TarTest(unittest.TestCase):
|
|||||||
os.makedirs(os.path.join(base, "bar"))
|
os.makedirs(os.path.join(base, "bar"))
|
||||||
os.symlink("../foo", os.path.join(base, "bar/foo"))
|
os.symlink("../foo", os.path.join(base, "bar/foo"))
|
||||||
with tar(base) as archive:
|
with tar(base) as archive:
|
||||||
tar_data = tarfile.open(fileobj=archive)
|
with tarfile.open(fileobj=archive) as tar_data:
|
||||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||||
|
|
||||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||||
@ -465,7 +465,7 @@ class TarTest(unittest.TestCase):
|
|||||||
os.makedirs(os.path.join(base, d))
|
os.makedirs(os.path.join(base, d))
|
||||||
os.symlink("../foo", os.path.join(base, "bar/foo"))
|
os.symlink("../foo", os.path.join(base, "bar/foo"))
|
||||||
with tar(base) as archive:
|
with tar(base) as archive:
|
||||||
tar_data = tarfile.open(fileobj=archive)
|
with tarfile.open(fileobj=archive) as tar_data:
|
||||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||||
|
|
||||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||||
@ -477,7 +477,7 @@ class TarTest(unittest.TestCase):
|
|||||||
|
|
||||||
os.symlink("../baz", os.path.join(base, "bar/foo"))
|
os.symlink("../baz", os.path.join(base, "bar/foo"))
|
||||||
with tar(base) as archive:
|
with tar(base) as archive:
|
||||||
tar_data = tarfile.open(fileobj=archive)
|
with tarfile.open(fileobj=archive) as tar_data:
|
||||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||||
|
|
||||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No UNIX sockets on Win32")
|
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No UNIX sockets on Win32")
|
||||||
@ -490,7 +490,7 @@ class TarTest(unittest.TestCase):
|
|||||||
self.addCleanup(sock.close)
|
self.addCleanup(sock.close)
|
||||||
sock.bind(os.path.join(base, "test.sock"))
|
sock.bind(os.path.join(base, "test.sock"))
|
||||||
with tar(base) as archive:
|
with tar(base) as archive:
|
||||||
tar_data = tarfile.open(fileobj=archive)
|
with tarfile.open(fileobj=archive) as tar_data:
|
||||||
assert sorted(tar_data.getnames()) == ["bar", "foo"]
|
assert sorted(tar_data.getnames()) == ["bar", "foo"]
|
||||||
|
|
||||||
def tar_test_negative_mtime_bug(self):
|
def tar_test_negative_mtime_bug(self):
|
||||||
@ -501,7 +501,7 @@ class TarTest(unittest.TestCase):
|
|||||||
f.write("Invisible Full Moon")
|
f.write("Invisible Full Moon")
|
||||||
os.utime(filename, (12345, -3600.0))
|
os.utime(filename, (12345, -3600.0))
|
||||||
with tar(base) as archive:
|
with tar(base) as archive:
|
||||||
tar_data = tarfile.open(fileobj=archive)
|
with tarfile.open(fileobj=archive) as tar_data:
|
||||||
assert tar_data.getnames() == ["th.txt"]
|
assert tar_data.getnames() == ["th.txt"]
|
||||||
assert tar_data.getmember("th.txt").mtime == -3600
|
assert tar_data.getmember("th.txt").mtime == -3600
|
||||||
|
|
||||||
@ -513,7 +513,7 @@ class TarTest(unittest.TestCase):
|
|||||||
self.addCleanup(shutil.rmtree, base)
|
self.addCleanup(shutil.rmtree, base)
|
||||||
os.symlink(os.path.join(base, "b"), os.path.join(base, "a/c/b"))
|
os.symlink(os.path.join(base, "b"), os.path.join(base, "a/c/b"))
|
||||||
with tar(base) as archive:
|
with tar(base) as archive:
|
||||||
tar_data = tarfile.open(fileobj=archive)
|
with tarfile.open(fileobj=archive) as tar_data:
|
||||||
names = tar_data.getnames()
|
names = tar_data.getnames()
|
||||||
for member in dirs + files:
|
for member in dirs + files:
|
||||||
assert member in names
|
assert member in names
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import typing as t
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from pytest import fixture, mark
|
from pytest import fixture, mark
|
||||||
@ -26,6 +27,7 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
class FindConfigFileTest(unittest.TestCase):
|
class FindConfigFileTest(unittest.TestCase):
|
||||||
|
mkdir: t.Callable[[str], os.PathLike[str]]
|
||||||
|
|
||||||
@fixture(autouse=True)
|
@fixture(autouse=True)
|
||||||
def tmpdir(self, tmpdir):
|
def tmpdir(self, tmpdir):
|
||||||
|
|||||||
@ -205,9 +205,8 @@ class ParseEnvFileTest(unittest.TestCase):
|
|||||||
of 'file_content' and returns the filename.
|
of 'file_content' and returns the filename.
|
||||||
Don't forget to unlink the file with os.unlink() after.
|
Don't forget to unlink the file with os.unlink() after.
|
||||||
"""
|
"""
|
||||||
local_tempfile = tempfile.NamedTemporaryFile(delete=False)
|
with tempfile.NamedTemporaryFile(delete=False) as local_tempfile:
|
||||||
local_tempfile.write(file_content.encode("UTF-8"))
|
local_tempfile.write(file_content.encode("UTF-8"))
|
||||||
local_tempfile.close()
|
|
||||||
return local_tempfile.name
|
return local_tempfile.name
|
||||||
|
|
||||||
def test_parse_env_file_proper(self):
|
def test_parse_env_file_proper(self):
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
# pylint: disable=line-too-long
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from ansible_collections.community.docker.plugins.module_utils._compose_v2 import (
|
from ansible_collections.community.docker.plugins.module_utils._compose_v2 import (
|
||||||
|
|||||||
@ -50,8 +50,7 @@ def write_irrelevant_tar(file_name):
|
|||||||
:type file_name: str
|
:type file_name: str
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tf = tarfile.open(file_name, "w")
|
with tarfile.open(file_name, "w") as tf:
|
||||||
try:
|
|
||||||
with TemporaryFile() as f:
|
with TemporaryFile() as f:
|
||||||
f.write("Hello, world.".encode("utf-8"))
|
f.write("Hello, world.".encode("utf-8"))
|
||||||
|
|
||||||
@ -60,6 +59,3 @@ def write_irrelevant_tar(file_name):
|
|||||||
|
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
tf.addfile(ti, f)
|
tf.addfile(ti, f)
|
||||||
|
|
||||||
finally:
|
|
||||||
tf.close()
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user