Files
computer-playbook/plugins/lookup/shared_network_key.py
T
kevinveenbirkenbachandClaude Opus 5 8df0ad4f5d fix(compose): derive the network label from the renderer
Two places decided independently what the pre-created <entity> network is called
inside the compose project. render.py emits the key; create.yml asserted it was
always `default`. They diverged in July and nobody noticed, because compose
5.3.1 resolved networks by name and never read the claim.

Compose 5.4.0, published 2026-08-03T14:39:12Z, resolves them by label. For
web-app-seaweedfs - the one deployed role that provides its own shared_net and
therefore renders an unnamed `default` - the mislabelled `seaweedfs` network is
adopted as the project default, `seaweedfs_default` is never created, and the
containers fail to start against it. That failed web-app-nextcloud 0 and 3 in
run 30830377785.

_shared_network_key() is now the single derivation. render_compose_networks
takes its branch from it, so the rendering decision IS the key decision;
shared_network_compose_key() exports the same value, the shared_network_key
lookup hands it to Ansible, and create.yml stamps it: `seaweedfs` for a
self-provider, `default` for everyone else. Both true, both from the source that
renders the file.

Verified on one host with only the compose binary swapped:
  5.4.0 network=default   -> FAIL, network <project>_default not found
  5.4.0 network=<entity>  -> OK
  5.3.1 network=default   -> OK
  5.3.1 network=<entity>  -> OK
so this is not a fix that trades one version for the other.

test_key_matches_the_key_the_renderer_emits renders the block and asserts the
reported key appears in it, for both role shapes and both modes. The drift that
sat unnoticed for a month now breaks a test.

The move of the attachment computation into utils/networks/attachments.py rides
along because render.py would otherwise be broken between two commits: it is a
pure relocation, re-exported so no importer changes, and it brings the file from
352 to 243 lines.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 22:02:50 +02:00

61 lines
1.9 KiB
Python

"""Lookup `shared_network_key`: the compose networks key of the pre-created
``<entity>`` network of a role.
Docker compose stores that key in the ``com.docker.compose.network`` label of
every network it owns, so a caller pre-creating the network out of band has to
stamp the same value or compose will resolve the project's networks against a
claim the rendered file does not make. The key is derived from
``utils.networks.render``, which renders the file itself, so the two cannot
drift.
Examples:
- name: create the shared network
ansible.builtin.command:
argv:
- container
- network
- create
- --label
- "com.docker.compose.network={{ lookup('shared_network_key', role_id) }}"
"""
from __future__ import annotations
from typing import Any
from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
from utils.networks.lookup_context import build_context, resolve_var
from utils.networks.render import shared_network_compose_key
from utils.roles.entity.name import get_entity_name
class LookupModule(LookupBase):
def run(
self,
terms: list[Any] | None,
variables: dict[str, Any] | None = None,
**kwargs: Any,
) -> list[str]:
if not terms or len(terms) != 1:
raise AnsibleError(
"shared_network_key lookup requires exactly one term: application_id"
)
ctx = build_context(self, variables)
application_id = str(resolve_var(ctx.templar, terms[0]))
return [
shared_network_compose_key(
application_id=application_id,
deployment_mode=ctx.deployment_mode,
registry=ctx.registry,
get_entity_name=get_entity_name,
lookup_config=ctx.lookup_config,
lookup_database=ctx.lookup_database,
node_local=bool(kwargs.get("node_local", False)),
)
]