mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
The container_address lookup does not return a container name in swarm. It returns a shell fragment, "$(/usr/bin/resolve-container-id <stack> <service>)", which is only a name once an interpreter evaluates the substitution. The shell module provides one. The command module does not -- it execs the binary directly, so the fragment arrives at container exec as literal text and the call dies with "No such container: $(...)". Compose hides the entire class: there the same lookup yields a bare name and command: works. The failure exists only in swarm, and no swarm run had touched these paths -- both were added by feature commits (b23653adf8,0421ebeb16) that wrote the same argv shape independently, which is the argument for a rule rather than six edits. Six call sites moved to the shell module: the moodle egress task, the three moodle AI-gateway tasks, and the two wordpress AI-Engine tasks. The wordpress pair keeps its stdin, so it uses the dict form with cmd:. Moving off argv exposes the surrounding values to word splitting, so they now go through quote -- the address itself must NOT, because single quotes would suppress exactly the substitution this depends on. test_argv_exec_needs_shell.py closes the gap that let this through. container-exec-resolver checks that the resolver is used; it has nothing to say about whether anything can evaluate the result. The new rule checks that other half. It reuses the sibling's argv parser, which recognises only container/docker in first position, so an argv list that does start an interpreter (argv: [bash, -lc, ...], as joomla does) is correctly not matched. Run against the tree the rule reported exactly the five sites found by hand plus bigbluebutton, and passed over joomla and the discourse task, whose address is a config lookup rather than the resolver. Bigbluebutton is pinned to compose via compose_mode_force and can only ever see a bare name, so it takes a nocheck. Five container-exec-resolver markers disappear with the argv form: under shell the resolver is the ordinary path, not an exception. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
35 lines
1.6 KiB
YAML
35 lines
1.6 KiB
YAML
---
|
|
- name: "🔐 Verify the gateway contract for {{ application_id }}"
|
|
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/svc-ai-litellm/tasks/utils/consumer_contract.yml') }}"
|
|
|
|
- name: "📌 Point the AI Engine default environment at the platform gateway"
|
|
ansible.builtin.shell:
|
|
cmd: >
|
|
container exec -i --user {{ WORDPRESS_USER | quote }}
|
|
-e {{ ('AI_ENGINE_PAYLOAD=' ~ (lookup('config', application_id, 'addons.ai-engine.config') | to_json | b64encode)) | quote }}
|
|
{{ WORDPRESS_CONTAINER_ADDRESS }}
|
|
wp eval-file - --path={{ WORDPRESS_DOCKER_HTML_PATH | quote }}
|
|
stdin: "{{ lookup('file', 'php/ai_engine/configure.php') }}"
|
|
changed_when: true
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: "🔎 Read back the configured AI Engine endpoint"
|
|
ansible.builtin.shell:
|
|
cmd: >
|
|
container exec -i --user {{ WORDPRESS_USER | quote }}
|
|
-e {{ ('AI_ENGINE_ENV_ID=' ~ WORDPRESS_LITELLM_ENV_ID) | quote }}
|
|
{{ WORDPRESS_CONTAINER_ADDRESS }}
|
|
wp eval-file - --path={{ WORDPRESS_DOCKER_HTML_PATH | quote }}
|
|
stdin: "{{ lookup('file', 'php/ai_engine/endpoint.php') }}"
|
|
register: wordpress_ai_endpoint
|
|
changed_when: false
|
|
|
|
- name: "🛑 Refuse an AI Engine environment that does not answer through the gateway"
|
|
ansible.builtin.assert:
|
|
that:
|
|
- (wordpress_ai_endpoint.stdout | trim) == LITELLM_OPENAI_BASE_LOCAL_URL
|
|
fail_msg: >-
|
|
The AI Engine environment '{{ WORDPRESS_LITELLM_ENV_ID }}' still resolves to
|
|
'{{ wordpress_ai_endpoint.stdout | trim }}' instead of
|
|
{{ LITELLM_OPENAI_BASE_LOCAL_URL }}, so prompts would leave the deployment.
|