update ansible collections sops, docker and debops
All checks were successful
/ build (pull_request) Successful in 28s
/ Ansible Lint (push) Successful in 2m36s
/ Ansible Lint (pull_request) Successful in 2m41s

This commit is contained in:
chris 2026-09-21 22:26:20 +02:00
commit e31ee5e39c
Signed by: c6ristian
SSH key fingerprint: SHA256:B3m+yzpaxGXSEcDBpPHfvza/DNC0wuX+CKMeGq8wgak
910 changed files with 27667 additions and 19786 deletions

View file

@ -51,6 +51,12 @@ options:
type: bool
default: false
version_added: 3.12.0
ignore_pull_failures:
description:
- If set to V(true), will pull what it can and ignores images with pull failures.
type: bool
default: false
version_added: 5.1.0
include_deps:
description:
- If set to V(true), also pull services that are declared as dependencies.
@ -132,6 +138,7 @@ class PullManager(BaseComposeManager):
self.policy: t.Literal["always", "missing"] = parameters["policy"]
self.ignore_buildable: bool = parameters["ignore_buildable"]
self.ignore_pull_failures: bool = parameters["ignore_pull_failures"]
self.include_deps: bool = parameters["include_deps"]
self.services: list[str] = parameters["services"] or []
@ -152,6 +159,8 @@ class PullManager(BaseComposeManager):
args.extend(["--policy", self.policy])
if self.ignore_buildable:
args.append("--ignore-buildable")
if self.ignore_pull_failures:
args.append("--ignore-pull-failures")
if self.include_deps:
args.append("--include-deps")
if dry_run:
@ -187,6 +196,7 @@ def main() -> None:
"default": "always",
},
"ignore_buildable": {"type": "bool", "default": False},
"ignore_pull_failures": {"type": "bool", "default": False},
"include_deps": {"type": "bool", "default": False},
"services": {"type": "list", "elements": "str"},
}

View file

@ -274,7 +274,7 @@ def main() -> None:
stdout: bytes | None
stderr: bytes | None
if stdin and not detach:
exec_socket = client.post_json_to_stream_socket(
exec_socket, response = client.post_json_to_stream_socket(
"/exec/{0}/start", exec_id, data=data
)
try:
@ -286,7 +286,7 @@ def main() -> None:
stdout, stderr = exec_socket_handler.consume()
finally:
exec_socket.close()
response.close()
elif tty:
stdout, stderr = client.post_json_to_stream(
"/exec/{0}/start",

View file

@ -995,7 +995,7 @@ class ImageManager(DockerBaseClass):
self.log(line, pretty_print=True)
self._extract_output_line(line, build_output)
if line.get("error"):
if line.get("error") or line.get("errorDetail"):
if line.get("errorDetail"):
error_detail = line.get("errorDetail")
self.fail(

View file

@ -31,9 +31,12 @@ attributes:
details:
- Whether the module is idempotent depends on the storage API used for images,
which determines how the image ID is computed. The idempotency check needs
that the image ID equals the ID stored in archive's C(manifest.json).
the image ID to equal the ID stored in archive's C(manifest.json).
This seemed to have worked fine with the default storage backend up to Docker 28,
but seems to have changed in Docker 29.
- This module is B(not idempotent) when used with multi-architecture images,
regardless of Docker version.
- Full idempotency requires Docker 28 or earlier B(and) a single-architecture image.
options:
names:
@ -61,6 +64,13 @@ options:
- Export the image even if the C(.tar) file already exists and seems to contain the right image.
type: bool
default: false
platform:
description:
- Ask for this specific platform when exporting.
- For example, C(linux/amd64), C(linux/arm64).
- Requires Docker API 1.48 or newer.
type: str
version_added: 5.2.0
requirements:
- "Docker API >= 1.25"
@ -98,6 +108,7 @@ images:
sample: []
"""
import json
import traceback
import typing as t
@ -119,6 +130,9 @@ from ansible_collections.community.docker.plugins.module_utils._image_archive im
api_image_id,
load_archived_image_manifest,
)
from ansible_collections.community.docker.plugins.module_utils._platform import (
_Platform,
)
from ansible_collections.community.docker.plugins.module_utils._util import (
DockerBaseClass,
is_image_name_id,
@ -137,6 +151,7 @@ class ImageExportManager(DockerBaseClass):
self.path = parameters["path"]
self.force = parameters["force"]
self.tag = parameters["tag"]
self.platform = parameters["platform"]
if not is_valid_tag(self.tag, allow_empty=True):
self.fail(f'"{self.tag}" is not a valid docker tag')
@ -198,15 +213,31 @@ class ImageExportManager(DockerBaseClass):
except Exception as exc: # pylint: disable=broad-exception-caught
self.fail(f"Error writing image archive {self.path} - {exc}")
def _platform_param(self) -> str:
platform = _Platform.parse_platform_string(self.platform)
platform_spec: dict[str, str] = {}
if platform.os:
platform_spec["os"] = platform.os
if platform.arch:
platform_spec["architecture"] = platform.arch
if platform.variant:
platform_spec["variant"] = platform.variant
return json.dumps(platform_spec)
def export_images(self) -> None:
image_names = [name["joined"] for name in self.names]
image_names_str = ", ".join(image_names)
if len(image_names) == 1:
self.log(f"Getting archive of image {image_names[0]}")
params: dict[str, t.Any] = {}
if self.platform:
params["platform"] = self._platform_param()
try:
chunks = self.client._stream_raw_result(
self.client._get(
self.client._url("/images/{0}/get", image_names[0]), stream=True
self.client._url("/images/{0}/get", image_names[0]),
stream=True,
params=params,
),
chunk_size=DEFAULT_DATA_CHUNK_SIZE,
decode=False,
@ -215,12 +246,15 @@ class ImageExportManager(DockerBaseClass):
self.fail(f"Error getting image {image_names[0]} - {exc}")
else:
self.log(f"Getting archive of images {image_names_str}")
params = {"names": image_names}
if self.platform:
params["platform"] = self._platform_param()
try:
chunks = self.client._stream_raw_result(
self.client._get(
self.client._url("/images/get"),
stream=True,
params={"names": image_names},
params=params,
),
chunk_size=DEFAULT_DATA_CHUNK_SIZE,
decode=False,
@ -277,11 +311,17 @@ def main() -> None:
"aliases": ["name"],
},
"tag": {"type": "str", "default": "latest"},
"platform": {"type": "str"},
}
option_minimal_versions = {
"platform": {"docker_api_version": "1.48"},
}
client = AnsibleDockerClient(
argument_spec=argument_spec,
supports_check_mode=True,
option_minimal_versions=option_minimal_versions,
)
try:

View file

@ -189,7 +189,7 @@ class DockerFileStore:
if not server_creds:
raise CredentialsNotFound("No matching credentials")
(username, password) = decode_auth(server_creds["auth"])
username, password = decode_auth(server_creds["auth"])
return {"Username": username, "Secret": password}

View file

@ -36,6 +36,10 @@ options:
description:
- List arguments to be passed to the container.
- Corresponds to the C(ARG) parameter of C(docker service create).
- When O(command_as_args=true), these values are appended after O(command)
and both are sent as ContainerSpec.Args (matching the Docker CLI).
- When O(command_as_args=false), O(args) is sent as C(ContainerSpec.Args)
while O(command) is sent as ContainerSpec.Command.
type: list
elements: str
command:
@ -43,7 +47,28 @@ options:
- Command to execute when the container starts.
- A command may be either a string or a list or a list of strings.
- Corresponds to the C(COMMAND) parameter of C(docker service create).
- When O(command_as_args=false), this is sent as C(ContainerSpec.Command),
which replaces the image C(ENTRYPOINT). This is the historical module behavior.
- When O(command_as_args=true), this is combined with O(args) and sent as
C(ContainerSpec.Args) (same as the Docker CLI
C(docker service create IMAGE [COMMAND] [ARG...])), so the image C(ENTRYPOINT)
is preserved. Use this for flag-style commands (for example V(--config.file=...))
that must be passed as arguments to the image entrypoint
(see U(https://github.com/ansible-collections/community.docker/issues/1044)).
type: raw
command_as_args:
description:
- Controls how O(command) and O(args) are mapped to the service C(ContainerSpec).
- If V(false) (default), O(command) is written to C(ContainerSpec.Command) and
O(args) to C(ContainerSpec.Args). This matches the historical module behavior
(ContainerSpec.Command replaces the image C(ENTRYPOINT)).
- If V(true), O(command) and O(args) are concatenated and written only to
C(ContainerSpec.Args), matching C(docker service create IMAGE [COMMAND] [ARG...])
so the image C(ENTRYPOINT) is preserved.
- The current default will eventually be depreacted and change to V(true).
type: bool
default: false
version_added: 5.3.0
configs:
description:
- List of dictionaries describing the service configs.
@ -696,7 +721,7 @@ rebuilt:
EXAMPLES = r"""
---
- name: Set command and arguments
- name: Set command and arguments (historical mapping)
community.docker.docker_swarm_service:
name: myservice
image: alpine
@ -704,6 +729,14 @@ EXAMPLES = r"""
args:
- "3600"
- name: Pass flags to the image ENTRYPOINT (CLI-compatible mapping)
community.docker.docker_swarm_service:
name: loki
image: grafana/loki:main
command_as_args: true
command:
- '-config.file=/etc/loki/loki-config.yaml'
- name: Set a bind mount
community.docker.docker_swarm_service:
name: myservice
@ -1054,6 +1087,22 @@ def has_dict_changed(
return False
def _combine_command_args(
command: list[str] | None, args: list[str] | None
) -> list[str] | None:
"""
Combine ansible command + args into a single argv list.
Matches docker CLI ``service create IMAGE [COMMAND] [ARG...]``, which places
all post-image tokens into ContainerSpec.Args (preserving ENTRYPOINT).
"""
if command is None:
return args
if args is None:
return command
return command + args
def has_list_changed(
new_list: list[t.Any] | None,
old_list: list[t.Any] | None,
@ -1161,6 +1210,7 @@ class DockerService(DockerBaseClass):
self.image: str | None = ""
self.command: t.Any = None
self.args: list[str] | None = None
self.command_as_args: bool = False
self.endpoint_mode: t.Literal["vip", "dnsrr"] | None = None
self.dns: list[str] | None = None
self.healthcheck: dict[str, t.Any] | None = None
@ -1473,6 +1523,7 @@ class DockerService(DockerBaseClass):
s = DockerService(client.docker_api_version, client.docker_py_version)
s.image = image_digest
s.args = ap["args"]
s.command_as_args = ap["command_as_args"]
s.endpoint_mode = ap["endpoint_mode"]
s.dns = ap["dns"]
s.dns_search = ap["dns_search"]
@ -1675,10 +1726,21 @@ class DockerService(DockerBaseClass):
needs_rebuild = not self.can_update_networks
if self.replicas != os.replicas:
differences.add("replicas", parameter=self.replicas, active=os.replicas)
if has_list_changed(self.command, os.command, sort_lists=False):
differences.add("command", parameter=self.command, active=os.command)
if has_list_changed(self.args, os.args, sort_lists=False):
differences.add("args", parameter=self.args, active=os.args)
if self.command_as_args:
# command + args are stored as ContainerSpec.Args (CLI-compatible).
# Older module versions wrote command to ContainerSpec.Command,
# so compare the combined command line from either field.
desired_cmdline = _combine_command_args(self.command, self.args)
active_cmdline = _combine_command_args(os.command, os.args)
if has_list_changed(desired_cmdline, active_cmdline, sort_lists=False):
differences.add(
"command", parameter=desired_cmdline, active=active_cmdline
)
else:
if has_list_changed(self.command, os.command, sort_lists=False):
differences.add("command", parameter=self.command, active=os.command)
if has_list_changed(self.args, os.args, sort_lists=False):
differences.add("args", parameter=self.args, active=os.args)
if has_list_changed(self.constraints, os.constraints):
differences.add(
"constraints", parameter=self.constraints, active=os.constraints
@ -1999,10 +2061,20 @@ class DockerService(DockerBaseClass):
dns_config = types.DNSConfig(**dns_config_args) if dns_config_args else None
container_spec_args: dict[str, t.Any] = {}
if self.command is not None:
container_spec_args["command"] = self.command
if self.args is not None:
container_spec_args["args"] = self.args
if self.command_as_args:
# Match `docker service create IMAGE [COMMAND] [ARG...]`: the CLI places
# all post-image tokens into ContainerSpec.Args so ENTRYPOINT is kept.
# Writing Command instead replaces ENTRYPOINT and breaks flag-style
# commands such as `-config.file=...` (see #1044, #212).
combined_args = _combine_command_args(self.command, self.args)
if combined_args is not None:
container_spec_args["args"] = combined_args
else:
# Historical mapping: command -> ContainerSpec.Command, args -> Args.
if self.command is not None:
container_spec_args["command"] = self.command
if self.args is not None:
container_spec_args["args"] = self.args
if self.env is not None:
container_spec_args["env"] = self.env
if self.user is not None:
@ -2748,6 +2820,7 @@ def main() -> None:
"networks": {"type": "list", "elements": "raw"},
"command": {"type": "raw"},
"args": {"type": "list", "elements": "str"},
"command_as_args": {"type": "bool", "default": False},
"env": {"type": "raw"},
"env_files": {"type": "list", "elements": "path"},
"force_update": {"type": "bool", "default": False},