refactor: notes-python — описательные имена файлов/ресурсов + комментарии

Python файлы:
- handler.py → sql_runner.py   (entrypoint: sql_runner.handle)
- handler.py → notes_crud.py   (entrypoint: notes_crud.handle)
- handler.py → notes_list.py   (entrypoint: notes_list.handle)

TF ресурсы переименованы:
- sless_function.notes         → sless_function.notes_crud
- sless_trigger.notes_http     → sless_trigger.notes_crud_http
- sless_job.create_table       → sless_job.notes_table_init
- sless_job.create_index       → sless_job.notes_index_init
- archive_file.notes           → archive_file.notes_crud_zip
- archive_file.sql_runner      → archive_file.sql_runner_zip
- archive_file.notes_list      → archive_file.notes_list_zip

Добавлены подробные комментарии во все .tf файлы
This commit is contained in:
“Naeel” 2026-03-09 10:10:43 +04:00
parent daf750e89d
commit 49035d35f0
19 changed files with 1656 additions and 98 deletions

View File

@ -1,22 +0,0 @@
# 2026-03-09
# handler.py — возвращает все записи из таблицы notes.
# GET/POST /fn/default/notes-list → JSON массив записей, сортировка по created_at DESC.
import os
import psycopg2
import psycopg2.extras
def handle(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()

View 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 handle(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()

View File

@ -1,10 +1,17 @@
# 2026-03-09 # 2026-03-09
# handler.py — CRUD роутер для таблицы notes. # notes_crud.py — CRUD роутер для таблицы notes.
# Роутинг по event._path (sub-path URL): #
# POST /fn/default/notes/add?title=...&body=... → INSERT # Назначение: единая функция, которая обрабатывает все операции с записями.
# POST /fn/default/notes/update?id=1&title=... → UPDATE # Роутинг осуществляется по sub-path URL (event._path), который runtime
# POST /fn/default/notes/delete?id=1 → DELETE # берёт из входящего HTTP-запроса и добавляет в event автоматически.
# _path и _query добавляет runtime из HTTP запроса (server.py). #
# Доступные маршруты (все 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 os
import psycopg2 import psycopg2
import psycopg2.extras import psycopg2.extras

View File

@ -1,26 +0,0 @@
# 2026-03-09
# handler.py — универсальный исполнитель SQL запросов.
# Принимает event.statements — массив SQL строк, выполняет последовательно.
# Используется sless_job для DDL операций (CREATE TABLE, миграции и т.д.)
import os
import psycopg2
def handle(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()

View 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 handle(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()

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +1,19 @@
# 2025-06-05 # 2026-03-09
# init.tf джобы инициализации БД: создание таблицы + индекса. # init.tf однократная инициализация схемы БД через sless_job.
# Запускаются один раз при terraform apply. #
# Для повторного запуска (например после drop) увеличь run_id. # Джобы запускаются один раз при terraform apply и ждут завершения.
# Использует функцию sql_runner (без HTTP-триггера) для безопасного DDL.
#
# Порядок выполнения гарантирован через depends_on:
# 1. notes_table_init создаём таблицу
# 2. notes_index_init создаём индекс (требует таблицу)
#
# Для повторного запуска (например, после DROP TABLE) увеличь run_id.
# run_id отслеживается в state: при изменении terraform перезапустит джоб.
resource "sless_job" "create_table" { # Джоб создания таблицы notes.
# CREATE TABLE IF NOT EXISTS безопасно запускать повторно, таблица не пересоздаётся.
resource "sless_job" "notes_table_init" {
namespace = "default" namespace = "default"
name = "notes-create-table" name = "notes-create-table"
function = sless_function.sql_runner.name function = sless_function.sql_runner.name
@ -17,8 +27,10 @@ resource "sless_job" "create_table" {
}) })
} }
resource "sless_job" "create_index" { # Джоб создания индекса для сортировки по дате.
depends_on = [sless_job.create_table] # depends_on гарантирует, что таблица уже создана до создания индекса.
resource "sless_job" "notes_index_init" {
depends_on = [sless_job.notes_table_init]
namespace = "default" namespace = "default"
name = "notes-create-index" name = "notes-create-index"

View File

@ -1,13 +1,22 @@
# 2025-06-05 # 2026-03-09
# main.tf terraform{} + provider для notes-python примера. # main.tf конфигурация terraform и провайдеров.
# Ресурсы вынесены в отдельные .tf файлы. #
# Все ресурсы вынесены в отдельные .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 { terraform {
required_providers { required_providers {
# Провайдер для управления serverless функциями через sless API
sless = { sless = {
source = "terra.k8c.ru/naeel/sless" source = "terra.k8c.ru/naeel/sless"
version = "~> 0.1.7" version = "~> 0.1.7"
} }
# hashicorp/archive для упаковки исходников в zip перед загрузкой
archive = { archive = {
source = "hashicorp/archive" source = "hashicorp/archive"
version = "~> 2.0" version = "~> 2.0"
@ -15,6 +24,8 @@ terraform {
} }
} }
# sless провайдер подключается к API кластера.
# В продакшне token следует передавать через TF_VAR или secrets.
provider "sless" { provider "sless" {
endpoint = "https://sless-api.kube5s.ru" endpoint = "https://sless-api.kube5s.ru"
token = "dev-token-change-me" token = "dev-token-change-me"

View File

@ -1,18 +1,27 @@
# 2025-06-05 # 2026-03-09
# notes-list.tf функция для получения всех записей из таблицы notes. # notes-list.tf функция для чтения всех заметок одним запросом.
# GET или POST /fn/default/notes-list JSON массив всех записей, сортировка по дате (новые первые). #
# Отдельная от CRUD функция «read-only» эндпоинт без роутинга.
# Принимает GET или POST, параметры игнорирует.
# Возвращает JSON-массив всех записей, сортировка: новые первые.
#
# Пример запроса:
# curl https://sless-api.kube5s.ru/fn/default/notes-list
data "archive_file" "notes_list" { # Упаковка исходников notes_list.py в zip.
data "archive_file" "notes_list_zip" {
type = "zip" type = "zip"
source_dir = "${path.module}/code/notes-list" source_dir = "${path.module}/code/notes-list"
output_path = "${path.module}/dist/notes-list.zip" output_path = "${path.module}/dist/notes-list.zip"
} }
# Read-only функция в кластере.
# entrypoint = "notes_list.handle" файл notes_list.py, функция handle().
resource "sless_function" "notes_list" { resource "sless_function" "notes_list" {
namespace = "default" namespace = "default"
name = "notes-list" name = "notes-list"
runtime = "python3.11" runtime = "python3.11"
entrypoint = "handler.handle" entrypoint = "notes_list.handle"
memory_mb = 128 memory_mb = 128
timeout_sec = 30 timeout_sec = 30
@ -20,10 +29,12 @@ resource "sless_function" "notes_list" {
PG_DSN = var.pg_dsn PG_DSN = var.pg_dsn
} }
code_path = data.archive_file.notes_list.output_path code_path = data.archive_file.notes_list_zip.output_path
code_hash = filesha256("${path.module}/code/notes-list/handler.py") code_hash = filesha256("${path.module}/code/notes-list/notes_list.py")
} }
# HTTP-триггер для read-only функции.
# Создаёт Ingress, URL доступен в outputs.tf.
resource "sless_trigger" "notes_list_http" { resource "sless_trigger" "notes_list_http" {
namespace = "default" namespace = "default"
name = "notes-list-http" name = "notes-list-http"

View File

@ -1,21 +1,29 @@
# 2025-06-05 # 2026-03-09
# notes.tf CRUD функция для таблицы notes. # notes.tf CRUD функция для управления заметками (CREATE / UPDATE / DELETE).
# Роутинг по sub-path URL: #
# POST /fn/default/notes/add?title=...&body=... INSERT записи # Одна функция обрабатывает все операции роутинг по sub-path URL.
# POST /fn/default/notes/update?id=1&title=...&body=... UPDATE записи # Sub-path и query string пробрасывает прокси (invoke.go) runtime добавляет
# POST /fn/default/notes/delete?id=1 DELETE записи # их в event как _path и _query.
#
# Маршруты (все методы принимаются, рекомендуется POST):
# /fn/default/notes/add?title=...&body=... INSERT, возвращает запись
# /fn/default/notes/update?id=1&title=...&body=... UPDATE, возвращает запись
# /fn/default/notes/delete?id=1 DELETE, возвращает {deleted: id}
data "archive_file" "notes" { # Упаковка исходников notes_crud.py в zip.
data "archive_file" "notes_crud_zip" {
type = "zip" type = "zip"
source_dir = "${path.module}/code/notes" source_dir = "${path.module}/code/notes"
output_path = "${path.module}/dist/notes.zip" output_path = "${path.module}/dist/notes.zip"
} }
resource "sless_function" "notes" { # CRUD функция в кластере.
# entrypoint = "notes_crud.handle" файл notes_crud.py, функция handle().
resource "sless_function" "notes_crud" {
namespace = "default" namespace = "default"
name = "notes" name = "notes"
runtime = "python3.11" runtime = "python3.11"
entrypoint = "handler.handle" entrypoint = "notes_crud.handle"
memory_mb = 128 memory_mb = 128
timeout_sec = 30 timeout_sec = 30
@ -23,13 +31,16 @@ resource "sless_function" "notes" {
PG_DSN = var.pg_dsn PG_DSN = var.pg_dsn
} }
code_path = data.archive_file.notes.output_path code_path = data.archive_file.notes_crud_zip.output_path
code_hash = filesha256("${path.module}/code/notes/handler.py") code_hash = filesha256("${path.module}/code/notes/notes_crud.py")
} }
resource "sless_trigger" "notes_http" { # HTTP-триггер для CRUD функции.
# Создаёт Ingress в кластере, URL доступен в outputs.tf.
# Базовый URL: https://sless-api.kube5s.ru/fn/default/notes
resource "sless_trigger" "notes_crud_http" {
namespace = "default" namespace = "default"
name = "notes-http" name = "notes-http"
type = "http" type = "http"
function = sless_function.notes.name function = sless_function.notes_crud.name
} }

View File

@ -1,12 +1,23 @@
# 2025-06-05 # 2026-03-09
# outputs.tf URL эндпоинтов для notes-python примера. # 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" { output "notes_url" {
value = sless_trigger.notes_http.url value = sless_trigger.notes_crud_http.url
description = "Базовый URL CRUD: /add?title=...&body=..., /update?id=X&title=...&body=..., /delete?id=X" description = "CRUD: /add?title=...&body=..., /update?id=X&title=...&body=..., /delete?id=X"
} }
# URL read-only функции (notes_list).
# Принимает GET или POST, параметры игнорирует, возвращает все записи.
output "notes_list_url" { output "notes_list_url" {
value = sless_trigger.notes_list_http.url value = sless_trigger.notes_list_http.url
description = "URL для получения всех записей (GET или POST)" description = "Список всех записей (GET или POST)"
} }

View File

@ -1,19 +1,26 @@
# 2025-06-05 # 2026-03-09
# sql-runner.tf универсальная функция для выполнения SQL запросов. # sql-runner.tf служебная DDL-функция для инициализации и миграций БД.
# Используется джобами для DDL операций (CREATE TABLE, индексы, миграции). #
# event.statements массив SQL строк, выполняются последовательно в одной транзакции. # ВАЖНО: эта функция не имеет HTTP-триггера только вызов через sless_job.
# Это сделано намеренно: функция выполняет произвольный SQL, и открывать её
# наружу через HTTP было бы небезопасно.
data "archive_file" "sql_runner" { # Упаковка исходников в zip для загрузки в кластер.
# archive_file пересоздаёт zip при изменении любого файла в source_dir.
data "archive_file" "sql_runner_zip" {
type = "zip" type = "zip"
source_dir = "${path.module}/code/sql-runner" source_dir = "${path.module}/code/sql-runner"
output_path = "${path.module}/dist/sql-runner.zip" output_path = "${path.module}/dist/sql-runner.zip"
} }
# Сама функция в кластере.
# entrypoint = "sql_runner.handle" файл sql_runner.py, функция handle().
# memory_mb=128 достаточно DDL запросы не требуют памяти на вычисления.
resource "sless_function" "sql_runner" { resource "sless_function" "sql_runner" {
namespace = "default" namespace = "default"
name = "sql-runner" name = "sql-runner"
runtime = "python3.11" runtime = "python3.11"
entrypoint = "handler.handle" entrypoint = "sql_runner.handle"
memory_mb = 128 memory_mb = 128
timeout_sec = 30 timeout_sec = 30
@ -21,6 +28,7 @@ resource "sless_function" "sql_runner" {
PG_DSN = var.pg_dsn PG_DSN = var.pg_dsn
} }
code_path = data.archive_file.sql_runner.output_path code_path = data.archive_file.sql_runner_zip.output_path
code_hash = filesha256("${path.module}/code/sql-runner/handler.py") # code_hash при изменении кода terraform пересобирает образ функции
code_hash = filesha256("${path.module}/code/sql-runner/sql_runner.py")
} }

View File

@ -0,0 +1,369 @@
{
"version": 4,
"terraform_version": "1.12.2",
"serial": 15,
"lineage": "46b43916-6d6b-060c-ad36-6176e18b5f7b",
"outputs": {
"notes_list_url": {
"value": "https://sless-api.kube5s.ru/fn/default/notes-list",
"type": "string"
},
"notes_url": {
"value": "https://sless-api.kube5s.ru/fn/default/notes",
"type": "string"
}
},
"resources": [
{
"mode": "data",
"type": "archive_file",
"name": "notes",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "d1fed6f90a4b4fde556aa2cd18e6ffaa9877c377",
"output_base64sha256": "HMlgBvSu0gccGVilru2ybzC7v31uzG1Zy96bK4p+C1E=",
"output_base64sha512": "GoV68HbQgbVaBtR4v1kLUhh+kMpJRIoBz30SrgYlVGz13SzV1wZ/lPvedqYvhmirG0fQf63wHYThOmvOR7lvgQ==",
"output_file_mode": null,
"output_md5": "cf96673e4f09c58d2e49c1664cdee1c2",
"output_path": "./dist/notes.zip",
"output_sha": "d1fed6f90a4b4fde556aa2cd18e6ffaa9877c377",
"output_sha256": "1cc96006f4aed2071c1958a5aeedb26f30bbbf7d6ecc6d59cbde9b2b8a7e0b51",
"output_sha512": "1a857af076d081b55a06d478bf590b52187e90ca49448a01cf7d12ae0625546cf5dd2cd5d7067f94fbde76a62f8668ab1b47d07fadf01d84e13a6bce47b96f81",
"output_size": 1226,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/notes",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "data",
"type": "archive_file",
"name": "notes_list",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "b5730a0d98ae778f80c27881147e14d060151fce",
"output_base64sha256": "1pbtfCE8qjpAP5Ddz9c9afhOUXq3aq56ordi5t4vX00=",
"output_base64sha512": "nTUnbRKT4d5g5g3HANTGxZi5FmUIaM3C660XzZmGQLJIQ+WNYNLJ/no/H30KzafwE1mJf2qkdcZ8cT3xZdciNg==",
"output_file_mode": null,
"output_md5": "090088f39e1ef9d8d7d152944441edb7",
"output_path": "./dist/notes-list.zip",
"output_sha": "b5730a0d98ae778f80c27881147e14d060151fce",
"output_sha256": "d696ed7c213caa3a403f90ddcfd73d69f84e517ab76aae7aa2b762e6de2f5f4d",
"output_sha512": "9d35276d1293e1de60e60dc700d4c6c598b916650868cdc2ebad17cd998640b24843e58d60d2c9fe7a3f1f7d0acda7f01359897f6aa475c67c713df165d72236",
"output_size": 746,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/notes-list",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "data",
"type": "archive_file",
"name": "sql_runner",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "241f12b31b5d970c697341292954b220e44f8d2a",
"output_base64sha256": "w/IUipIki9V1lf33x06/gHq+KWVdfJO9Ni98DkhC+Xw=",
"output_base64sha512": "aLpBXApQ5Nltm6ODUqQc6VZQCoxgn68mHlcrOF8bFrdem8psnz7dujkJE5PYvB5VDNKmdsViDAKPNTwHxut4XA==",
"output_file_mode": null,
"output_md5": "1fe2ab7afe4730b1141146363d69bd23",
"output_path": "./dist/sql-runner.zip",
"output_sha": "241f12b31b5d970c697341292954b220e44f8d2a",
"output_sha256": "c3f2148a92248bd57595fdf7c74ebf807abe29655d7c93bd362f7c0e4842f97c",
"output_sha512": "68ba415c0a50e4d96d9ba38352a41ce956500a8c609faf261e572b385f1b16b75e9bca6c9f3eddba39091393d8bc1e550cd2a676c5620c028f353c07c6eb785c",
"output_size": 796,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/sql-runner",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "notes",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "aaefd6de16697af6ac7331c7e1795a5446c71e351e6cacc3f4b490b683feb0cb",
"code_path": "./dist/notes.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-notes:80b15a8b73f5",
"memory_mb": 128,
"name": "notes",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes"
]
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "notes_list",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "4091f7c79ca8c9c5663c812eb08f25ef5257af217bf2b412add670a4737b9d7f",
"code_path": "./dist/notes-list.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-notes-list:07f2d5ae5ee4",
"memory_mb": 128,
"name": "notes-list",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes_list"
]
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "sql_runner",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "fcde93e59e6fd7f3db426482da7667d5d402aaaaaf56f79a7a60bb1722ec603a",
"code_path": "./dist/sql-runner.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-sql-runner:22bce581a299",
"memory_mb": 128,
"name": "sql-runner",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner"
]
}
]
},
{
"mode": "managed",
"type": "sless_job",
"name": "create_index",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"completion_time": "2026-03-09T05:44:59Z",
"event_json": "{\"statements\":[\"CREATE INDEX IF NOT EXISTS notes_created_idx ON notes(created_at DESC)\"]}",
"function": "sql-runner",
"message": "completed successfully",
"name": "notes-create-index",
"namespace": "default",
"phase": "Succeeded",
"run_id": 1,
"start_time": "2026-03-09T05:44:54Z",
"wait_timeout_sec": 60
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner",
"sless_function.sql_runner",
"sless_job.create_table"
]
}
]
},
{
"mode": "managed",
"type": "sless_job",
"name": "create_table",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"completion_time": "2026-03-09T05:44:54Z",
"event_json": "{\"statements\":[\"CREATE TABLE IF NOT EXISTS notes (id serial PRIMARY KEY, title text NOT NULL, body text, created_at timestamp DEFAULT now())\"]}",
"function": "sql-runner",
"message": "completed successfully",
"name": "notes-create-table",
"namespace": "default",
"phase": "Succeeded",
"run_id": 1,
"start_time": "2026-03-09T05:44:39Z",
"wait_timeout_sec": 120
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner",
"sless_function.sql_runner"
]
}
]
},
{
"mode": "managed",
"type": "sless_trigger",
"name": "notes_http",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"active": true,
"enabled": true,
"function": "notes",
"name": "notes-http",
"namespace": "default",
"schedule": null,
"type": "http",
"url": "https://sless-api.kube5s.ru/fn/default/notes"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes",
"sless_function.notes"
]
}
]
},
{
"mode": "managed",
"type": "sless_trigger",
"name": "notes_list_http",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"active": true,
"enabled": true,
"function": "notes-list",
"name": "notes-list-http",
"namespace": "default",
"schedule": null,
"type": "http",
"url": "https://sless-api.kube5s.ru/fn/default/notes-list"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes_list",
"sless_function.notes_list"
]
}
]
}
],
"check_results": null
}

View File

@ -0,0 +1,365 @@
{
"version": 4,
"terraform_version": "1.12.2",
"serial": 16,
"lineage": "46b43916-6d6b-060c-ad36-6176e18b5f7b",
"outputs": {
"notes_list_url": {
"value": "https://sless-api.kube5s.ru/fn/default/notes-list",
"type": "string"
},
"notes_url": {
"value": "https://sless-api.kube5s.ru/fn/default/notes",
"type": "string"
}
},
"resources": [
{
"mode": "data",
"type": "archive_file",
"name": "notes",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "d1fed6f90a4b4fde556aa2cd18e6ffaa9877c377",
"output_base64sha256": "HMlgBvSu0gccGVilru2ybzC7v31uzG1Zy96bK4p+C1E=",
"output_base64sha512": "GoV68HbQgbVaBtR4v1kLUhh+kMpJRIoBz30SrgYlVGz13SzV1wZ/lPvedqYvhmirG0fQf63wHYThOmvOR7lvgQ==",
"output_file_mode": null,
"output_md5": "cf96673e4f09c58d2e49c1664cdee1c2",
"output_path": "./dist/notes.zip",
"output_sha": "d1fed6f90a4b4fde556aa2cd18e6ffaa9877c377",
"output_sha256": "1cc96006f4aed2071c1958a5aeedb26f30bbbf7d6ecc6d59cbde9b2b8a7e0b51",
"output_sha512": "1a857af076d081b55a06d478bf590b52187e90ca49448a01cf7d12ae0625546cf5dd2cd5d7067f94fbde76a62f8668ab1b47d07fadf01d84e13a6bce47b96f81",
"output_size": 1226,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/notes",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "data",
"type": "archive_file",
"name": "notes_list",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "b5730a0d98ae778f80c27881147e14d060151fce",
"output_base64sha256": "1pbtfCE8qjpAP5Ddz9c9afhOUXq3aq56ordi5t4vX00=",
"output_base64sha512": "nTUnbRKT4d5g5g3HANTGxZi5FmUIaM3C660XzZmGQLJIQ+WNYNLJ/no/H30KzafwE1mJf2qkdcZ8cT3xZdciNg==",
"output_file_mode": null,
"output_md5": "090088f39e1ef9d8d7d152944441edb7",
"output_path": "./dist/notes-list.zip",
"output_sha": "b5730a0d98ae778f80c27881147e14d060151fce",
"output_sha256": "d696ed7c213caa3a403f90ddcfd73d69f84e517ab76aae7aa2b762e6de2f5f4d",
"output_sha512": "9d35276d1293e1de60e60dc700d4c6c598b916650868cdc2ebad17cd998640b24843e58d60d2c9fe7a3f1f7d0acda7f01359897f6aa475c67c713df165d72236",
"output_size": 746,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/notes-list",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "data",
"type": "archive_file",
"name": "sql_runner",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "241f12b31b5d970c697341292954b220e44f8d2a",
"output_base64sha256": "w/IUipIki9V1lf33x06/gHq+KWVdfJO9Ni98DkhC+Xw=",
"output_base64sha512": "aLpBXApQ5Nltm6ODUqQc6VZQCoxgn68mHlcrOF8bFrdem8psnz7dujkJE5PYvB5VDNKmdsViDAKPNTwHxut4XA==",
"output_file_mode": null,
"output_md5": "1fe2ab7afe4730b1141146363d69bd23",
"output_path": "./dist/sql-runner.zip",
"output_sha": "241f12b31b5d970c697341292954b220e44f8d2a",
"output_sha256": "c3f2148a92248bd57595fdf7c74ebf807abe29655d7c93bd362f7c0e4842f97c",
"output_sha512": "68ba415c0a50e4d96d9ba38352a41ce956500a8c609faf261e572b385f1b16b75e9bca6c9f3eddba39091393d8bc1e550cd2a676c5620c028f353c07c6eb785c",
"output_size": 796,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/sql-runner",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "notes_crud",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "aaefd6de16697af6ac7331c7e1795a5446c71e351e6cacc3f4b490b683feb0cb",
"code_path": "./dist/notes.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-notes:80b15a8b73f5",
"memory_mb": 128,
"name": "notes",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes"
]
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "notes_list",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "4091f7c79ca8c9c5663c812eb08f25ef5257af217bf2b412add670a4737b9d7f",
"code_path": "./dist/notes-list.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-notes-list:07f2d5ae5ee4",
"memory_mb": 128,
"name": "notes-list",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes_list"
]
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "sql_runner",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "fcde93e59e6fd7f3db426482da7667d5d402aaaaaf56f79a7a60bb1722ec603a",
"code_path": "./dist/sql-runner.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-sql-runner:22bce581a299",
"memory_mb": 128,
"name": "sql-runner",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner"
]
}
]
},
{
"mode": "managed",
"type": "sless_job",
"name": "create_index",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"completion_time": "2026-03-09T05:44:59Z",
"event_json": "{\"statements\":[\"CREATE INDEX IF NOT EXISTS notes_created_idx ON notes(created_at DESC)\"]}",
"function": "sql-runner",
"message": "completed successfully",
"name": "notes-create-index",
"namespace": "default",
"phase": "Succeeded",
"run_id": 1,
"start_time": "2026-03-09T05:44:54Z",
"wait_timeout_sec": 60
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner",
"sless_function.sql_runner",
"sless_job.create_table"
]
}
]
},
{
"mode": "managed",
"type": "sless_job",
"name": "create_table",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"completion_time": "2026-03-09T05:44:54Z",
"event_json": "{\"statements\":[\"CREATE TABLE IF NOT EXISTS notes (id serial PRIMARY KEY, title text NOT NULL, body text, created_at timestamp DEFAULT now())\"]}",
"function": "sql-runner",
"message": "completed successfully",
"name": "notes-create-table",
"namespace": "default",
"phase": "Succeeded",
"run_id": 1,
"start_time": "2026-03-09T05:44:39Z",
"wait_timeout_sec": 120
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner",
"sless_function.sql_runner"
]
}
]
},
{
"mode": "managed",
"type": "sless_trigger",
"name": "notes_http",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"active": true,
"enabled": true,
"function": "notes",
"name": "notes-http",
"namespace": "default",
"schedule": null,
"type": "http",
"url": "https://sless-api.kube5s.ru/fn/default/notes"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "managed",
"type": "sless_trigger",
"name": "notes_list_http",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"active": true,
"enabled": true,
"function": "notes-list",
"name": "notes-list-http",
"namespace": "default",
"schedule": null,
"type": "http",
"url": "https://sless-api.kube5s.ru/fn/default/notes-list"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes_list",
"sless_function.notes_list"
]
}
]
}
],
"check_results": null
}

View File

@ -0,0 +1,365 @@
{
"version": 4,
"terraform_version": "1.12.2",
"serial": 17,
"lineage": "46b43916-6d6b-060c-ad36-6176e18b5f7b",
"outputs": {
"notes_list_url": {
"value": "https://sless-api.kube5s.ru/fn/default/notes-list",
"type": "string"
},
"notes_url": {
"value": "https://sless-api.kube5s.ru/fn/default/notes",
"type": "string"
}
},
"resources": [
{
"mode": "data",
"type": "archive_file",
"name": "notes",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "d1fed6f90a4b4fde556aa2cd18e6ffaa9877c377",
"output_base64sha256": "HMlgBvSu0gccGVilru2ybzC7v31uzG1Zy96bK4p+C1E=",
"output_base64sha512": "GoV68HbQgbVaBtR4v1kLUhh+kMpJRIoBz30SrgYlVGz13SzV1wZ/lPvedqYvhmirG0fQf63wHYThOmvOR7lvgQ==",
"output_file_mode": null,
"output_md5": "cf96673e4f09c58d2e49c1664cdee1c2",
"output_path": "./dist/notes.zip",
"output_sha": "d1fed6f90a4b4fde556aa2cd18e6ffaa9877c377",
"output_sha256": "1cc96006f4aed2071c1958a5aeedb26f30bbbf7d6ecc6d59cbde9b2b8a7e0b51",
"output_sha512": "1a857af076d081b55a06d478bf590b52187e90ca49448a01cf7d12ae0625546cf5dd2cd5d7067f94fbde76a62f8668ab1b47d07fadf01d84e13a6bce47b96f81",
"output_size": 1226,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/notes",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "data",
"type": "archive_file",
"name": "notes_list",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "b5730a0d98ae778f80c27881147e14d060151fce",
"output_base64sha256": "1pbtfCE8qjpAP5Ddz9c9afhOUXq3aq56ordi5t4vX00=",
"output_base64sha512": "nTUnbRKT4d5g5g3HANTGxZi5FmUIaM3C660XzZmGQLJIQ+WNYNLJ/no/H30KzafwE1mJf2qkdcZ8cT3xZdciNg==",
"output_file_mode": null,
"output_md5": "090088f39e1ef9d8d7d152944441edb7",
"output_path": "./dist/notes-list.zip",
"output_sha": "b5730a0d98ae778f80c27881147e14d060151fce",
"output_sha256": "d696ed7c213caa3a403f90ddcfd73d69f84e517ab76aae7aa2b762e6de2f5f4d",
"output_sha512": "9d35276d1293e1de60e60dc700d4c6c598b916650868cdc2ebad17cd998640b24843e58d60d2c9fe7a3f1f7d0acda7f01359897f6aa475c67c713df165d72236",
"output_size": 746,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/notes-list",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "data",
"type": "archive_file",
"name": "sql_runner",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "241f12b31b5d970c697341292954b220e44f8d2a",
"output_base64sha256": "w/IUipIki9V1lf33x06/gHq+KWVdfJO9Ni98DkhC+Xw=",
"output_base64sha512": "aLpBXApQ5Nltm6ODUqQc6VZQCoxgn68mHlcrOF8bFrdem8psnz7dujkJE5PYvB5VDNKmdsViDAKPNTwHxut4XA==",
"output_file_mode": null,
"output_md5": "1fe2ab7afe4730b1141146363d69bd23",
"output_path": "./dist/sql-runner.zip",
"output_sha": "241f12b31b5d970c697341292954b220e44f8d2a",
"output_sha256": "c3f2148a92248bd57595fdf7c74ebf807abe29655d7c93bd362f7c0e4842f97c",
"output_sha512": "68ba415c0a50e4d96d9ba38352a41ce956500a8c609faf261e572b385f1b16b75e9bca6c9f3eddba39091393d8bc1e550cd2a676c5620c028f353c07c6eb785c",
"output_size": 796,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/sql-runner",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "notes_crud",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "aaefd6de16697af6ac7331c7e1795a5446c71e351e6cacc3f4b490b683feb0cb",
"code_path": "./dist/notes.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-notes:80b15a8b73f5",
"memory_mb": 128,
"name": "notes",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes"
]
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "notes_list",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "4091f7c79ca8c9c5663c812eb08f25ef5257af217bf2b412add670a4737b9d7f",
"code_path": "./dist/notes-list.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-notes-list:07f2d5ae5ee4",
"memory_mb": 128,
"name": "notes-list",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes_list"
]
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "sql_runner",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "fcde93e59e6fd7f3db426482da7667d5d402aaaaaf56f79a7a60bb1722ec603a",
"code_path": "./dist/sql-runner.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-sql-runner:22bce581a299",
"memory_mb": 128,
"name": "sql-runner",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner"
]
}
]
},
{
"mode": "managed",
"type": "sless_job",
"name": "create_index",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"completion_time": "2026-03-09T05:44:59Z",
"event_json": "{\"statements\":[\"CREATE INDEX IF NOT EXISTS notes_created_idx ON notes(created_at DESC)\"]}",
"function": "sql-runner",
"message": "completed successfully",
"name": "notes-create-index",
"namespace": "default",
"phase": "Succeeded",
"run_id": 1,
"start_time": "2026-03-09T05:44:54Z",
"wait_timeout_sec": 60
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner",
"sless_function.sql_runner",
"sless_job.create_table"
]
}
]
},
{
"mode": "managed",
"type": "sless_job",
"name": "create_table",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"completion_time": "2026-03-09T05:44:54Z",
"event_json": "{\"statements\":[\"CREATE TABLE IF NOT EXISTS notes (id serial PRIMARY KEY, title text NOT NULL, body text, created_at timestamp DEFAULT now())\"]}",
"function": "sql-runner",
"message": "completed successfully",
"name": "notes-create-table",
"namespace": "default",
"phase": "Succeeded",
"run_id": 1,
"start_time": "2026-03-09T05:44:39Z",
"wait_timeout_sec": 120
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner",
"sless_function.sql_runner"
]
}
]
},
{
"mode": "managed",
"type": "sless_trigger",
"name": "notes_crud_http",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"active": true,
"enabled": true,
"function": "notes",
"name": "notes-http",
"namespace": "default",
"schedule": null,
"type": "http",
"url": "https://sless-api.kube5s.ru/fn/default/notes"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "managed",
"type": "sless_trigger",
"name": "notes_list_http",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"active": true,
"enabled": true,
"function": "notes-list",
"name": "notes-list-http",
"namespace": "default",
"schedule": null,
"type": "http",
"url": "https://sless-api.kube5s.ru/fn/default/notes-list"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes_list",
"sless_function.notes_list"
]
}
]
}
],
"check_results": null
}

View File

@ -0,0 +1,360 @@
{
"version": 4,
"terraform_version": "1.12.2",
"serial": 18,
"lineage": "46b43916-6d6b-060c-ad36-6176e18b5f7b",
"outputs": {
"notes_list_url": {
"value": "https://sless-api.kube5s.ru/fn/default/notes-list",
"type": "string"
},
"notes_url": {
"value": "https://sless-api.kube5s.ru/fn/default/notes",
"type": "string"
}
},
"resources": [
{
"mode": "data",
"type": "archive_file",
"name": "notes",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "d1fed6f90a4b4fde556aa2cd18e6ffaa9877c377",
"output_base64sha256": "HMlgBvSu0gccGVilru2ybzC7v31uzG1Zy96bK4p+C1E=",
"output_base64sha512": "GoV68HbQgbVaBtR4v1kLUhh+kMpJRIoBz30SrgYlVGz13SzV1wZ/lPvedqYvhmirG0fQf63wHYThOmvOR7lvgQ==",
"output_file_mode": null,
"output_md5": "cf96673e4f09c58d2e49c1664cdee1c2",
"output_path": "./dist/notes.zip",
"output_sha": "d1fed6f90a4b4fde556aa2cd18e6ffaa9877c377",
"output_sha256": "1cc96006f4aed2071c1958a5aeedb26f30bbbf7d6ecc6d59cbde9b2b8a7e0b51",
"output_sha512": "1a857af076d081b55a06d478bf590b52187e90ca49448a01cf7d12ae0625546cf5dd2cd5d7067f94fbde76a62f8668ab1b47d07fadf01d84e13a6bce47b96f81",
"output_size": 1226,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/notes",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "data",
"type": "archive_file",
"name": "notes_list",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "b5730a0d98ae778f80c27881147e14d060151fce",
"output_base64sha256": "1pbtfCE8qjpAP5Ddz9c9afhOUXq3aq56ordi5t4vX00=",
"output_base64sha512": "nTUnbRKT4d5g5g3HANTGxZi5FmUIaM3C660XzZmGQLJIQ+WNYNLJ/no/H30KzafwE1mJf2qkdcZ8cT3xZdciNg==",
"output_file_mode": null,
"output_md5": "090088f39e1ef9d8d7d152944441edb7",
"output_path": "./dist/notes-list.zip",
"output_sha": "b5730a0d98ae778f80c27881147e14d060151fce",
"output_sha256": "d696ed7c213caa3a403f90ddcfd73d69f84e517ab76aae7aa2b762e6de2f5f4d",
"output_sha512": "9d35276d1293e1de60e60dc700d4c6c598b916650868cdc2ebad17cd998640b24843e58d60d2c9fe7a3f1f7d0acda7f01359897f6aa475c67c713df165d72236",
"output_size": 746,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/notes-list",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "data",
"type": "archive_file",
"name": "sql_runner",
"provider": "provider[\"registry.terraform.io/hashicorp/archive\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"exclude_symlink_directories": null,
"excludes": null,
"id": "241f12b31b5d970c697341292954b220e44f8d2a",
"output_base64sha256": "w/IUipIki9V1lf33x06/gHq+KWVdfJO9Ni98DkhC+Xw=",
"output_base64sha512": "aLpBXApQ5Nltm6ODUqQc6VZQCoxgn68mHlcrOF8bFrdem8psnz7dujkJE5PYvB5VDNKmdsViDAKPNTwHxut4XA==",
"output_file_mode": null,
"output_md5": "1fe2ab7afe4730b1141146363d69bd23",
"output_path": "./dist/sql-runner.zip",
"output_sha": "241f12b31b5d970c697341292954b220e44f8d2a",
"output_sha256": "c3f2148a92248bd57595fdf7c74ebf807abe29655d7c93bd362f7c0e4842f97c",
"output_sha512": "68ba415c0a50e4d96d9ba38352a41ce956500a8c609faf261e572b385f1b16b75e9bca6c9f3eddba39091393d8bc1e550cd2a676c5620c028f353c07c6eb785c",
"output_size": 796,
"source": [],
"source_content": null,
"source_content_filename": null,
"source_dir": "./code/sql-runner",
"source_file": null,
"type": "zip"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "notes_crud",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "aaefd6de16697af6ac7331c7e1795a5446c71e351e6cacc3f4b490b683feb0cb",
"code_path": "./dist/notes.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-notes:80b15a8b73f5",
"memory_mb": 128,
"name": "notes",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes"
]
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "notes_list",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "4091f7c79ca8c9c5663c812eb08f25ef5257af217bf2b412add670a4737b9d7f",
"code_path": "./dist/notes-list.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-notes-list:07f2d5ae5ee4",
"memory_mb": 128,
"name": "notes-list",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes_list"
]
}
]
},
{
"mode": "managed",
"type": "sless_function",
"name": "sql_runner",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"build_timeout_sec": 300,
"code_hash": "fcde93e59e6fd7f3db426482da7667d5d402aaaaaf56f79a7a60bb1722ec603a",
"code_path": "./dist/sql-runner.zip",
"entrypoint": "handler.handle",
"env_vars": {
"PG_DSN": "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable"
},
"image_ref": "naeel/sless-default-sql-runner:22bce581a299",
"memory_mb": 128,
"name": "sql-runner",
"namespace": "default",
"phase": "Ready",
"runtime": "python3.11",
"timeout_sec": 30
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "env_vars"
},
{
"type": "index",
"value": {
"value": "PG_DSN",
"type": "string"
}
}
]
],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner"
]
}
]
},
{
"mode": "managed",
"type": "sless_job",
"name": "create_index",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"completion_time": "2026-03-09T05:44:59Z",
"event_json": "{\"statements\":[\"CREATE INDEX IF NOT EXISTS notes_created_idx ON notes(created_at DESC)\"]}",
"function": "sql-runner",
"message": "completed successfully",
"name": "notes-create-index",
"namespace": "default",
"phase": "Succeeded",
"run_id": 1,
"start_time": "2026-03-09T05:44:54Z",
"wait_timeout_sec": 60
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "managed",
"type": "sless_job",
"name": "notes_table_init",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"completion_time": "2026-03-09T05:44:54Z",
"event_json": "{\"statements\":[\"CREATE TABLE IF NOT EXISTS notes (id serial PRIMARY KEY, title text NOT NULL, body text, created_at timestamp DEFAULT now())\"]}",
"function": "sql-runner",
"message": "completed successfully",
"name": "notes-create-table",
"namespace": "default",
"phase": "Succeeded",
"run_id": 1,
"start_time": "2026-03-09T05:44:39Z",
"wait_timeout_sec": 120
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.sql_runner",
"sless_function.sql_runner"
]
}
]
},
{
"mode": "managed",
"type": "sless_trigger",
"name": "notes_crud_http",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"active": true,
"enabled": true,
"function": "notes",
"name": "notes-http",
"namespace": "default",
"schedule": null,
"type": "http",
"url": "https://sless-api.kube5s.ru/fn/default/notes"
},
"sensitive_attributes": [],
"identity_schema_version": 0
}
]
},
{
"mode": "managed",
"type": "sless_trigger",
"name": "notes_list_http",
"provider": "provider[\"terra.k8c.ru/naeel/sless\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"active": true,
"enabled": true,
"function": "notes-list",
"name": "notes-list-http",
"namespace": "default",
"schedule": null,
"type": "http",
"url": "https://sless-api.kube5s.ru/fn/default/notes-list"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"dependencies": [
"data.archive_file.notes_list",
"sless_function.notes_list"
]
}
]
}
],
"check_results": null
}

View File

@ -1,6 +1,12 @@
# 2025-06-05 # 2026-03-09
# variables.tf входные переменные для notes-python примера. # 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" { variable "pg_dsn" {
description = "PostgreSQL DSN для подключения к БД внутри кластера" description = "PostgreSQL DSN для подключения к БД внутри кластера"
type = string type = string