mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
refactor(ai): declare the litellm consumer contract once
Fourteen roles repeated the same two lines to say they use the gateway: a
`shared` flag gated on group_names, and an `enabled` flag conjoining that gate
with LITELLM_CHAT_MODEL_SERVED. Both are now single-sourced.
`shared` becomes literal true. The flag means the provider is a shared instance
rather than one deployed per consumer, and a central gateway is always that;
the dynamic form only said "shared if deployed", which `enabled` already
decides. The 50 shared pins under `litellm:` leave meta/variants.yml with it.
The tree had already noticed: 20 of those 50 lines carried
`# nocheck: variants-static-override`, two of them with copy-pasted text about
container_backup. This narrows e5de4e085a for one service key rather than
reversing it; every other dynamic flag keeps the group_names form.
`enabled` becomes `{{ LITELLM_USABLE }}`, defined in group_vars/all/16_ai.yml.
That shorthand is only possible because is_explicit_truth learns about it.
The resolver reads a dependency out of the flag TEXT — "in group_names" in
value — so a constant hides the role id and the provider silently leaves the
static closure of every role referencing it. Measured: the old expression
resolves True, `{{ LITELLM_USABLE }}` resolves False. GROUP_GATED_CONSTANTS
names the constants whose own definition carries the gate, and the docstring
states the obligation: a SPOT of this kind that is not listed there drops its
provider without a word.
The wider fix, accepting any Jinja as dynamic, was measured and rejected: 35
other flags carry a Jinja value without the marker (MCP sidecars, javascript
and SSO gates, recaptcha), and they would all enter closures they are not in
today.
A literal shared flag is no longer dynamic, so test_dynamic_flags wants the
`# nocheck: dynamic-flag` its own message documents for legitimate exceptions;
where a marker already existed the rule list is extended rather than a second
comment added.
Behaviour is unchanged where it counts. The closure keeps litellm with the same
app counts (wordpress 26, openwebui 23, hermes 23, mediawiki 22, flowise 23),
unrelated Jinja still resolves False, and the truth table of the new enabled
form matches the old one in all four served/deployed combinations. Three roles
resolve without litellm, and `git show HEAD:` proves that predates this change:
zammad pins enabled false in variant 0 at line 39, nextcloud at line 97.
Six unit tests cover the resolver, including one asserting that every
registered constant is actually defined in group_vars, so an entry cannot
become a dead promise.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
dac61edbc6
commit
328113e7c3
31 files changed
+102
-89
No files matched your search
@@ -35,6 +35,8 @@ LITELLM_CHAT_MODEL_SERVED: >-
|
||||
| map(attribute='alias') | reject('search', 'embed') | list) | length > 0))
|
||||
or ((OPENROUTER_API_KEY | string) | length > 0) }}
|
||||
|
||||
LITELLM_USABLE: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
|
||||
OPENROUTER_API_KEY: ""
|
||||
|
||||
MCP_DISCOVERY: "{{ lookup('mcp_servers') }}"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
# nocheck: seaweedfs-required — Discourse's aws-sdk-s3 defaults a custom endpoint to virtual-host addressing and exposes no force_path_style option, incompatible with SeaweedFS path-style without a global SeaweedFS virtual-host/wildcard-DNS change affecting all consumers; uploads stay on the local volume
|
||||
# nocheck: playwright-service-flag - shared gateway consumer; inference wiring is covered by the gateway role
|
||||
# nocheck: playwright-service-flag, dynamic-flag - shared gateway consumer; inference wiring is covered by the gateway role, and the gateway is a single shared instance
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: playwright-service-flag — static-asset provider, no Playwright surface
|
||||
asset:
|
||||
bond: 1
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
sso:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -59,7 +58,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
sso:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -28,11 +28,11 @@ sso:
|
||||
ldap:
|
||||
enabled: false
|
||||
shared: false
|
||||
# nocheck: playwright-service-flag - shared gateway consumer; inference wiring is covered by the gateway role
|
||||
# nocheck: playwright-service-flag, dynamic-flag - shared gateway consumer; inference wiring is covered by the gateway role, and the gateway is a single shared instance
|
||||
litellm:
|
||||
bond: 1
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: playwright-service-flag - DB engine, covered by role-local integration tests
|
||||
qdrant:
|
||||
bond: 1
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
qdrant:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -68,7 +67,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
qdrant:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -108,7 +106,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
qdrant:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -60,11 +60,11 @@ logout:
|
||||
enabled: false
|
||||
shared: false
|
||||
|
||||
# nocheck: playwright-service-flag
|
||||
# nocheck: playwright-service-flag, dynamic-flag - the gateway is a single shared instance, never deployed per consumer
|
||||
litellm:
|
||||
bond: 1
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
|
||||
dashboard:
|
||||
bond: 1
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
dashboard:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -34,7 +33,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override variant pins a literal off-switch
|
||||
dashboard:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override variant pins a literal off-switch
|
||||
@@ -58,7 +56,6 @@
|
||||
shared: false # nocheck: variants-static-override variant pins a literal off-switch
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override variant pins a literal off-switch
|
||||
dashboard:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override variant pins a literal off-switch
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
# nocheck: dynamic-flag - the gateway is a single shared instance, never deployed per consumer
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: dockerfile-custom
|
||||
sso:
|
||||
bond: 1
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
sso:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -73,7 +72,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
sso:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -120,7 +118,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
sso:
|
||||
enabled: true
|
||||
shared: true
|
||||
|
||||
@@ -113,10 +113,11 @@ container_backup: # nocheck: bond-baseline backup host joins outside the variant
|
||||
bond: 1
|
||||
enabled: "{{ 'svc-bkp-volume-2-local' in group_names }}"
|
||||
shared: true
|
||||
# nocheck: dynamic-flag - the gateway is a single shared instance, never deployed per consumer
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: playwright-service-flag internal adapter sidecar, covered by the role's MCP spec
|
||||
# nocheck: dockerfile-custom the Dockerfile is owned by svc-ai-mcp-adapter and staged per instance, so every adapter-backed provider shares one audited build
|
||||
# nocheck: dynamic-flag the sidecar tracks this role's own mcp flag, not another role's presence; a group_names expression would decide its exposure from an unrelated deployment
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
openwebui:
|
||||
@@ -83,7 +82,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
openwebui:
|
||||
@@ -130,7 +128,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
tor:
|
||||
enabled: true
|
||||
openwebui:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
# nocheck: playwright-service-flag - shared gateway consumer; inference wiring is covered by the gateway role
|
||||
# nocheck: playwright-service-flag, dynamic-flag - shared gateway consumer; inference wiring is covered by the gateway role, and the gateway is a single shared instance
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: seaweedfs-required — object storage not implemented for this role
|
||||
sso:
|
||||
bond: 1
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
sso:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -58,7 +57,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
sso:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -91,7 +89,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
sso:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
# nocheck: dynamic-flag - the gateway is a single shared instance, never deployed per consumer
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: seaweedfs-required — object storage not implemented for this role
|
||||
sso:
|
||||
bond: 1
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
|
||||
@@ -83,7 +82,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
openwebui:
|
||||
@@ -128,7 +126,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
tor:
|
||||
enabled: true
|
||||
openwebui:
|
||||
|
||||
@@ -93,10 +93,11 @@ container_backup: # nocheck: bond-baseline backup host joins outside the variant
|
||||
bond: 1
|
||||
enabled: "{{ 'svc-bkp-volume-2-local' in group_names }}"
|
||||
shared: true
|
||||
# nocheck: dynamic-flag - the gateway is a single shared instance, never deployed per consumer
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: playwright-service-flag MCP pairing is proven by the role's own MCP spec, not by a per-consumer gate
|
||||
openwebui:
|
||||
bond: 0.5
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
tor:
|
||||
enabled: true
|
||||
|
||||
@@ -69,7 +68,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
openwebui:
|
||||
|
||||
@@ -335,11 +335,11 @@ openwebui:
|
||||
bond: 0.5
|
||||
enabled: "{{ 'web-app-openwebui' in group_names }}"
|
||||
shared: "{{ 'web-app-openwebui' in group_names }}"
|
||||
# nocheck: playwright-service-flag: bridged litellm gateway partner, covered by partner role spec
|
||||
# nocheck: playwright-service-flag, dynamic-flag - bridged litellm gateway partner, covered by partner role spec, and a single shared instance
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: playwright-service-flag: bridged mastodon partner, covered by partner role spec
|
||||
mastodon:
|
||||
bond: 0.5
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -193,7 +192,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -332,7 +330,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -427,7 +424,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -522,7 +518,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -617,7 +612,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -712,7 +706,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -807,7 +800,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -902,7 +894,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -997,7 +988,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -1092,7 +1082,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -1187,7 +1176,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -1282,7 +1270,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -1377,7 +1364,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
mastodon:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -50,11 +50,11 @@ sso:
|
||||
- "{{ lookup('rbac_group_path', application_id='web-app-openclaw', role='administrator') }}"
|
||||
- "{{ lookup('rbac_group_path', application_id='web-app-openclaw', role='mcp') }}"
|
||||
|
||||
# nocheck: playwright-service-flag
|
||||
# nocheck: playwright-service-flag, dynamic-flag - the gateway is a single shared instance, never deployed per consumer
|
||||
litellm:
|
||||
bond: 1
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
|
||||
logout:
|
||||
bond: 1
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
logout:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -37,7 +36,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
logout:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -64,7 +62,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
logout:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -81,11 +81,11 @@ css:
|
||||
javascript:
|
||||
enabled: false # nocheck: dynamic-flag
|
||||
shared: true
|
||||
# nocheck: playwright-service-flag — AI backend, infrastructural
|
||||
# nocheck: playwright-service-flag, dynamic-flag — AI backend, infrastructural, and a single shared instance
|
||||
litellm:
|
||||
bond: 1
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
|
||||
email:
|
||||
bond: 1
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
prometheus:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -63,7 +62,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
prometheus:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -102,7 +100,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
prometheus:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
# nocheck: playwright-service-flag - shared gateway consumer; inference wiring is covered by the gateway role
|
||||
# nocheck: playwright-service-flag, dynamic-flag - shared gateway consumer; inference wiring is covered by the gateway role, and the gateway is a single shared instance
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: seaweedfs-required, object storage not implemented for this role
|
||||
sso:
|
||||
bond: 1
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
sso:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -79,7 +78,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
sso:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
# nocheck: dynamic-flag - the gateway is a single shared instance, never deployed per consumer
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: seaweedfs-required — object storage not implemented for this role
|
||||
sso:
|
||||
bond: 1
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
- services:
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
container_backup:
|
||||
enabled: true
|
||||
dashboard:
|
||||
@@ -40,7 +39,6 @@
|
||||
- services:
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
container_backup:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
@@ -74,7 +72,6 @@
|
||||
- services: # nocheck: variants-auth-isolation
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
container_backup:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
# nocheck: dynamic-flag - the gateway is a single shared instance, never deployed per consumer
|
||||
litellm:
|
||||
bond: 0.5
|
||||
enabled: "{{ ('svc-ai-litellm' in group_names) and (LITELLM_CHAT_MODEL_SERVED | bool) }}"
|
||||
shared: "{{ 'svc-ai-litellm' in group_names }}"
|
||||
enabled: "{{ LITELLM_USABLE }}"
|
||||
shared: true
|
||||
# nocheck: seaweedfs-required - object storage not implemented for this role
|
||||
sso:
|
||||
bond: 1
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
openwebui:
|
||||
@@ -86,7 +85,6 @@
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
litellm:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
|
||||
@@ -117,7 +115,6 @@
|
||||
shared: true
|
||||
litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
logout:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
|
||||
@@ -4,12 +4,15 @@ import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from utils.cache.files import PROJECT_ROOT
|
||||
from utils.cache.yaml import dump_yaml_str
|
||||
from utils.roles.applications.services.registry import (
|
||||
GROUP_GATED_CONSTANTS,
|
||||
ServiceRegistryError,
|
||||
build_service_registry_from_applications,
|
||||
detect_service_bucket,
|
||||
detect_service_channel,
|
||||
is_explicit_truth,
|
||||
ordered_primary_service_entries,
|
||||
resolve_service_dependency_roles_from_config,
|
||||
)
|
||||
@@ -335,5 +338,42 @@ class TestServiceRegistryOrdering(unittest.TestCase):
|
||||
ordered_primary_service_entries(registry, roles_dir)
|
||||
|
||||
|
||||
class TestExplicitTruth(unittest.TestCase):
|
||||
"""A flag may resolve a dependency through a group-gated constant.
|
||||
|
||||
The substring rule reads the role id out of the flag itself, so a SPOT
|
||||
constant hides it. Roles referencing one keep their provider only while
|
||||
the constant is registered.
|
||||
"""
|
||||
|
||||
def test_a_literal_true_resolves(self):
|
||||
self.assertTrue(is_explicit_truth(True))
|
||||
|
||||
def test_the_in_group_names_form_resolves(self):
|
||||
self.assertTrue(is_explicit_truth("{{ 'web-app-keycloak' in group_names }}"))
|
||||
|
||||
def test_every_registered_constant_resolves(self):
|
||||
for constant in GROUP_GATED_CONSTANTS:
|
||||
with self.subTest(constant=constant):
|
||||
self.assertTrue(is_explicit_truth("{{ " + constant + " }}"))
|
||||
|
||||
def test_an_unregistered_jinja_expression_does_not_resolve(self):
|
||||
self.assertFalse(
|
||||
is_explicit_truth("{{ lookup('config', 'web-app-gitea', 'mcp.enabled') }}")
|
||||
)
|
||||
|
||||
def test_a_literal_false_does_not_resolve(self):
|
||||
self.assertFalse(is_explicit_truth(False))
|
||||
|
||||
def test_every_registered_constant_is_defined_in_group_vars(self):
|
||||
group_vars = PROJECT_ROOT / "group_vars" / "all"
|
||||
defined = "".join(
|
||||
path.read_text(encoding="utf-8") for path in group_vars.glob("*.yml")
|
||||
)
|
||||
for constant in GROUP_GATED_CONSTANTS:
|
||||
with self.subTest(constant=constant):
|
||||
self.assertIn(f"{constant}:", defined)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -28,10 +28,21 @@ def _normalized_name(value: Any) -> str:
|
||||
return value.strip()
|
||||
|
||||
|
||||
GROUP_GATED_CONSTANTS: tuple[str, ...] = ("LITELLM_USABLE",)
|
||||
"""Group_vars constants whose own definition carries an ``in group_names``
|
||||
gate, so a flag referencing one is dynamic even though its own text is not.
|
||||
|
||||
A constant hides the role id the substring rule looks for, so every SPOT of
|
||||
this kind MUST be listed here or the roles referencing it silently drop their
|
||||
provider from the static closure.
|
||||
"""
|
||||
|
||||
|
||||
def is_explicit_truth(value: Any) -> bool:
|
||||
"""A services.<key> flag (``enabled`` / ``shared``) MAY be true if it
|
||||
is the literal Python ``True`` OR any string containing the substring
|
||||
``in group_names``. Negated and compound predicates
|
||||
is the literal Python ``True``, any string containing the substring
|
||||
``in group_names``, or a string referencing a `GROUP_GATED_CONSTANTS`
|
||||
entry. Negated and compound predicates
|
||||
(``"{{ 'X' not in group_names }}"``) match on purpose: they are true
|
||||
on some node shape, and the static closure is the co-deploy superset.
|
||||
Mirrors the substring test at
|
||||
@@ -47,7 +58,11 @@ def is_explicit_truth(value: Any) -> bool:
|
||||
"""
|
||||
if value is True:
|
||||
return True
|
||||
return bool(isinstance(value, str) and "in group_names" in value)
|
||||
if not isinstance(value, str):
|
||||
return False
|
||||
return "in group_names" in value or any(
|
||||
constant in value for constant in GROUP_GATED_CONSTANTS
|
||||
)
|
||||
|
||||
|
||||
def detect_service_channel(role_name: str) -> str:
|
||||
|
||||
Reference in new issue
Block a user