Files
computer-playbook/plugins/lookup/api.py
T
kevinveenbirkenbachandClaude Opus 5 ddd62febd5 refactor(api): move utils/api.py under utils/cache
`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>
2026-09-19 06:39:22 +02:00

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]