Files
sless/examples/POSTGRES/code/funcs-list/funcs_list.py
T

84 lines
3.3 KiB
Python

# 2026-03-18
# funcs_list.py — HTTP-функция, возвращает список всех функций пользователя.
# Вызывает внутренний REST API оператора (http://sless-operator.sless.svc.cluster.local:9090).
# Объединяет данные функций и их триггеров в один ответ.
#
# Env vars (обязательные):
# SLESS_API_URL — URL оператора внутри кластера
# SLESS_NAMESPACE — namespace пользователя (sless-{hex16})
# SLESS_TOKEN — JWT токен для авторизации в /v1/ API
#
# Поля в ответе:
# name, runtime, phase, image_ref, message — из /v1/namespaces/{ns}/functions
# triggers[].type/enabled/active/url — из /v1/namespaces/{ns}/triggers
#
# Что ПОКА не возвращается (фиксировано оператором):
# created_at — metav1.CreationTimestamp, не включён в fnToResponse (нужно v0.1.32+)
# last_built_at — FunctionStatus.LastBuiltAt, не включён в fnToResponse (нужно v0.1.32+)
import os
import json
import requests
def list_all(event):
api_url = os.environ["SLESS_API_URL"].rstrip("/")
namespace = os.environ["SLESS_NAMESPACE"]
token = os.environ["SLESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}
fns_resp = requests.get(
f"{api_url}/v1/namespaces/{namespace}/functions",
headers=headers,
timeout=10,
)
fns_resp.raise_for_status()
functions = fns_resp.json()
trs_resp = requests.get(
f"{api_url}/v1/namespaces/{namespace}/triggers",
headers=headers,
timeout=10,
)
trs_resp.raise_for_status()
triggers = trs_resp.json()
# Индексируем триггеры по имени функции (поле "function" = functionRef).
triggers_by_fn = {}
for tr in triggers:
fn_name = tr.get("function") or tr.get("functionRef")
if fn_name:
triggers_by_fn.setdefault(fn_name, []).append(tr)
result = []
for fn in functions:
name = fn["name"]
fn_triggers = [
{
"name": tr.get("name"),
"type": tr.get("type"),
"enabled": tr.get("enabled", True),
"active": tr.get("active", False),
"url": tr.get("url", ""),
"schedule": tr.get("schedule", ""),
}
for tr in triggers_by_fn.get(name, [])
]
result.append({
"name": name,
"runtime": fn.get("runtime"),
"phase": fn.get("phase"),
# active = у функции есть хотя бы один включённый и активный триггер
"active": any(t["enabled"] and t["active"] for t in fn_triggers),
"image_ref": fn.get("image_ref", ""),
"message": fn.get("message", ""),
"triggers": fn_triggers,
# TODO: добавить created_at и last_built_at после обновления оператора до v0.1.32+
})
# Сортируем: сначала активные, потом по имени
result.sort(key=lambda f: (not f["active"], f["name"]))
return {"functions": result, "count": len(result)}