// 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//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//pg-table-reader # https://sless.kube5s.ru/fn//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 }