# 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)}