init0
This commit is contained in:
commit
9293985003
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
# S3 конфиги с кредами — не коммитим
|
||||||
|
.s3cfg*
|
||||||
|
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
bin
|
||||||
|
testbin/*
|
||||||
|
hack/local.env
|
||||||
|
Dockerfile.cross
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Kubernetes Generated files - skip generated files, except for vendored files
|
||||||
|
|
||||||
|
!vendor/**/zz_generated.*
|
||||||
|
|
||||||
|
# editor and IDE paraphernalia
|
||||||
|
.idea
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
terraform/provider/build/
|
||||||
|
|
||||||
|
# Terraform state и кэш провайдеров (не коммитим)
|
||||||
|
**/.terraform/
|
||||||
|
**/.terraform.lock.hcl
|
||||||
|
**/terraform.tfstate
|
||||||
|
**/terraform.tfstate.backup
|
||||||
|
**/terraform.tfstate.*.backup
|
||||||
|
**/handler.zip
|
||||||
|
|
||||||
|
# Локальные артефакты упаковки функций
|
||||||
|
**/dist/
|
||||||
141
README.md
Normal file
141
README.md
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
# Примеры sless
|
||||||
|
|
||||||
|
Примеры показывают различные сценарии использования serverless функций через Terraform провайдер `terra.k8c.ru/naeel/sless`.
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- Terraform >= 1.0
|
||||||
|
- Доступ к `https://sless-api.kube5s.ru`
|
||||||
|
|
||||||
|
## Провайдер
|
||||||
|
|
||||||
|
Во всех примерах `main.tf` содержит:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
provider "sless" {
|
||||||
|
endpoint = "https://sless-api.kube5s.ru"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Примеры
|
||||||
|
|
||||||
|
### `simple-python` — джоб передаёт результат в HTTP-функцию (Python)
|
||||||
|
|
||||||
|
При `apply` запускается джоб, его вывод передаётся в HTTP-функцию через `env_vars`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd simple-python
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
# Что вернул джоб (время на момент деплоя):
|
||||||
|
terraform output job_result
|
||||||
|
|
||||||
|
# Проверить функцию:
|
||||||
|
curl -s https://sless-api.kube5s.ru/fn/default/simple-py-time-display
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `simple-node` — то же самое, но на Node.js 20
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd simple-node
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
terraform output job_result
|
||||||
|
curl -s https://sless-api.kube5s.ru/fn/default/simple-node-time-display
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `hello-node` — минимальный пример на Node.js
|
||||||
|
|
||||||
|
Две независимые функции: HTTP-функция (возвращает приветствие) и одноразовый джоб (суммирует числа).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hello-node
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
# Проверить HTTP-функцию:
|
||||||
|
curl -s -X POST https://sless-api.kube5s.ru/fn/default/hello-http \
|
||||||
|
-H 'Content-Type: application/json' -d '{"name":"World"}'
|
||||||
|
|
||||||
|
# Посмотреть результат джоба:
|
||||||
|
terraform output job_message
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `notes-python` — CRUD API на Python + PostgreSQL
|
||||||
|
|
||||||
|
Полноценное приложение: инициализация схемы БД через джобы, CRUD-функция, read-only функция для списка записей.
|
||||||
|
|
||||||
|
**Переменные:**
|
||||||
|
|
||||||
|
| Переменная | Описание | Дефолт |
|
||||||
|
|---|---|---|
|
||||||
|
| `pg_dsn` | DSN для подключения к PostgreSQL | `postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable` |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd notes-python
|
||||||
|
terraform init
|
||||||
|
|
||||||
|
# Опционально — переопределить DSN:
|
||||||
|
# export TF_VAR_pg_dsn="postgres://user:pass@host:5432/db?sslmode=disable"
|
||||||
|
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
# Проверить инициализацию БД:
|
||||||
|
terraform output db_init_table_status
|
||||||
|
terraform output db_init_index_status
|
||||||
|
|
||||||
|
# URL функций:
|
||||||
|
terraform output notes_url # CRUD
|
||||||
|
terraform output notes_list_url # список всех записей
|
||||||
|
|
||||||
|
# Создать запись:
|
||||||
|
curl -s -X POST "https://sless-api.kube5s.ru/fn/default/notes/add?title=Hello&body=World"
|
||||||
|
|
||||||
|
# Список записей:
|
||||||
|
curl -s https://sless-api.kube5s.ru/fn/default/notes-list
|
||||||
|
|
||||||
|
# Обновить (id из предыдущего ответа):
|
||||||
|
curl -s -X POST "https://sless-api.kube5s.ru/fn/default/notes/update?id=1&title=Updated&body=New+body"
|
||||||
|
|
||||||
|
# Удалить:
|
||||||
|
curl -s -X POST "https://sless-api.kube5s.ru/fn/default/notes/delete?id=1"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Общие команды
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Посмотреть текущее состояние ресурсов:
|
||||||
|
terraform show
|
||||||
|
|
||||||
|
# Пересоздать конкретный ресурс:
|
||||||
|
terraform apply -replace=sless_function.имя -auto-approve
|
||||||
|
|
||||||
|
# Повторно запустить джоб — увеличить run_id в .tf файле, затем:
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
# Удалить все ресурсы примера:
|
||||||
|
terraform destroy -auto-approve
|
||||||
|
```
|
||||||
|
|
||||||
|
## Структура каждого примера
|
||||||
|
|
||||||
|
```
|
||||||
|
пример/
|
||||||
|
├── main.tf — провайдер
|
||||||
|
├── *.tf — ресурсы (функции, триггеры, джобы)
|
||||||
|
├── outputs.tf — URLs и статусы после apply
|
||||||
|
├── variables.tf — входные переменные (если есть)
|
||||||
|
└── code/ — исходный код функций
|
||||||
|
```
|
||||||
8
hello-node/code/handler-http.js
Normal file
8
hello-node/code/handler-http.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// 2026-03-08
|
||||||
|
// handler-http.js — HTTP-функция: возвращает приветствие.
|
||||||
|
// Используется с sless_trigger (постоянный эндпоинт).
|
||||||
|
exports.handle = async (event) => {
|
||||||
|
const name = event.name || 'World';
|
||||||
|
return { message: `Hello, ${name}! HTTP !!!` };
|
||||||
|
};
|
||||||
|
|
||||||
11
hello-node/code/handler-job.js
Normal file
11
hello-node/code/handler-job.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// 2026-03-08
|
||||||
|
// handler-job.js — batch-функция: суммирует числа и считает среднее.
|
||||||
|
// Используется с sless_job (одноразовый запуск).
|
||||||
|
// event.numbers — массив чисел, например [1, 2, 3, 4, 5]
|
||||||
|
exports.handle = async (event) => {
|
||||||
|
const numbers = event.numbers || [];
|
||||||
|
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||||
|
const avg = numbers.length > 0 ? sum / numbers.length : 0;
|
||||||
|
return { input: numbers, sum, avg, count: numbers.length };
|
||||||
|
};
|
||||||
|
|
||||||
24
hello-node/http.tf
Normal file
24
hello-node/http.tf
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# 2026-03-08 / Изменено: 2026-03-09
|
||||||
|
# http.tf — HTTP-функция: принимает запросы, возвращает приветствие.
|
||||||
|
# Код: code/handler-http.js
|
||||||
|
|
||||||
|
resource "sless_function" "hello_http" {
|
||||||
|
name = "hello-http"
|
||||||
|
runtime = "nodejs20"
|
||||||
|
entrypoint = "handler-http.handle"
|
||||||
|
memory_mb = 128
|
||||||
|
timeout_sec = 30
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "sless_trigger" "hello_http" {
|
||||||
|
name = "hello-http-trigger"
|
||||||
|
type = "http"
|
||||||
|
function = sless_function.hello_http.name
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
output "trigger_url" {
|
||||||
|
value = sless_trigger.hello_http.url
|
||||||
|
}
|
||||||
34
hello-node/job.tf
Normal file
34
hello-node/job.tf
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# 2026-03-08 / Изменено: 2026-03-09
|
||||||
|
# job.tf — одноразовая функция: суммирует числа из переданного массива.
|
||||||
|
# Код: code/handler-job.js
|
||||||
|
|
||||||
|
resource "sless_function" "hello_job" {
|
||||||
|
name = "hello-job"
|
||||||
|
runtime = "nodejs20"
|
||||||
|
entrypoint = "handler-job.handle"
|
||||||
|
memory_mb = 128
|
||||||
|
timeout_sec = 30
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Одноразовый запуск. Для повторного запуска увеличь run_id (1→2→3...).
|
||||||
|
resource "sless_job" "hello_run" {
|
||||||
|
name = "hello-run"
|
||||||
|
function = sless_function.hello_job.name
|
||||||
|
event_json = jsonencode({ numbers = [100, 200, 300] })
|
||||||
|
wait_timeout_sec = 600
|
||||||
|
run_id = 9
|
||||||
|
}
|
||||||
|
|
||||||
|
output "job_phase" {
|
||||||
|
value = sless_job.hello_run.phase
|
||||||
|
}
|
||||||
|
|
||||||
|
output "job_message" {
|
||||||
|
value = sless_job.hello_run.message
|
||||||
|
}
|
||||||
|
|
||||||
|
output "job_completion_time" {
|
||||||
|
value = sless_job.hello_run.completion_time
|
||||||
|
}
|
||||||
20
hello-node/main.tf
Normal file
20
hello-node/main.tf
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# 2026-03-08
|
||||||
|
# main.tf — провайдеры.
|
||||||
|
# Функции и их код определены в отдельных файлах:
|
||||||
|
# http.tf — HTTP-триггер (code/handler-http.js)
|
||||||
|
# job.tf — одноразовый запуск (code/handler-job.js)
|
||||||
|
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
sless = {
|
||||||
|
source = "terra.k8c.ru/naeel/sless"
|
||||||
|
version = "~> 0.1.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "sless" {
|
||||||
|
endpoint = "https://sless-api.kube5s.ru"
|
||||||
|
token = "dev-token-change-me"
|
||||||
|
}
|
||||||
|
|
||||||
2
hello-node/test_invalid.tf.disabled
Normal file
2
hello-node/test_invalid.tf.disabled
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Временный файл для негативных тестов — не применяется через terraform
|
||||||
|
# Тесты запускаются вручную с временным переименованием в .tf
|
||||||
31
notes-python/code/notes-list/notes_list.py
Normal file
31
notes-python/code/notes-list/notes_list.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# notes_list.py — чтение всех записей из таблицы notes.
|
||||||
|
#
|
||||||
|
# Назначение: отдать полный список заметок одним запросом.
|
||||||
|
# Принимает GET или POST — тело/query параметры игнорируются.
|
||||||
|
# Возвращает JSON-массив, сортировка: новые записи первые (ORDER BY created_at DESC).
|
||||||
|
#
|
||||||
|
# Пример ответа:
|
||||||
|
# [
|
||||||
|
# {"id": 3, "title": "Hello", "body": "World", "created_at": "2026-03-09 ..."},
|
||||||
|
# {"id": 1, "title": "First", "body": "Note", "created_at": "2026-03-08 ..."}
|
||||||
|
# ]
|
||||||
|
import os
|
||||||
|
import psycopg2
|
||||||
|
import psycopg2.extras
|
||||||
|
|
||||||
|
|
||||||
|
def list_notes(event):
|
||||||
|
dsn = os.environ['PG_DSN']
|
||||||
|
conn = psycopg2.connect(dsn)
|
||||||
|
try:
|
||||||
|
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
|
||||||
|
cur.execute(
|
||||||
|
"SELECT id, title, body, created_at::text FROM notes ORDER BY created_at DESC"
|
||||||
|
)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
return [dict(r) for r in rows]
|
||||||
|
except Exception as e:
|
||||||
|
return {'error': str(e)}
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
1
notes-python/code/notes-list/requirements.txt
Normal file
1
notes-python/code/notes-list/requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
psycopg2-binary
|
||||||
81
notes-python/code/notes/notes_crud.py
Normal file
81
notes-python/code/notes/notes_crud.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# notes_crud.py — CRUD роутер для таблицы notes.
|
||||||
|
#
|
||||||
|
# Назначение: единая функция, которая обрабатывает все операции с записями.
|
||||||
|
# Роутинг осуществляется по sub-path URL (event._path), который runtime
|
||||||
|
# берёт из входящего HTTP-запроса и добавляет в event автоматически.
|
||||||
|
#
|
||||||
|
# Доступные маршруты (все POST):
|
||||||
|
# /fn/default/notes/add?title=...&body=... → создать запись
|
||||||
|
# /fn/default/notes/update?id=1&title=...&body=... → обновить запись
|
||||||
|
# /fn/default/notes/delete?id=1 → удалить запись
|
||||||
|
#
|
||||||
|
# Параметры берутся из query string (event._query) или из тела запроса (event).
|
||||||
|
# event._path и event._query добавляет Python runtime (server.py) автоматически.
|
||||||
|
import os
|
||||||
|
import psycopg2
|
||||||
|
import psycopg2.extras
|
||||||
|
|
||||||
|
|
||||||
|
def crud(event):
|
||||||
|
dsn = os.environ['PG_DSN']
|
||||||
|
# sub-path без ведущего слэша: "add", "update", "delete"
|
||||||
|
action = event.get('_path', '/').strip('/')
|
||||||
|
q = event.get('_query', {})
|
||||||
|
|
||||||
|
conn = psycopg2.connect(dsn)
|
||||||
|
try:
|
||||||
|
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
|
||||||
|
|
||||||
|
if action == 'add':
|
||||||
|
title = q.get('title') or event.get('title', '')
|
||||||
|
body = q.get('body') or event.get('body', '')
|
||||||
|
if not title:
|
||||||
|
return {'error': 'title is required'}
|
||||||
|
cur.execute(
|
||||||
|
"INSERT INTO notes (title, body) VALUES (%s, %s)"
|
||||||
|
" RETURNING id, title, body, created_at::text",
|
||||||
|
(title, body)
|
||||||
|
)
|
||||||
|
row = cur.fetchone()
|
||||||
|
conn.commit()
|
||||||
|
return dict(row)
|
||||||
|
|
||||||
|
elif action == 'update':
|
||||||
|
id_ = q.get('id') or event.get('id')
|
||||||
|
if not id_:
|
||||||
|
return {'error': 'id is required'}
|
||||||
|
title = q.get('title') or event.get('title', '')
|
||||||
|
body = q.get('body') or event.get('body', '')
|
||||||
|
cur.execute(
|
||||||
|
"UPDATE notes SET title=%s, body=%s WHERE id=%s"
|
||||||
|
" RETURNING id, title, body, created_at::text",
|
||||||
|
(title, body, int(id_))
|
||||||
|
)
|
||||||
|
row = cur.fetchone()
|
||||||
|
conn.commit()
|
||||||
|
return dict(row) if row else {'error': 'not found'}
|
||||||
|
|
||||||
|
elif action == 'delete':
|
||||||
|
id_ = q.get('id') or event.get('id')
|
||||||
|
if not id_:
|
||||||
|
return {'error': 'id is required'}
|
||||||
|
cur.execute(
|
||||||
|
"DELETE FROM notes WHERE id=%s RETURNING id",
|
||||||
|
(int(id_),)
|
||||||
|
)
|
||||||
|
row = cur.fetchone()
|
||||||
|
conn.commit()
|
||||||
|
return {'deleted': row['id']} if row else {'error': 'not found'}
|
||||||
|
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
'error': f'unknown action: /{action}',
|
||||||
|
'hint': 'use /add?title=...&body=..., /update?id=X&title=...&body=..., /delete?id=X'
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
conn.rollback()
|
||||||
|
return {'error': str(e)}
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
1
notes-python/code/notes/requirements.txt
Normal file
1
notes-python/code/notes/requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
psycopg2-binary
|
||||||
1
notes-python/code/sql-runner/requirements.txt
Normal file
1
notes-python/code/sql-runner/requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
psycopg2-binary
|
||||||
39
notes-python/code/sql-runner/sql_runner.py
Normal file
39
notes-python/code/sql-runner/sql_runner.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# sql_runner.py — универсальный DDL/SQL исполнитель.
|
||||||
|
#
|
||||||
|
# Назначение: выполнять произвольные SQL запросы переданные через event.
|
||||||
|
# Используется ТОЛЬКО через sless_job (init.tf) — HTTP-триггера нет намеренно,
|
||||||
|
# чтобы никто снаружи не мог выполнить произвольный SQL.
|
||||||
|
#
|
||||||
|
# Входящий event:
|
||||||
|
# {
|
||||||
|
# "statements": [
|
||||||
|
# "CREATE TABLE IF NOT EXISTS ...",
|
||||||
|
# "CREATE INDEX IF NOT EXISTS ..."
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# Все statements выполняются последовательно в одной транзакции.
|
||||||
|
# Если хотя бы один упал — транзакция откатывается целиком.
|
||||||
|
import os
|
||||||
|
import psycopg2
|
||||||
|
|
||||||
|
|
||||||
|
def run_sql(event):
|
||||||
|
dsn = os.environ['PG_DSN']
|
||||||
|
statements = event.get('statements', [])
|
||||||
|
if not statements:
|
||||||
|
return {'error': 'no statements provided'}
|
||||||
|
|
||||||
|
conn = psycopg2.connect(dsn)
|
||||||
|
try:
|
||||||
|
cur = conn.cursor()
|
||||||
|
for sql in statements:
|
||||||
|
cur.execute(sql)
|
||||||
|
conn.commit()
|
||||||
|
return {'ok': True, 'executed': len(statements)}
|
||||||
|
except Exception as e:
|
||||||
|
conn.rollback()
|
||||||
|
return {'error': str(e)}
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
44
notes-python/init.tf
Normal file
44
notes-python/init.tf
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# init.tf — однократная инициализация схемы БД через sless_job.
|
||||||
|
#
|
||||||
|
# Джобы запускаются один раз при terraform apply и ждут завершения.
|
||||||
|
# Использует функцию sql_runner (без HTTP-триггера) для безопасного DDL.
|
||||||
|
#
|
||||||
|
# Порядок выполнения гарантирован через depends_on:
|
||||||
|
# 1. notes_table_init — создаём таблицу
|
||||||
|
# 2. notes_index_init — создаём индекс (требует таблицу)
|
||||||
|
#
|
||||||
|
# Для повторного запуска (например, после DROP TABLE) — увеличь run_id.
|
||||||
|
# run_id отслеживается в state: при изменении terraform перезапустит джоб.
|
||||||
|
|
||||||
|
# Джоб создания таблицы notes.
|
||||||
|
# CREATE TABLE IF NOT EXISTS — безопасно запускать повторно, таблица не пересоздаётся.
|
||||||
|
resource "sless_job" "notes_table_init" {
|
||||||
|
name = "notes-create-table"
|
||||||
|
function = sless_function.sql_runner.name
|
||||||
|
wait_timeout_sec = 120
|
||||||
|
run_id = 1
|
||||||
|
|
||||||
|
event_json = jsonencode({
|
||||||
|
statements = [
|
||||||
|
"CREATE TABLE IF NOT EXISTS notes (id serial PRIMARY KEY, title text NOT NULL, body text, created_at timestamp DEFAULT now())"
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
# Джоб создания индекса для сортировки по дате.
|
||||||
|
# depends_on гарантирует, что таблица уже создана до создания индекса.
|
||||||
|
resource "sless_job" "notes_index_init" {
|
||||||
|
depends_on = [sless_job.notes_table_init]
|
||||||
|
|
||||||
|
name = "notes-create-index"
|
||||||
|
function = sless_function.sql_runner.name
|
||||||
|
wait_timeout_sec = 60
|
||||||
|
run_id = 1
|
||||||
|
|
||||||
|
event_json = jsonencode({
|
||||||
|
statements = [
|
||||||
|
"CREATE INDEX IF NOT EXISTS notes_created_idx ON notes(created_at DESC)"
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
27
notes-python/main.tf
Normal file
27
notes-python/main.tf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# main.tf — конфигурация terraform и провайдеров.
|
||||||
|
#
|
||||||
|
# Все ресурсы вынесены в отдельные .tf файлы по назначению:
|
||||||
|
# variables.tf — входные переменные (pg_dsn)
|
||||||
|
# sql-runner.tf — служебная DDL-функция (без HTTP-триггера)
|
||||||
|
# init.tf — однократная инициализация схемы БД
|
||||||
|
# notes.tf — CRUD функция + HTTP-триггер
|
||||||
|
# notes-list.tf — read-only функция + HTTP-триггер
|
||||||
|
# outputs.tf — URLs развёрнутых эндпоинтов
|
||||||
|
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
# Провайдер для управления serverless функциями через sless API
|
||||||
|
sless = {
|
||||||
|
source = "terra.k8c.ru/naeel/sless"
|
||||||
|
version = "~> 0.1.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# sless провайдер подключается к API кластера.
|
||||||
|
# В продакшне token следует передавать через TF_VAR или secrets.
|
||||||
|
provider "sless" {
|
||||||
|
endpoint = "https://sless-api.kube5s.ru"
|
||||||
|
token = "dev-token-change-me"
|
||||||
|
}
|
||||||
22
notes-python/notes-list.tf
Normal file
22
notes-python/notes-list.tf
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# notes-list.tf — read-only эндпоинт: возвращает все заметки, сортировка новые первые.
|
||||||
|
|
||||||
|
resource "sless_function" "notes_list" {
|
||||||
|
name = "notes-list"
|
||||||
|
runtime = "python3.11"
|
||||||
|
entrypoint = "notes_list.list_notes"
|
||||||
|
memory_mb = 128
|
||||||
|
timeout_sec = 30
|
||||||
|
|
||||||
|
env_vars = {
|
||||||
|
PG_DSN = var.pg_dsn
|
||||||
|
}
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code/notes-list"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "sless_trigger" "notes_list_http" {
|
||||||
|
name = "notes-list-http"
|
||||||
|
type = "http"
|
||||||
|
function = sless_function.notes_list.name
|
||||||
|
}
|
||||||
27
notes-python/notes.tf
Normal file
27
notes-python/notes.tf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# notes.tf — CRUD функция для управления заметками (CREATE / UPDATE / DELETE).
|
||||||
|
#
|
||||||
|
# Маршруты (рекомендуется POST):
|
||||||
|
# /fn/default/notes/add?title=...&body=... → INSERT
|
||||||
|
# /fn/default/notes/update?id=1&title=...&body=... → UPDATE
|
||||||
|
# /fn/default/notes/delete?id=1 → DELETE
|
||||||
|
|
||||||
|
resource "sless_function" "notes_crud" {
|
||||||
|
name = "notes"
|
||||||
|
runtime = "python3.11"
|
||||||
|
entrypoint = "notes_crud.crud"
|
||||||
|
memory_mb = 128
|
||||||
|
timeout_sec = 30
|
||||||
|
|
||||||
|
env_vars = {
|
||||||
|
PG_DSN = var.pg_dsn
|
||||||
|
}
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code/notes"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "sless_trigger" "notes_crud_http" {
|
||||||
|
name = "notes-http"
|
||||||
|
type = "http"
|
||||||
|
function = sless_function.notes_crud.name
|
||||||
|
}
|
||||||
42
notes-python/outputs.tf
Normal file
42
notes-python/outputs.tf
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# outputs.tf — публичные URL развёрнутых функций.
|
||||||
|
#
|
||||||
|
# После terraform apply используй эти URLs для тестирования:
|
||||||
|
# terraform output notes_url → базовый URL для CRUD
|
||||||
|
# terraform output notes_list_url → URL для получения всех записей
|
||||||
|
|
||||||
|
# URL CRUD-функции (notes_crud).
|
||||||
|
# Базовый URL — к нему добавляй sub-path:
|
||||||
|
# POST $(terraform output -raw notes_url)/add?title=Hello&body=World
|
||||||
|
# POST $(terraform output -raw notes_url)/update?id=1&title=Updated
|
||||||
|
# POST $(terraform output -raw notes_url)/delete?id=1
|
||||||
|
output "notes_url" {
|
||||||
|
value = sless_trigger.notes_crud_http.url
|
||||||
|
description = "CRUD: /add?title=...&body=..., /update?id=X&title=...&body=..., /delete?id=X"
|
||||||
|
}
|
||||||
|
|
||||||
|
# URL read-only функции (notes_list).
|
||||||
|
# Принимает GET или POST, параметры игнорирует, возвращает все записи.
|
||||||
|
output "notes_list_url" {
|
||||||
|
value = sless_trigger.notes_list_http.url
|
||||||
|
description = "Список всех записей (GET или POST)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Статус init-джобов — показывает результат инициализации БД.
|
||||||
|
# Если phase="Succeeded" — таблица и индекс созданы успешно.
|
||||||
|
# Если phase="Failed" — смотри message, исправь и увеличь run_id в init.tf.
|
||||||
|
output "db_init_table_status" {
|
||||||
|
value = {
|
||||||
|
phase = sless_job.notes_table_init.phase
|
||||||
|
message = sless_job.notes_table_init.message
|
||||||
|
}
|
||||||
|
description = "Статус джоба создания таблицы notes"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "db_init_index_status" {
|
||||||
|
value = {
|
||||||
|
phase = sless_job.notes_index_init.phase
|
||||||
|
message = sless_job.notes_index_init.message
|
||||||
|
}
|
||||||
|
description = "Статус джоба создания индекса"
|
||||||
|
}
|
||||||
20
notes-python/sql-runner.tf
Normal file
20
notes-python/sql-runner.tf
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# sql-runner.tf — служебная DDL-функция для инициализации и миграций БД.
|
||||||
|
#
|
||||||
|
# ВАЖНО: эта функция не имеет HTTP-триггера — только вызов через sless_job.
|
||||||
|
# Это сделано намеренно: функция выполняет произвольный SQL, и открывать её
|
||||||
|
# наружу через HTTP было бы небезопасно.
|
||||||
|
|
||||||
|
resource "sless_function" "sql_runner" {
|
||||||
|
name = "sql-runner"
|
||||||
|
runtime = "python3.11"
|
||||||
|
entrypoint = "sql_runner.run_sql"
|
||||||
|
memory_mb = 128
|
||||||
|
timeout_sec = 30
|
||||||
|
|
||||||
|
env_vars = {
|
||||||
|
PG_DSN = var.pg_dsn
|
||||||
|
}
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code/sql-runner"
|
||||||
|
}
|
||||||
15
notes-python/variables.tf
Normal file
15
notes-python/variables.tf
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# 2026-03-09
|
||||||
|
# variables.tf — входные переменные для notes-python примера.
|
||||||
|
#
|
||||||
|
# PG_DSN передаётся во все функции через env_vars.
|
||||||
|
# Хранится как sensitive чтобы не светился в terraform output и логах.
|
||||||
|
# В продакшне — не хардкоди DSN здесь, используй TF_VAR_pg_dsn или secrets manager.
|
||||||
|
|
||||||
|
# DSN для подключения к PostgreSQL внутри кластера.
|
||||||
|
# Формат: postgres://user:password@host:port/dbname?sslmode=...
|
||||||
|
variable "pg_dsn" {
|
||||||
|
description = "PostgreSQL DSN для подключения к БД внутри кластера"
|
||||||
|
type = string
|
||||||
|
default = "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
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() };
|
||||||
|
};
|
||||||
30
simple-node/main.tf
Normal file
30
simple-node/main.tf
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Создано: 2026-03-09
|
||||||
|
# main.tf — пример: запустить один раз скрипт при деплое и передать его результат в функцию.
|
||||||
|
# То же самое что simple-python, но на Node.js 20.
|
||||||
|
#
|
||||||
|
# Как это работает:
|
||||||
|
# 1. При «terraform apply» запускается скрипт-джоб (time_getter)
|
||||||
|
# 2. Скрипт возвращает JSON с текущим временем
|
||||||
|
# 3. Terraform подхватывает этот JSON и передаёт в переменную окружения HTTP-функции (time_display)
|
||||||
|
# 4. Функция отдаёт время при каждом запросе
|
||||||
|
#
|
||||||
|
# Зачем такое нужно:
|
||||||
|
# Если данные нужны функции, но считаются один раз при деплое —
|
||||||
|
# напишите логику в джоб, а результат передайте через env_vars.
|
||||||
|
# Например: получить токен, версию схемы БД, время деплоя и т.д.
|
||||||
|
#
|
||||||
|
# namespace захардкодирован внутри провайдера, здесь ничего указывать.
|
||||||
|
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
sless = {
|
||||||
|
source = "terra.k8c.ru/naeel/sless"
|
||||||
|
version = "~> 0.1.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "sless" {
|
||||||
|
endpoint = "https://sless-api.kube5s.ru"
|
||||||
|
token = "dev-token-change-me"
|
||||||
|
}
|
||||||
14
simple-node/outputs.tf
Normal file
14
simple-node/outputs.tf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Создано: 2026-03-09
|
||||||
|
# outputs.tf — что выводит terraform после apply.
|
||||||
|
|
||||||
|
# Адрес вашей функции — откройте в браузере или вставьте в curl
|
||||||
|
output "display_url" {
|
||||||
|
description = "URL функции time_display"
|
||||||
|
value = sless_trigger.display_http.url
|
||||||
|
}
|
||||||
|
|
||||||
|
# Что вернул скрипт-джоб — именно это передано в функцию как JOB_TIME
|
||||||
|
output "job_result" {
|
||||||
|
description = "Результат выполнения скрипта time_getter"
|
||||||
|
value = sless_job.run_getter.message
|
||||||
|
}
|
||||||
28
simple-node/time-display.tf
Normal file
28
simple-node/time-display.tf
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Создано: 2026-03-09 / Изменено: 2026-03-09
|
||||||
|
# time-display.tf — HTTP-функция, доступная по URL после apply.
|
||||||
|
# Получает результат джоба (из time-getter.tf) через переменную окружения JOB_TIME.
|
||||||
|
|
||||||
|
# HTTP-функция — отвечает на запросы по URL из outputs.tf
|
||||||
|
resource "sless_function" "time_display" {
|
||||||
|
name = "simple-node-time-display" # уникальное имя в namespace
|
||||||
|
runtime = "nodejs20"
|
||||||
|
entrypoint = "time_display.showTime" # файл.функция в code/time_display/
|
||||||
|
memory_mb = 64
|
||||||
|
|
||||||
|
# Передаём результат джоба в функцию через переменную окружения.
|
||||||
|
# В коде функции: process.env.JOB_TIME
|
||||||
|
env_vars = {
|
||||||
|
JOB_TIME = sless_job.run_getter.message
|
||||||
|
}
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code/time_display"
|
||||||
|
|
||||||
|
depends_on = [sless_job.run_getter] # ждём завершения джоба перед деплоем функции
|
||||||
|
}
|
||||||
|
|
||||||
|
# Публикуем функцию по HTTP — URL будет в outputs.tf
|
||||||
|
resource "sless_trigger" "display_http" {
|
||||||
|
name = "simple-node-display-http"
|
||||||
|
type = "http"
|
||||||
|
function = sless_function.time_display.name
|
||||||
|
}
|
||||||
27
simple-node/time-getter.tf
Normal file
27
simple-node/time-getter.tf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Создано: 2026-03-09 / Изменено: 2026-03-09
|
||||||
|
# time-getter.tf — скрипт который запускается ОДИН РАЗ при terraform apply.
|
||||||
|
# После запуска его результат доступен через: sless_job.run_getter.message
|
||||||
|
# Смотри time-display.tf — там этот результат передаётся в функцию.
|
||||||
|
|
||||||
|
# Функция для скрипта — без HTTP-триггера, вызывается только через джоб ниже
|
||||||
|
resource "sless_function" "time_getter" {
|
||||||
|
name = "simple-node-time-getter" # уникальное имя в namespace
|
||||||
|
runtime = "nodejs20"
|
||||||
|
entrypoint = "time_getter.getTime" # файл.функция в code/time_getter/
|
||||||
|
memory_mb = 64
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code/time_getter"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Джоб — запускает функцию time_getter один раз прямо при apply.
|
||||||
|
# run_id = 1 означает «запустить». Если увеличить (2, 3...) — запустится снова.
|
||||||
|
# После завершения: sless_job.run_getter.message = то что вернула функция
|
||||||
|
resource "sless_job" "run_getter" {
|
||||||
|
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({})))
|
||||||
29
simple-python/main.tf
Normal file
29
simple-python/main.tf
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Создано: 2026-03-09
|
||||||
|
# main.tf — пример: запустить один раз скрипт при деплое и передать его результат в функцию.
|
||||||
|
#
|
||||||
|
# Как это работает:
|
||||||
|
# 1. При «terraform apply» запускается скрипт-джоб (time_getter)
|
||||||
|
# 2. Скрипт возвращает JSON с текущим временем
|
||||||
|
# 3. Terraform подхватывает этот JSON и передаёт в переменную окружения HTTP-функции (time_display)
|
||||||
|
# 4. Функция отдаёт время при каждом запросе
|
||||||
|
#
|
||||||
|
# Зачем такое нужно:
|
||||||
|
# Если данные нужны функции, но считаются один раз при деплое —
|
||||||
|
# напишите логику в джоб, а результат передайте через env_vars.
|
||||||
|
# Например: получить токен, версию схемы БД, время деплоя и т.д.
|
||||||
|
#
|
||||||
|
# namespace захардкодирован внутри провайдера, здесь ничего указывать.
|
||||||
|
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
sless = {
|
||||||
|
source = "terra.k8c.ru/naeel/sless"
|
||||||
|
version = "~> 0.1.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
# Адрес вашей функции — откройте в браузере или вставьте в curl
|
||||||
|
output "display_url" {
|
||||||
|
description = "URL функции time_display"
|
||||||
|
value = sless_trigger.display_http.url
|
||||||
|
}
|
||||||
|
|
||||||
|
# Что вернул скрипт-джоб — именно это передано в функцию как JOB_TIME
|
||||||
|
output "job_result" {
|
||||||
|
description = "Результат выполнения скрипта time_getter"
|
||||||
|
value = sless_job.run_getter.message
|
||||||
|
}
|
||||||
28
simple-python/time-display.tf
Normal file
28
simple-python/time-display.tf
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Создано: 2026-03-09 / Изменено: 2026-03-09
|
||||||
|
# time-display.tf — HTTP-функция, доступная по URL после apply.
|
||||||
|
# Получает результат джоба (из time-getter.tf) через переменную окружения JOB_TIME.
|
||||||
|
|
||||||
|
# HTTP-функция — отвечает на запросы по URL из outputs.tf
|
||||||
|
resource "sless_function" "time_display" {
|
||||||
|
name = "simple-py-time-display" # уникальное имя в namespace
|
||||||
|
runtime = "python3.11"
|
||||||
|
entrypoint = "time_display.show_time" # файл.функция в code/time_display/
|
||||||
|
memory_mb = 64
|
||||||
|
|
||||||
|
# Передаём результат джоба в функцию через переменную окружения.
|
||||||
|
# В коде функции: os.environ.get("JOB_TIME")
|
||||||
|
env_vars = {
|
||||||
|
JOB_TIME = sless_job.run_getter.message
|
||||||
|
}
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code/time_display"
|
||||||
|
|
||||||
|
depends_on = [sless_job.run_getter] # ждём завершения джоба перед деплоем функции
|
||||||
|
}
|
||||||
|
|
||||||
|
# Публикуем функцию по HTTP — URL будет в outputs.tf
|
||||||
|
resource "sless_trigger" "display_http" {
|
||||||
|
name = "simple-py-display-http"
|
||||||
|
type = "http"
|
||||||
|
function = sless_function.time_display.name
|
||||||
|
}
|
||||||
27
simple-python/time-getter.tf
Normal file
27
simple-python/time-getter.tf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Создано: 2026-03-09 / Изменено: 2026-03-09
|
||||||
|
# time-getter.tf — скрипт который запускается ОДИН РАЗ при terraform apply.
|
||||||
|
# После запуска его результат доступен через: sless_job.run_getter.message
|
||||||
|
# Смотри time-display.tf — там этот результат передаётся в функцию.
|
||||||
|
|
||||||
|
# Функция для скрипта — без HTTP-триггера, вызывается только через джоб ниже
|
||||||
|
resource "sless_function" "time_getter" {
|
||||||
|
name = "simple-py-time-getter" # уникальное имя в namespace
|
||||||
|
runtime = "python3.11"
|
||||||
|
entrypoint = "time_getter.get_time" # файл.функция в code/time_getter/
|
||||||
|
memory_mb = 64
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code/time_getter"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Джоб — запускает функцию time_getter один раз прямо при apply.
|
||||||
|
# run_id = 1 означает «запустить». Если увеличить (2, 3...) — запустится снова.
|
||||||
|
# После завершения: sless_job.run_getter.message = то что вернула функция
|
||||||
|
resource "sless_job" "run_getter" {
|
||||||
|
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