feat: add funcs endpoint — list all functions with triggers for UI
This commit is contained in:
@@ -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
|
||||
@@ -130,3 +130,44 @@ output "table_reader_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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user