feat: sless_service CRD + ServiceReconciler, RBAC fix, split postgres/functions.tf, operator v0.1.41

This commit is contained in:
Naeel
2026-03-20 13:03:12 +03:00
parent dc65f7ab8f
commit 680beb675b
19 changed files with 2448 additions and 693 deletions
+280
View File
@@ -0,0 +1,280 @@
// 2026-03-20 — выделено из resources.tf: sless функции, сервисы и джобы.
// 2026-03-19 — миграция: sless_function (oneshot/Job) + sless_service (long-running Deployment).
// sless_trigger(type=http) удалены — HTTP URL теперь автоматически в sless_service.
// postgres_sql_runner_create_table и stress-* остаются sless_function (oneshot/Job).
// pg-info, pg-table-reader, pg-table-writer → sless_service.
# Служебная функция выполняет SQL-операторы из event_json.
# Credentials берутся из locals (vault_secrets) — без хардкода.
# Для сверки хардкод остаётся в terraform.tfvars.
resource "sless_function" "postgres_sql_runner_create_table" {
name = "pg-create-table-runner"
runtime = "python3.11"
entrypoint = "sql_runner.run_sql"
memory_mb = 128
timeout_sec = 30
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
# Для сверки (должно совпадать с vault):
# PGUSER = var.pg_user
# PGPASSWORD = var.pg_password
}
source_dir = "${path.module}/code/sql-runner"
}
resource "sless_job" "postgres_table_init_job" {
name = "pg-create-table-job-main-v13"
function = sless_function.postgres_sql_runner_create_table.name
wait_timeout_sec = 180
run_id = 13
event_json = jsonencode({
statements = [
"CREATE TABLE IF NOT EXISTS terraform_demo_table (id serial PRIMARY KEY, title text NOT NULL, created_at timestamp DEFAULT now())"
]
})
depends_on = [nubes_postgres_database.db]
}
# Long-running сервис на NodeJS: возвращает версию PG-сервера и счётчик строк в таблице.
# Единственная функция примера на nodejs20 — проверка что JS runtime работает.
# URL автоматически: https://sless.kube5s.ru/fn/<namespace>/pg-info
resource "sless_service" "pg_info" {
name = "pg-info"
runtime = "nodejs20"
entrypoint = "pg_info.info"
memory_mb = 128
timeout_sec = 15
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/pg-info"
depends_on = [sless_job.postgres_table_init_job]
}
# Long-running сервисы чтения и записи строк terraform_demo_table — в одном файле table_rw.py.
# list_rows (GET) — читает все строки; add_row (POST {title}) — вставляет строку.
# URL автоматически: https://sless.kube5s.ru/fn/<namespace>/pg-table-reader
# https://sless.kube5s.ru/fn/<namespace>/pg-table-writer
resource "sless_service" "postgres_table_reader" {
name = "pg-table-reader"
runtime = "python3.11"
entrypoint = "table_rw.list_rows"
memory_mb = 128
timeout_sec = 30
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/table-rw"
depends_on = [sless_job.postgres_table_init_job]
}
output "table_reader_url" {
value = sless_service.postgres_table_reader.url
}
resource "sless_service" "postgres_table_writer" {
name = "pg-table-writer"
runtime = "python3.11"
entrypoint = "table_rw.add_row"
memory_mb = 256
timeout_sec = 45
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/table-rw"
depends_on = [sless_job.postgres_table_init_job]
}
output "table_writer_url" {
value = sless_service.postgres_table_writer.url
}
# =============================================================================
# STRESS-ТЕСТЫ: 9 функций для проверки устойчивости платформы.
# Python: slow, divzero, bigloop, writer
# Go: fast, nil-panic, pgstorm
# NodeJS: async-parallel, badenv
# =============================================================================
# --- [1] Python: долгая (sleep N сек) ---
resource "sless_function" "stress_slow" {
name = "stress-slow"
runtime = "python3.11"
entrypoint = "stress_slow.run"
memory_mb = 128
timeout_sec = 30
env_vars = {}
source_dir = "${path.module}/code/stress-slow"
depends_on = [sless_job.postgres_table_init_job]
}
# --- [2] Python: деление на ноль ---
resource "sless_function" "stress_divzero" {
name = "stress-divzero"
runtime = "python3.11"
entrypoint = "stress_divzero.run"
memory_mb = 128
timeout_sec = 10
env_vars = {}
source_dir = "${path.module}/code/stress-divzero"
depends_on = [sless_job.postgres_table_init_job]
}
# --- [3] Python: CPU bigloop ---
resource "sless_function" "stress_bigloop" {
name = "stress-bigloop"
runtime = "python3.11"
entrypoint = "stress_bigloop.run"
memory_mb = 256
timeout_sec = 30
env_vars = {}
source_dir = "${path.module}/code/stress-bigloop"
depends_on = [sless_job.postgres_table_init_job]
}
# --- [4] Python: массовая запись в PG ---
resource "sless_function" "stress_writer" {
name = "stress-writer"
runtime = "python3.11"
entrypoint = "stress_writer.run"
memory_mb = 128
timeout_sec = 30
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/stress-writer"
depends_on = [sless_job.postgres_table_init_job]
}
# --- [5] Go: быстрая математика (факториал + Фибоначчи) ---
resource "sless_function" "stress_go_fast" {
name = "stress-go-fast"
runtime = "go1.23"
entrypoint = "handler.Handle"
memory_mb = 64
timeout_sec = 10
env_vars = {}
source_dir = "${path.module}/code/stress-go-fast"
depends_on = [sless_job.postgres_table_init_job]
}
# --- [6] Go: nil pointer panic ---
resource "sless_function" "stress_go_nil" {
name = "stress-go-nil"
runtime = "go1.23"
entrypoint = "handler.Handle"
memory_mb = 64
timeout_sec = 10
env_vars = {}
source_dir = "${path.module}/code/stress-go-nil"
depends_on = [sless_job.postgres_table_init_job]
}
# --- [7] NodeJS: 3 параллельных запроса к PG через Promise.all ---
resource "sless_function" "stress_js_async" {
name = "stress-js-async"
runtime = "nodejs20"
entrypoint = "stress_js_async.run"
memory_mb = 128
timeout_sec = 15
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/stress-js-async"
depends_on = [sless_job.postgres_table_init_job]
}
# --- [8] NodeJS: TypeError на несуществующей env-переменной ---
resource "sless_function" "stress_js_badenv" {
name = "stress-js-badenv"
runtime = "nodejs20"
entrypoint = "stress_js_badenv.run"
memory_mb = 128
timeout_sec = 10
env_vars = {}
source_dir = "${path.module}/code/stress-js-badenv"
depends_on = [sless_job.postgres_table_init_job]
}
# --- [9] Go: PG Storm — 100 горутин долбят PostgreSQL напрямую через pgxpool ---
# Тестирует: Go runtime под конкурентной нагрузкой, pgxpool connection pool,
# устойчивость managed PG при массовых INSERT/SELECT.
# Параметры: workers (default 100), duration_sec (default 600), max_delay_ms (default 300).
resource "sless_function" "stress_go_pgstorm" {
name = "stress-go-pgstorm"
runtime = "go1.23"
entrypoint = "handler.Handle"
memory_mb = 256
timeout_sec = 700
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/stress-go-pgstorm"
depends_on = [sless_job.postgres_table_init_job]
}
+54
View File
@@ -0,0 +1,54 @@
// 2026-03-20 — выделено из resources.tf: только managed PostgreSQL ресурсы.
# Актуальные credentials из vault_secrets (authoritatively) — vault синхронизирован с кластером.
# Структура vault_secrets["users"]: JSON-строка {"username": {"password": "...", "username": "..."}}
locals {
pg_creds_map = jsondecode(nubes_postgres.npg.vault_secrets["users"])
pg_username = nubes_postgres_user.pg_user.username
pg_password = local.pg_creds_map[local.pg_username]["password"]
pg_host = nubes_postgres.npg.state_out_flat["internalConnect.master"]
pg_database = nubes_postgres_database.db.db_name
}
resource "nubes_postgres" "npg" {
resource_name = "teststand-pg-2"
# s3_uid = "s01325"
s3_uid = var.s3_uid
resource_realm = var.realm
resource_instances = 1
resource_memory = 512
resource_c_p_u = 500
resource_disk = "1"
app_version = "17"
json_parameters = jsonencode({
log_connections = "off"
log_disconnections = "off"
})
enable_pg_pooler_master = false
enable_pg_pooler_slave = false
allow_no_s_s_l = false
auto_scale = false
auto_scale_percentage = 10
auto_scale_tech_window = 0
auto_scale_quota_gb = "1"
need_external_address_master = false
# suspend_on_destroy = false
operation_timeout = "11m"
adopt_existing_on_create = true
}
resource "nubes_postgres_user" "pg_user" {
postgres_id = nubes_postgres.npg.id
username = "u-user0"
role = "ddl_user"
adopt_existing_on_create = true
}
resource "nubes_postgres_database" "db" {
postgres_id = nubes_postgres.npg.id
db_name = "db_terra"
db_owner = nubes_postgres_user.pg_user.username
adopt_existing_on_create = true
# suspend_on_destroy = false
}
+3 -407
View File
@@ -1,407 +1,3 @@
// 2026-03-18добавлены locals для извлечения credentials из vault_secrets (без хардкода).
// Для сверки хардкод остаётся в terraform.tfvars на этапе разработки.
// sless_function и sless_job закомментированы — сначала проверяется сетевое соединение.
# Актуальные credentials из vault_secrets (authoritatively) — vault синхронизирован с кластером.
# Структура vault_secrets["users"]: JSON-строка {"username": {"password": "...", "username": "..."}}
locals {
pg_creds_map = jsondecode(nubes_postgres.npg.vault_secrets["users"])
pg_username = nubes_postgres_user.pg_user.username
pg_password = local.pg_creds_map[local.pg_username]["password"]
pg_host = nubes_postgres.npg.state_out_flat["internalConnect.master"]
pg_database = nubes_postgres_database.db.db_name
}
resource "nubes_postgres" "npg" {
resource_name = "teststand-pg-2"
# s3_uid = "s01325"
s3_uid = var.s3_uid
resource_realm = var.realm
resource_instances = 1
resource_memory = 512
resource_c_p_u = 500
resource_disk = "1"
app_version = "17"
json_parameters = jsonencode({
log_connections = "off"
log_disconnections = "off"
})
enable_pg_pooler_master = false
enable_pg_pooler_slave = false
allow_no_s_s_l = false
auto_scale = false
auto_scale_percentage = 10
auto_scale_tech_window = 0
auto_scale_quota_gb = "1"
need_external_address_master = false
# suspend_on_destroy = false
operation_timeout = "11m"
adopt_existing_on_create = true
}
resource "nubes_postgres_user" "pg_user" {
postgres_id = nubes_postgres.npg.id
username = "u-user0"
role = "ddl_user"
adopt_existing_on_create = true
}
resource "nubes_postgres_database" "db" {
postgres_id = nubes_postgres.npg.id
db_name = "db_terra"
db_owner = nubes_postgres_user.pg_user.username
adopt_existing_on_create = true
# suspend_on_destroy = false
}
# Служебная функция выполняет SQL-операторы из event_json.
# Credentials берутся из locals (vault_secrets) — без хардкода.
# Для сверки хардкод остаётся в terraform.tfvars.
resource "sless_function" "postgres_sql_runner_create_table" {
name = "pg-create-table-runner"
runtime = "python3.11"
entrypoint = "sql_runner.run_sql"
memory_mb = 128
timeout_sec = 30
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
# Для сверки (должно совпадать с vault):
# PGUSER = var.pg_user
# PGPASSWORD = var.pg_password
}
source_dir = "${path.module}/code/sql-runner"
}
resource "sless_job" "postgres_table_init_job" {
name = "pg-create-table-job-main-v13"
function = sless_function.postgres_sql_runner_create_table.name
wait_timeout_sec = 180
run_id = 13
event_json = jsonencode({
statements = [
"CREATE TABLE IF NOT EXISTS terraform_demo_table (id serial PRIMARY KEY, title text NOT NULL, created_at timestamp DEFAULT now())"
]
})
depends_on = [nubes_postgres_database.db]
}
# HTTP-функция на NodeJS: возвращает версию PG-сервера и счётчик строк в таблице.
# Единственная функция примера на nodejs20 — проверка что JS runtime работает.
# Доступна по URL: https://sless.kube5s.ru/fn/<namespace>/pg-info
resource "sless_function" "pg_info" {
name = "pg-info"
runtime = "nodejs20"
entrypoint = "pg_info.info"
memory_mb = 128
timeout_sec = 15
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/pg-info"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "pg_info_http" {
name = "pg-info-http"
type = "http"
function = sless_function.pg_info.name
enabled = true
}
# HTTP-функции чтения и записи строк terraform_demo_table — в одном файле table_rw.py.
# list_rows (GET) — читает все строки; add_row (POST {title}) — вставляет строку.
# Доступны по URL: https://sless.kube5s.ru/fn/<namespace>/pg-table-reader
# https://sless.kube5s.ru/fn/<namespace>/pg-table-writer
resource "sless_function" "postgres_table_reader" {
name = "pg-table-reader"
runtime = "python3.11"
entrypoint = "table_rw.list_rows"
memory_mb = 128
timeout_sec = 30
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/table-rw"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "postgres_table_reader_http" {
name = "pg-table-reader-http"
type = "http"
function = sless_function.postgres_table_reader.name
enabled = true
}
output "table_reader_url" {
value = sless_trigger.postgres_table_reader_http.url
}
resource "sless_function" "postgres_table_writer" {
name = "pg-table-writer"
runtime = "python3.11"
entrypoint = "table_rw.add_row"
memory_mb = 256
timeout_sec = 45
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/table-rw"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "postgres_table_writer_http" {
name = "pg-table-writer-http"
type = "http"
function = sless_function.postgres_table_writer.name
enabled = true
}
output "table_writer_url" {
value = sless_trigger.postgres_table_writer_http.url
}
# =============================================================================
# STRESS-ТЕСТЫ: 8 функций для проверки устойчивости платформы.
# Python: slow, divzero, bigloop, writer
# Go: fast, nil-panic
# NodeJS: async-parallel, badenv
# =============================================================================
# --- [1] Python: долгая (sleep N сек) ---
resource "sless_function" "stress_slow" {
name = "stress-slow"
runtime = "python3.11"
entrypoint = "stress_slow.run"
memory_mb = 128
timeout_sec = 30
env_vars = {}
source_dir = "${path.module}/code/stress-slow"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_slow_http" {
name = "stress-slow-http"
type = "http"
function = sless_function.stress_slow.name
enabled = true
}
# --- [2] Python: деление на ноль ---
resource "sless_function" "stress_divzero" {
name = "stress-divzero"
runtime = "python3.11"
entrypoint = "stress_divzero.run"
memory_mb = 128
timeout_sec = 10
env_vars = {}
source_dir = "${path.module}/code/stress-divzero"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_divzero_http" {
name = "stress-divzero-http"
type = "http"
function = sless_function.stress_divzero.name
enabled = true
}
# --- [3] Python: CPU bigloop ---
resource "sless_function" "stress_bigloop" {
name = "stress-bigloop"
runtime = "python3.11"
entrypoint = "stress_bigloop.run"
memory_mb = 256
timeout_sec = 30
env_vars = {}
source_dir = "${path.module}/code/stress-bigloop"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_bigloop_http" {
name = "stress-bigloop-http"
type = "http"
function = sless_function.stress_bigloop.name
enabled = true
}
# --- [4] Python: массовая запись в PG ---
resource "sless_function" "stress_writer" {
name = "stress-writer"
runtime = "python3.11"
entrypoint = "stress_writer.run"
memory_mb = 128
timeout_sec = 30
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/stress-writer"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_writer_http" {
name = "stress-writer-http"
type = "http"
function = sless_function.stress_writer.name
enabled = true
}
# --- [5] Go: быстрая математика (факториал + Фибоначчи) ---
resource "sless_function" "stress_go_fast" {
name = "stress-go-fast"
runtime = "go1.23"
entrypoint = "handler.Handle"
memory_mb = 64
timeout_sec = 10
env_vars = {}
source_dir = "${path.module}/code/stress-go-fast"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_go_fast_http" {
name = "stress-go-fast-http"
type = "http"
function = sless_function.stress_go_fast.name
enabled = true
}
# --- [6] Go: nil pointer panic ---
resource "sless_function" "stress_go_nil" {
name = "stress-go-nil"
runtime = "go1.23"
entrypoint = "handler.Handle"
memory_mb = 64
timeout_sec = 10
env_vars = {}
source_dir = "${path.module}/code/stress-go-nil"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_go_nil_http" {
name = "stress-go-nil-http"
type = "http"
function = sless_function.stress_go_nil.name
enabled = true
}
# --- [7] NodeJS: 3 параллельных запроса к PG через Promise.all ---
resource "sless_function" "stress_js_async" {
name = "stress-js-async"
runtime = "nodejs20"
entrypoint = "stress_js_async.run"
memory_mb = 128
timeout_sec = 15
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/stress-js-async"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_js_async_http" {
name = "stress-js-async-http"
type = "http"
function = sless_function.stress_js_async.name
enabled = true
}
# --- [8] NodeJS: TypeError на несуществующей env-переменной ---
resource "sless_function" "stress_js_badenv" {
name = "stress-js-badenv"
runtime = "nodejs20"
entrypoint = "stress_js_badenv.run"
memory_mb = 128
timeout_sec = 10
env_vars = {}
source_dir = "${path.module}/code/stress-js-badenv"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_js_badenv_http" {
name = "stress-js-badenv-http"
type = "http"
function = sless_function.stress_js_badenv.name
enabled = true
}
# --- [9] Go: PG Storm — 100 горутин долбят PostgreSQL напрямую через pgxpool ---
# Тестирует: Go runtime под конкурентной нагрузкой, pgxpool connection pool,
# устойчивость managed PG при массовых INSERT/SELECT.
# Параметры: workers (default 100), duration_sec (default 600), max_delay_ms (default 300).
resource "sless_function" "stress_go_pgstorm" {
name = "stress-go-pgstorm"
runtime = "go1.23"
entrypoint = "handler.Handle"
memory_mb = 256
timeout_sec = 700
env_vars = {
PGHOST = local.pg_host
PGPORT = "5432"
PGDATABASE = local.pg_database
PGUSER = local.pg_username
PGPASSWORD = local.pg_password
PGSSLMODE = "require"
}
source_dir = "${path.module}/code/stress-go-pgstorm"
depends_on = [sless_job.postgres_table_init_job]
}
resource "sless_trigger" "stress_go_pgstorm_http" {
name = "stress-go-pgstorm-http"
type = "http"
function = sless_function.stress_go_pgstorm.name
enabled = true
}
// 2026-03-20содержимое перенесено в два файла:
// postgres.tf — managed PostgreSQL ресурсы (nubes_postgres, user, database, locals)
// functions.tf — sless функции, сервисы, джобы, outputs