feat: add funcs endpoint — list all functions with triggers for UI

This commit is contained in:
Naeel
2026-03-18 10:05:15 +03:00
parent ba0375d47e
commit 6010649e7b
3 changed files with 125 additions and 0 deletions
@@ -0,0 +1,83 @@
# 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)}
@@ -0,0 +1 @@
requests==2.31.0
+41
View File
@@ -130,3 +130,44 @@ output "table_reader_url" {
value = sless_trigger.postgres_table_reader_http.url value = sless_trigger.postgres_table_reader_http.url
} }
# Namespace пользователя — извлекаем из уже известного URL триггера.
# URL формат: https://sless.kube5s.ru/fn/sless-{hex16}/{name}
# split("/") → ["https:", "", "sless.kube5s.ru", "fn", "sless-{hex16}", "{name}"]
# element(..., 4) → "sless-{hex16}"
locals {
user_namespace = element(split("/", sless_trigger.postgres_table_reader_http.url), 4)
}
# HTTP-функция возвращает список всех функций пользователя с их статусами и триггерами.
# Вызывает внутренний API оператора — не проходит через внешний Ingress.
# Доступна по URL: https://sless.kube5s.ru/fn/<namespace>/funcs
resource "sless_function" "funcs_list" {
name = "funcs"
runtime = "python3.11"
entrypoint = "funcs_list.list_all"
memory_mb = 128
timeout_sec = 15
env_vars = {
# Внутренний ClusterIP сервис оператора — без TLS, без DNS-overhead.
SLESS_API_URL = "http://sless-operator.sless.svc.cluster.local:9090"
SLESS_NAMESPACE = local.user_namespace
SLESS_TOKEN = var.api_token
}
source_dir = "${path.module}/code/funcs-list"
depends_on = [sless_trigger.postgres_table_reader_http]
}
resource "sless_trigger" "funcs_list_http" {
name = "funcs-http"
type = "http"
function = sless_function.funcs_list.name
enabled = true
}
output "funcs_url" {
value = sless_trigger.funcs_list_http.url
}