mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Run 34421944328 Snipe-IT#1 (swarm) failed its CLI contract with "UNREACHABLE read call snipeit_get_license_summary: the provider answered 500". The mint ran provision_mcp_identity.php through container exec as root, so the first deploy's passport:keys wrote the key files root-owned (0660/0600), and the NFS export's No_Root_Squash kept them that way. Apache serves as apache and could not read the public key, so every token-checked request failed with 500 on every replica. The image's startup script chowns the keys to apache:root, but only when a container starts, and the mint ran after that. mcp_mint.yml now runs the same chown in the resolved container before minting, which also heals keys an earlier deploy left root-owned, and runs the mint itself with -u apache so keys it creates start out readable. The PHP script checks the token it just minted against its own API and exits 1 on anything but 200, so a broken mint fails the task that made it, within its retries, instead of surfacing as an unreachable provider in the CLI contract. Each retry revokes the same-name token before minting, so retries do not pile up live tokens. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
65 lines
2.2 KiB
YAML
65 lines
2.2 KiB
YAML
---
|
|
- name: "🔍 Resolve {{ application_id }} hosting node + container id"
|
|
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/sys-svc-compose/tasks/utils/swarm/resolve_host_cid.yml') }}"
|
|
vars:
|
|
resolve_service_key: "{{ SNIPE_IT_SERVICE }}"
|
|
resolve_output_prefix: SNIPEIT_IDENTITY
|
|
resolve_compose_cid: "{{ SNIPE_IT_CONTAINER }}"
|
|
|
|
- name: "🔐 Hand Passport's keys to apache, as the image's startup script does"
|
|
ansible.builtin.command:
|
|
argv:
|
|
- container
|
|
- exec
|
|
- "{{ SNIPEIT_IDENTITY_LOCAL_CID }}" # nocheck: container-exec-resolver
|
|
- chown
|
|
- -R
|
|
- apache:root
|
|
- /var/lib/snipeit/keys
|
|
changed_when: false
|
|
delegate_to: "{{ SNIPEIT_IDENTITY_HOST_NODE }}"
|
|
run_once: true
|
|
|
|
- name: "🔑 Mint the read-only Snipe-IT token the MCP adapter presents"
|
|
ansible.builtin.command:
|
|
argv:
|
|
- container
|
|
- exec
|
|
- -i
|
|
- -u
|
|
- apache
|
|
- -e
|
|
- "APP_KEY={{ SNIPE_IT_APP_KEY }}"
|
|
- -e
|
|
- "MCP_USER={{ SNIPEIT_MCP_UPSTREAM_USER }}"
|
|
- -e
|
|
- "MCP_PASSWORD={{ SNIPEIT_MCP_UPSTREAM_PASSWORD }}"
|
|
- -e
|
|
- "MCP_TOKEN_NAME={{ SNIPEIT_MCP_UPSTREAM_TOKEN_NAME }}"
|
|
- -e
|
|
- "MCP_CURRENT_TOKEN={{ MCP_UPSTREAM_CURRENT_KEY }}"
|
|
- "{{ SNIPEIT_IDENTITY_LOCAL_CID }}" # nocheck: container-exec-resolver
|
|
- php
|
|
stdin: "{{ lookup('file', 'php/provision_mcp_identity.php') }}"
|
|
register: snipeit_mcp_identity
|
|
retries: 30
|
|
delay: 10
|
|
until: snipeit_mcp_identity.rc == 0
|
|
changed_when: true
|
|
delegate_to: "{{ SNIPEIT_IDENTITY_HOST_NODE }}"
|
|
run_once: true
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: "🛑 Refuse an adapter whose upstream identity did not converge"
|
|
ansible.builtin.assert:
|
|
that:
|
|
- snipeit_mcp_identity.stdout_lines | length == 2
|
|
fail_msg: >-
|
|
{{ application_id }} could not mint a read-only API token for its MCP adapter.
|
|
|
|
- name: "🔑 Hand the minted token to the adapter"
|
|
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/svc-ai-mcp-adapter/tasks/upstream_key.yml') }}"
|
|
vars:
|
|
mcp_upstream_key_path: "{{ [SNIPEIT_MCP_INSTANCE_DIR, 'upstream.env'] | path_join }}"
|
|
mcp_upstream_key: "{{ snipeit_mcp_identity.stdout_lines[1] }}"
|