Files
kevinveenbirkenbachandClaude Opus 5.5 eda6249d7b fix(sys-svc-compose): probe provider networks by their exact name
The network probe used community.docker.docker_network_info, whose
get_network() scans GET /networks and returns the first entry whose Name
equals the requested name OR whose Id starts with it, in a list order that
changes between calls. In main run 38038541631 (Zammad#1, swarm) the
central redis overlay got the ID n8nwzb1q39m3u4k7awwwmt6yg, the probe for
the not yet created provider network "n8n" returned it as existing, the
create step was skipped, docker stack deploy attached hermes to the redis
overlay as "n8n", and the oauth2-proxy then reached the password-protected
central redis by its bare host name: "NOAUTH Authentication required".
The same scan can also return the ID-prefix twin of a network that does
exist, so comparing the returned name alone would turn that network into
"missing" and fail the create with "already exists".

Both probes now run `container network ls --filter name=<entity> --format
'{{json .}}'`, whose name filter never matches an ID. The new lookup
network_driver picks the entry named exactly after the entity and returns
its driver, '' when there is none; the drift checks, their messages and the
create steps all read that one entry. No docker module is left in the file,
so its two docker-module-uses-container-cli suppressions go too.

Verified: on the host daemon GET /networks/<id prefix> returns a network of
another name and docker network ls --filter name=<id prefix> returns
nothing. In ansible-playbook against real docker network ls output the
lookup returned the exact network's driver in 20 of 20 probes beside an
ID-prefix twin, an empty driver (create path) for a missing network and for
a name only contained in a sibling, and the drift path for a foreign
driver. Unit tests cover the same cases; with a substring match instead of
the exact name the two sibling cases fail.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 18:35:22 +02:00
..
…

Network utils 🕸️

Reusable task files for creating Docker networks in a uniform way. Both helpers derive the docker-side network name from role_id | get_entity_name and the subnet from meta/server.yml.networks.local.subnet, so the name and the subnet pinning live in exactly one place.

Ad-hoc community.docker.docker_network calls or docker network create / container network create shell-outs in role tasks are forbidden by test_network_create_via_util.py.

When to use which 🧭

create.yml: network only, no compose-up

Use when the role still has work to do between the network creation and the compose-up. Examples: copy entrypoint.sh / healthcheck.sh into the instance directory before the container starts, render additional configs, pre-attach other resources. Also the right choice when pre-creating several foreign networks in a loop (e.g. prometheus's native_metrics_apps pre-create), where firing the compose handler per iteration would be wrong.

Required var:

  • network_role_id: the role whose network to create. Name and subnet are derived from it.
- include_tasks: "{{ [playbook_dir, 'roles/sys-svc-compose/tasks/utils/network/create.yml'] | path_join }}"
  vars:
    network_role_id: "{{ application_id }}"

routine.yml: wrapper with immediate compose-up

Use when the role is a self-contained single-container service whose only pre-condition for compose-up is its own network (e.g. svc-db-mariadb, svc-db-postgres, svc-ai-ollama). The wrapper loads the docker-python deps, calls create.yml for the role's own network (via application_id), and then re-includes sys-svc-compose with compose_handlers_flush: true so the compose-up fires right after.

- include_tasks: "{{ [playbook_dir, 'roles/sys-svc-compose/tasks/utils/network/routine.yml'] | path_join }}"
  vars:
    compose_handlers_flush: true

Decision rule 📌

Pick routine.yml when "create network → compose-up immediately" is the entire pre-condition chain. Pick create.yml in every other case.