diff --git a/examples/pg-list-python/code/catalog.py b/examples/pg-list-python/code/catalog.py new file mode 100644 index 0000000..54ef884 --- /dev/null +++ b/examples/pg-list-python/code/catalog.py @@ -0,0 +1,47 @@ +# 2026-03-11 +# catalog.py — читает список продуктов из PostgreSQL. +# Таблица demo_products создаётся автоматически при первом вызове. +# Точка входа: list_products(event) + +import json +import os +import psycopg2 + + +def list_products(event): + dsn = os.environ["PG_DSN"] + conn = psycopg2.connect(dsn) + try: + with conn.cursor() as cur: + _ensure_table(cur) + conn.commit() + + cur.execute("SELECT id, name, price FROM demo_products ORDER BY id") + rows = cur.fetchall() + finally: + conn.close() + + products = [{"id": row[0], "name": row[1], "price": row[2]} for row in rows] + return {"products": products, "count": len(products)} + + +def _ensure_table(cur): + # Создаём таблицу и наполняем демо-данными — только один раз + cur.execute(""" + CREATE TABLE IF NOT EXISTS demo_products ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + price NUMERIC(10,2) NOT NULL + ) + """) + cur.execute("SELECT COUNT(*) FROM demo_products") + if cur.fetchone()[0] == 0: + cur.executemany( + "INSERT INTO demo_products (name, price) VALUES (%s, %s)", + [ + ("Ноутбук", 89999.00), + ("Мышь", 1299.00), + ("Клавиатура", 3499.00), + ("Монитор", 32000.00), + ], + ) diff --git a/examples/pg-list-python/code/requirements.txt b/examples/pg-list-python/code/requirements.txt new file mode 100644 index 0000000..37ec460 --- /dev/null +++ b/examples/pg-list-python/code/requirements.txt @@ -0,0 +1 @@ +psycopg2-binary diff --git a/examples/pg-list-python/function.tf b/examples/pg-list-python/function.tf new file mode 100644 index 0000000..6638c65 --- /dev/null +++ b/examples/pg-list-python/function.tf @@ -0,0 +1,29 @@ +# 2026-03-11 +# function.tf — HTTP-функция: читает из PostgreSQL и возвращает список записей. +# Нет джобов, нет инициализации — только функция + HTTP триггер. + +resource "sless_function" "product_catalog" { + name = "product-catalog" + runtime = "python3.11" + entrypoint = "catalog.list_products" + memory_mb = 128 + timeout_sec = 10 + + source_dir = "${path.module}/code" + + # DSN передаётся через env — функция не знает об инфраструктуре + env_vars = { + PG_DSN = var.pg_dsn + } +} + +resource "sless_trigger" "product_catalog_http" { + name = "product-catalog-http" + type = "http" + function = sless_function.product_catalog.name + enabled = true +} + +output "catalog_url" { + value = sless_trigger.product_catalog_http.url +} diff --git a/examples/pg-list-python/main.tf b/examples/pg-list-python/main.tf new file mode 100644 index 0000000..7d3d427 --- /dev/null +++ b/examples/pg-list-python/main.tf @@ -0,0 +1,17 @@ +# 2026-03-11 +# main.tf — провайдер для pg-list-python примера. + +terraform { + required_providers { + sless = { + source = "terra.k8c.ru/naeel/sless" + version = "~> 0.1.14" + } + } +} + +provider "sless" { + endpoint = "https://sless-api.kube5s.ru" + token = var.token + nubes_endpoint = "https://deck-api.ngcloud.ru/api/v1" +} diff --git a/examples/pg-list-python/variables.tf b/examples/pg-list-python/variables.tf new file mode 100644 index 0000000..ab59478 --- /dev/null +++ b/examples/pg-list-python/variables.tf @@ -0,0 +1,14 @@ +# 2026-03-11 +# variables.tf + +variable "token" { + description = "JWT токен облака" + type = string + sensitive = true +} + +variable "pg_dsn" { + description = "DSN подключения к PostgreSQL" + type = string + default = "postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable" +}