mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 19:56:53 +00:00
`utils.api` shadowed `ansible.module_utils.api` for anything that reached the top-level `utils` package first, which the ai-agent-employees merge made reachable. The module caches provider declarations, so it belongs beside the other caches rather than at the root. The three importers and the two documentation references move with it; nothing else names the old path. Verified: `from utils.cache.api import declared_api, provider_enabled, resolve_api` resolves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
51 lines
1.8 KiB
Python
51 lines
1.8 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from ansible.errors import AnsibleError
|
|
from ansible.plugins.lookup import LookupBase
|
|
|
|
from utils.cache.api import resolve_api
|
|
|
|
|
|
class LookupModule(LookupBase):
|
|
"""
|
|
lookup('api', '<provider>.<key>') e.g. lookup('api', 'github.client_id')
|
|
|
|
Single point of truth for proprietary / external API credentials. Resolves a
|
|
dotted path against the effective ``API`` mapping: the declaration in
|
|
group_vars/all/18_api.yml with the calling scope's override merged over it.
|
|
Routing every access through this plugin keeps one place to change how
|
|
proprietary API credentials are sourced (vault, env, secret manager, a
|
|
different provider abstraction) without touching the call sites.
|
|
"""
|
|
|
|
def run(self, terms, variables: dict[str, Any] | None = None, **kwargs):
|
|
if not terms or len(terms) != 1:
|
|
raise AnsibleError(
|
|
"lookup('api') takes exactly one term: '<provider>.<key>' "
|
|
"(e.g. 'github.client_id')."
|
|
)
|
|
|
|
templar = getattr(self, "_templar", None)
|
|
variables = variables or getattr(templar, "available_variables", {}) or {}
|
|
|
|
path = str(terms[0]).strip()
|
|
if not path:
|
|
raise AnsibleError("lookup('api'): empty key path.")
|
|
|
|
try:
|
|
api = resolve_api(variables, templar=templar)
|
|
except TypeError as error:
|
|
raise AnsibleError(f"lookup('api'): {error}") from error
|
|
|
|
node: Any = api
|
|
for part in path.split("."):
|
|
if not isinstance(node, dict) or part not in node:
|
|
raise AnsibleError(
|
|
f"lookup('api'): unknown key '{path}' (failed at '{part}'). "
|
|
f"Declare it under 'API' in group_vars/all/18_api.yml."
|
|
)
|
|
node = node[part]
|
|
return [node]
|