feat: operator v0.1.16 — job stdout -> status.Message (feature B)
- FunctionJobReconciler: added KubeClient field (kubernetes.Interface) - getJobPodOutput(): reads pod logs via typed client after job succeeds - main.go: inject kubernetes.NewForConfigOrDie into FunctionJobReconciler - rbac.yaml: add pods/pods/log get/list/watch permissions - examples/simple-python/: job->function chain demo (Python) - examples/simple-node/: job->function chain demo (Node.js) sless_job.X.message now contains the return value of the function
This commit is contained in:
parent
83c8eea61b
commit
695f217e13
20
simple-node/code/time_display/time_display.js
Normal file
20
simple-node/code/time_display/time_display.js
Normal file
@ -0,0 +1,20 @@
|
||||
// Создано: 2026-03-09
|
||||
// time_display.js — HTTP-функция (постоянный Deployment + Trigger).
|
||||
// Читает env JOB_TIME, которую terraform передаёт из sless_job.run_getter.message.
|
||||
// Демонстрирует цепочку: Job вычисляет данные → Function использует их через env.
|
||||
|
||||
exports.showTime = function(event) {
|
||||
// JOB_TIME устанавливается terraform из статуса джоба (JSON строка)
|
||||
const jobTimeRaw = process.env.JOB_TIME || '{}';
|
||||
let jobTime;
|
||||
try {
|
||||
const parsed = JSON.parse(jobTimeRaw);
|
||||
jobTime = parsed.time || jobTimeRaw;
|
||||
} catch (e) {
|
||||
jobTime = jobTimeRaw;
|
||||
}
|
||||
return {
|
||||
message: `Сервис запустился в: ${jobTime}`,
|
||||
path: event._path || '/',
|
||||
};
|
||||
};
|
||||
10
simple-node/code/time_getter/time_getter.js
Normal file
10
simple-node/code/time_getter/time_getter.js
Normal file
@ -0,0 +1,10 @@
|
||||
// Создано: 2026-03-09
|
||||
// time_getter.js — функция запускается как Job (одноразово).
|
||||
// Возвращает JSON со временем запуска. Оператор v0.1.16 захватывает stdout
|
||||
// и записывает его в sless_job.run_getter.message — оттуда terraform передаёт
|
||||
// значение в sless_function.display через env_var JOB_TIME.
|
||||
|
||||
exports.getTime = function(event) {
|
||||
// Возвращаем время в ISO 8601 UTC — без зависимостей, только stdlib
|
||||
return { time: new Date().toISOString() };
|
||||
};
|
||||
BIN
simple-node/dist/time_display.zip
vendored
Normal file
BIN
simple-node/dist/time_display.zip
vendored
Normal file
Binary file not shown.
BIN
simple-node/dist/time_getter.zip
vendored
Normal file
BIN
simple-node/dist/time_getter.zip
vendored
Normal file
Binary file not shown.
22
simple-node/main.tf
Normal file
22
simple-node/main.tf
Normal file
@ -0,0 +1,22 @@
|
||||
# Создано: 2026-03-09
|
||||
# main.tf — точка входа для примера simple-node.
|
||||
# Демонстрирует цепочку: sless_job (one-shot) → sless_function (http).
|
||||
# Аналог simple-python, но на Node.js 20.
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
sless = {
|
||||
source = "terra.k8c.ru/naeel/sless"
|
||||
version = "~> 0.1.8"
|
||||
}
|
||||
archive = {
|
||||
source = "hashicorp/archive"
|
||||
version = "~> 2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "sless" {
|
||||
endpoint = "https://sless-api.kube5s.ru"
|
||||
token = "dev-token-change-me"
|
||||
}
|
||||
12
simple-node/outputs.tf
Normal file
12
simple-node/outputs.tf
Normal file
@ -0,0 +1,12 @@
|
||||
# Создано: 2026-03-09
|
||||
# outputs.tf — полезные значения после terraform apply.
|
||||
|
||||
output "display_url" {
|
||||
description = "URL HTTP-триггера функции time_display"
|
||||
value = sless_trigger.display_http.url
|
||||
}
|
||||
|
||||
output "job_result" {
|
||||
description = "Stdout джоба (return value функции getTime)"
|
||||
value = sless_job.run_getter.message
|
||||
}
|
||||
36
simple-node/time-display.tf
Normal file
36
simple-node/time-display.tf
Normal file
@ -0,0 +1,36 @@
|
||||
# Создано: 2026-03-09
|
||||
# time-display.tf — постоянная HTTP-функция, получающая данные от джоба.
|
||||
|
||||
# Упаковываем код функции в zip
|
||||
data "archive_file" "time_display_zip" {
|
||||
type = "zip"
|
||||
source_dir = "${path.module}/code/time_display"
|
||||
output_path = "${path.module}/dist/time_display.zip"
|
||||
}
|
||||
|
||||
# HTTP-функция: постоянный Deployment, читает JOB_TIME из env
|
||||
resource "sless_function" "time_display" {
|
||||
namespace = "default"
|
||||
name = "simple-node-time-display"
|
||||
runtime = "nodejs20"
|
||||
entrypoint = "time_display.showTime"
|
||||
memory_mb = 64
|
||||
|
||||
# Значение вычислено джобом при apply и зафиксировано в state
|
||||
env_vars = {
|
||||
JOB_TIME = sless_job.run_getter.message
|
||||
}
|
||||
|
||||
code_path = data.archive_file.time_display_zip.output_path
|
||||
code_hash = filesha256("${path.module}/code/time_display/time_display.js")
|
||||
|
||||
depends_on = [sless_job.run_getter]
|
||||
}
|
||||
|
||||
# HTTP-триггер — публикует функцию по URL
|
||||
resource "sless_trigger" "display_http" {
|
||||
namespace = "default"
|
||||
name = "simple-node-display-http"
|
||||
type = "http"
|
||||
function = sless_function.time_display.name
|
||||
}
|
||||
36
simple-node/time-getter.tf
Normal file
36
simple-node/time-getter.tf
Normal file
@ -0,0 +1,36 @@
|
||||
# Создано: 2026-03-09
|
||||
# time-getter.tf — одноразовая функция + джоб запускающий её при apply.
|
||||
# sless_job.run_getter.message после apply содержит stdout runner-а:
|
||||
# {"time":"2026-03-09T12:34:56.789Z"}
|
||||
# Это значение terraform записывает в env JOB_TIME функции time_display.
|
||||
|
||||
# Упаковываем код функции в zip
|
||||
data "archive_file" "time_getter_zip" {
|
||||
type = "zip"
|
||||
source_dir = "${path.module}/code/time_getter"
|
||||
output_path = "${path.module}/dist/time_getter.zip"
|
||||
}
|
||||
|
||||
# Функция-вычислитель: запускается только джобом, не имеет HTTP-триггера
|
||||
resource "sless_function" "time_getter" {
|
||||
namespace = "default"
|
||||
name = "simple-node-time-getter"
|
||||
runtime = "nodejs20"
|
||||
entrypoint = "time_getter.getTime"
|
||||
memory_mb = 64
|
||||
|
||||
code_path = data.archive_file.time_getter_zip.output_path
|
||||
code_hash = filesha256("${path.module}/code/time_getter/time_getter.js")
|
||||
}
|
||||
|
||||
# Джоб: запускает time_getter один раз при terraform apply.
|
||||
resource "sless_job" "run_getter" {
|
||||
namespace = "default"
|
||||
name = "simple-node-getter-run"
|
||||
function = sless_function.time_getter.name
|
||||
run_id = 1
|
||||
wait_timeout_sec = 120
|
||||
event_json = "{}"
|
||||
|
||||
depends_on = [sless_function.time_getter]
|
||||
}
|
||||
20
simple-python/code/time_display/time_display.py
Normal file
20
simple-python/code/time_display/time_display.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Создано: 2026-03-09
|
||||
# time_display.py — HTTP-функция (постоянный Deployment + Trigger).
|
||||
# Читает env JOB_TIME, которую terraform передаёт из sless_job.run_getter.message.
|
||||
# Демонстрирует цепочку: Job вычисляет данные → Function использует их через env.
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
def show_time(event):
|
||||
# JOB_TIME устанавливается terraform из статуса джоба (JSON строка)
|
||||
job_time_raw = os.environ.get("JOB_TIME", "{}")
|
||||
try:
|
||||
job_time = json.loads(job_time_raw).get("time", job_time_raw)
|
||||
except (json.JSONDecodeError, AttributeError):
|
||||
job_time = job_time_raw
|
||||
return {
|
||||
"message": f"Сервис запустился в: {job_time}",
|
||||
"path": event.get("_path", "/"),
|
||||
}
|
||||
18
simple-python/code/time_getter/time_getter.py
Normal file
18
simple-python/code/time_getter/time_getter.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Создано: 2026-03-09
|
||||
# time_getter.py — функция запускается как Job (одноразово).
|
||||
# Возвращает JSON со временем запуска. Оператор v0.1.16 захватывает stdout
|
||||
# и записывает его в sless_job.run_getter.message — оттуда terraform передаёт
|
||||
# значение в sless_function.display через env_var JOB_TIME.
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
def get_time(event):
|
||||
# Возвращаем время в ISO 8601 UTC — без зависимостей, только stdlib
|
||||
return {"time": datetime.now(timezone.utc).isoformat()}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Для локального тестирования без оператора
|
||||
print(json.dumps(get_time({})))
|
||||
BIN
simple-python/dist/time_display.zip
vendored
Normal file
BIN
simple-python/dist/time_display.zip
vendored
Normal file
Binary file not shown.
BIN
simple-python/dist/time_getter.zip
vendored
Normal file
BIN
simple-python/dist/time_getter.zip
vendored
Normal file
Binary file not shown.
23
simple-python/main.tf
Normal file
23
simple-python/main.tf
Normal file
@ -0,0 +1,23 @@
|
||||
# Создано: 2026-03-09
|
||||
# main.tf — точка входа для примера simple-python.
|
||||
# Демонстрирует цепочку: sless_job (one-shot) → sless_function (http).
|
||||
# Джоб запускается при terraform apply, его stdout (JSON) попадает в
|
||||
# sless_job.run_getter.message и передаётся функции через env_vars.
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
sless = {
|
||||
source = "terra.k8c.ru/naeel/sless"
|
||||
version = "~> 0.1.8"
|
||||
}
|
||||
archive = {
|
||||
source = "hashicorp/archive"
|
||||
version = "~> 2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "sless" {
|
||||
endpoint = "https://sless-api.kube5s.ru"
|
||||
token = "dev-token-change-me"
|
||||
}
|
||||
14
simple-python/outputs.tf
Normal file
14
simple-python/outputs.tf
Normal file
@ -0,0 +1,14 @@
|
||||
# Создано: 2026-03-09
|
||||
# outputs.tf — полезные значения после terraform apply.
|
||||
|
||||
# URL HTTP-триггера для тестирования функции display
|
||||
output "display_url" {
|
||||
description = "URL HTTP-триггера функции time_display"
|
||||
value = sless_trigger.display_http.url
|
||||
}
|
||||
|
||||
# Результат джоба — JSON строка {"time": "..."} из stdout функции get_time()
|
||||
output "job_result" {
|
||||
description = "Stdout джоба (return value функции get_time)"
|
||||
value = sless_job.run_getter.message
|
||||
}
|
||||
40
simple-python/time-display.tf
Normal file
40
simple-python/time-display.tf
Normal file
@ -0,0 +1,40 @@
|
||||
# Создано: 2026-03-09
|
||||
# time-display.tf — постоянная HTTP-функция, получающая данные от джоба.
|
||||
# JOB_TIME берётся из sless_job.run_getter.message (stdout джоба) —
|
||||
# это JSON строка {"time": "..."}, terraform передаёт её в env целиком.
|
||||
# Функция парсит её через os.environ, а не через event — демонстрирует
|
||||
# паттерн "данные вычислены один раз при деплое, используются на каждый запрос".
|
||||
|
||||
# Упаковываем код функции в zip
|
||||
data "archive_file" "time_display_zip" {
|
||||
type = "zip"
|
||||
source_dir = "${path.module}/code/time_display"
|
||||
output_path = "${path.module}/dist/time_display.zip"
|
||||
}
|
||||
|
||||
# HTTP-функция: постоянный Deployment, читает JOB_TIME из env
|
||||
resource "sless_function" "time_display" {
|
||||
namespace = "default"
|
||||
name = "simple-py-time-display"
|
||||
runtime = "python3.11"
|
||||
entrypoint = "time_display.show_time"
|
||||
memory_mb = 64
|
||||
|
||||
# Значение вычислено джобом при apply и зафиксировано в state
|
||||
env_vars = {
|
||||
JOB_TIME = sless_job.run_getter.message
|
||||
}
|
||||
|
||||
code_path = data.archive_file.time_display_zip.output_path
|
||||
code_hash = filesha256("${path.module}/code/time_display/time_display.py")
|
||||
|
||||
depends_on = [sless_job.run_getter]
|
||||
}
|
||||
|
||||
# HTTP-триггер — публикует функцию по URL
|
||||
resource "sless_trigger" "display_http" {
|
||||
namespace = "default"
|
||||
name = "simple-py-display-http"
|
||||
type = "http"
|
||||
function = sless_function.time_display.name
|
||||
}
|
||||
38
simple-python/time-getter.tf
Normal file
38
simple-python/time-getter.tf
Normal file
@ -0,0 +1,38 @@
|
||||
# Создано: 2026-03-09
|
||||
# time-getter.tf — одноразовая функция + джоб запускающий её при apply.
|
||||
# sless_job.run_getter.message после apply содержит stdout runner-а:
|
||||
# {"time": "2026-03-09T12:34:56.789012+00:00"}
|
||||
# Это значение terraform записывает в env JOB_TIME функции time_display.
|
||||
|
||||
# Упаковываем код функции в zip
|
||||
data "archive_file" "time_getter_zip" {
|
||||
type = "zip"
|
||||
source_dir = "${path.module}/code/time_getter"
|
||||
output_path = "${path.module}/dist/time_getter.zip"
|
||||
}
|
||||
|
||||
# Функция-вычислитель: запускается только джобом, не имеет HTTP-триггера
|
||||
resource "sless_function" "time_getter" {
|
||||
namespace = "default"
|
||||
name = "simple-py-time-getter"
|
||||
runtime = "python3.11"
|
||||
entrypoint = "time_getter.get_time"
|
||||
memory_mb = 64
|
||||
|
||||
code_path = data.archive_file.time_getter_zip.output_path
|
||||
code_hash = filesha256("${path.module}/code/time_getter/time_getter.py")
|
||||
}
|
||||
|
||||
# Джоб: запускает time_getter один раз при terraform apply.
|
||||
# run_id > 0 — разрешение на запуск (run_id=0 пропускается оператором).
|
||||
# После завершения message = stdout пода = json возвращённый get_time().
|
||||
resource "sless_job" "run_getter" {
|
||||
namespace = "default"
|
||||
name = "simple-py-getter-run"
|
||||
function = sless_function.time_getter.name
|
||||
run_id = 1
|
||||
wait_timeout_sec = 120
|
||||
event_json = "{}"
|
||||
|
||||
depends_on = [sless_function.time_getter]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user