Naeel
7220fe5b8b
feat: IoT Admin Stats page — /iot-admin (v0.1.70)
...
- GET /iot-admin — HTML страница администратора (go:embed)
- GET /iot-admin/stats — JSON API с данными (Bearer ADMIN_STATS_TOKEN)
- Источники: Kafka consumer lag, K8s pod statuses, PostgreSQL per-tenant stats
- Авторизация: ADMIN_STATS_TOKEN env var
- Auto-refresh каждые 30 секунд
- Nubes brand style
2026-04-06 19:14:57 +03:00
Naeel
7e16dd0e0b
v0.1.66: token input visible, display name in navbar
2026-04-05 17:31:02 +03:00
Naeel
69dc023bf7
fix: make MQTTX Web visually a button-link, not plain text
...
Image: v0.1.65
2026-04-05 16:43:49 +03:00
Naeel
d2460ac988
fix: improve credentials tab readability
...
- cred-label: 11px→13px, убран uppercase, цвет #7eb8e0 (читаемый на тёмном)
- cred-value: 13px→14px, фон #0a1e30, текст #e2f0ff (светлый, контрастный)
- hint: 12px→14px, цвет #a0bcd8
- MQTTX-блок: заголовок 15px жирный #c8dff0, текст 14px #c8dff0,
code-теги со своим фоном и цветом #7dd3fc,
предупреждение ⚠️ жёлтым #fcd34d
Image: v0.1.64
2026-04-05 16:39:16 +03:00
Naeel
20846297af
fix: EnsureNamespace in doCreate + sanitize API errors in UI
...
- doCreate() calls EnsureNamespace before creating device (idempotent)
Fixes namespace-not-found when session was cached before v0.1.62
- Added sanitizeApiError() — hides internal details (namespace names,
k8s paths) from user, shows friendly Russian messages instead
- Patterns handled: namespace not found, already exists, HTTP 5xx
Image: v0.1.63
2026-04-05 11:11:50 +03:00
Naeel
11bc86d2c9
fix: call EnsureNamespace on login to auto-create k8s namespace
...
doLogin() now calls POST /v1/namespaces/{ns}/ensure before apiListDevices().
Prevents namespace not found error when user logs in for the first time
with a new token (test mode or real JWT).
Image: v0.1.62
2026-04-05 11:06:27 +03:00
Naeel
354fded5b9
fix: remove copyAll button, add MQTTX Web link in creds tab
...
- Removed 📋 Скопировать всё button and Подключение физического устройства block
- Added MQTTX Web link (https://mqttx.app/web-client ) with brief instructions:
Host, Port 443, Protocol wss, Path /mqtt — copy username/password above
- Warning: check port is 443 not 8084/1883 if connection fails
- Updated help step 1: removed mention of copyAll, added port 443 note
- Removed unused copyAll() function
Image: v0.1.61
2026-04-05 10:52:38 +03:00
Naeel
3bf1dd604c
feat: test auth mode — accept any plain token without JWT validation
...
authTestMode=true in middleware/auth.go:
- any non-whitespace, non-JWT string is accepted as Bearer token
- string is used as sub for namespace derivation (SHA256)
- JWT validation still runs for actual JWT strings (xxx.yyy.zzz)
- revert to strict mode: authTestMode = false
iot-console.html:
- namespaceFromToken: plain tokens use the string itself as sub
- login form: updated placeholder + hint explaining test mode
Image: v0.1.60
2026-04-05 10:46:29 +03:00
Naeel
763dca8653
fix(ux): credentials tab — copy button for password, port 443 in broker URL
2026-04-05 10:35:51 +03:00
Naeel
5e3c82d12a
fix: autoTimer runs as background process, not killed on tab switch
2026-04-05 09:50:48 +03:00
Naeel
911f2bdafe
fix: auto-send continues when switching to Telemetry tab, uses random payload
2026-04-05 09:17:54 +03:00
Naeel
233e28579d
fix: MQTT ACL — allow bridge subscribe +/telemetry/+, fix device topic {ns}/telemetry/{deviceId}
2026-04-05 09:06:31 +03:00
Naeel
b902e136ed
fix: QueryTelemetry returns empty array when tenant DB not yet created
2026-04-05 08:55:54 +03:00
Naeel
2bdd753f4e
v0.1.59: IoT telemetry pipeline — Postgres storage + REST API + UI table
2026-04-05 08:46:17 +03:00
Naeel
93e87a3b30
fix(iot-console): favicon Nubes, v0.1.58
2026-04-04 20:37:44 +03:00
Naeel
0400f97eb6
design(iot-console): Nubes brand rebrand v0.1.57
...
- Палитра: #001C34 (Nubes navy) как фоновая карточек/navbar
- Логотип Nubes SVG в navbar и на экране входа (filter:invert → белый)
- Убраны эмодзи из brand-элементов
- Accent: #1a7fd4 (корпоративный синий на тёмном фоне)
- Badges: прямоугольные, UPPERCASE, строгие
- Кнопки/формы/таблицы: Nubes-спецификация
2026-04-04 20:34:23 +03:00
Naeel
e54787177b
fix(iot-console): убрать поля API/MQTT из формы входа, добавить Help блок
...
- Форма входа: только токен, без полей API адреса и MQTT broker
- Адреса zardcoded: https://sless.kube5s.ru и wss://iot.kube5s.ru/mqtt
- Страница устройства: блок «Как это работает» — 5 шагов с инструкцией
- operator.yaml: v0.1.55 → v0.1.56
2026-04-04 20:25:06 +03:00
Naeel
fb6f9d48cd
feat(tls): HTTPS + wss:// для iot.kube5s.ru
...
- emqx-ws-ingress.yaml: TLS секция + cert-manager letsencrypt-prod, ssl-redirect=true
- router.go: CORS Allow-Origin: http → https://iot.kube5s.ru
- iot-console.html: дефолт MQTT брокера ws:// → wss://
- operator.yaml: v0.1.53 → v0.1.54
- crypto.subtle теперь работает (HTTPS страница)
2026-04-04 19:56:31 +03:00
Naeel
017312f35c
fix(iot-console): убрать namespace из UI полностью
...
- Поле Namespace удалено из формы входа
- namespace вычисляется из токена: SHA256(sub) → sless-{hex}
- navbar: убран badge с ns
- Телеметрия: убрана техническая подсказка про namespace
- Пользователь не видит и не вводит namespace нигде
2026-04-04 19:38:32 +03:00
Naeel
b48c300ac5
feat(iot-console): IoT управляющий UI v0.1.53
...
- Добавлен HTML SPA: internal/api/ui/iot-console.html
Ванильный JS + mqtt.js (CDN), без фреймворков.
Страницы: вход, список устройств, credentials, эмулятор MQTT, заглушка телеметрии.
- Добавлен go:embed: internal/api/console_embed.go, GET /console
- Добавлен CORS middleware в router.go для http://iot.kube5s.ru
- Ingress emqx-ws-ingress.yaml: /console → sless-operator:9090
- Версия образа v0.1.53, задеплоен
Доступно: http://iot.kube5s.ru/console
2026-04-04 19:28:30 +03:00
Naeel
b23ae40975
security(iot): MQTT ACL isolation via EMQX HTTP authorization
...
Each IoT device can only pub/sub to its own topics: {namespace}/{deviceId}/#
Any attempt to access foreign topics → EMQX denies and disconnects.
Changes:
- internal/api/handler: add MQTTAcl handler (POST /internal/mqtt/acl)
- internal/api/router: register /internal/mqtt/acl route
- deployments/k8s/emqx.yaml: add HTTP authorization backend, no_match=deny
- Operator v0.1.52 deployed
Tested: own topic ALLOWED, foreign topic → authorization_permission_denied + disconnect
2026-04-04 17:51:51 +03:00
Naeel
857d057af9
feat(iot): деплой IoT MVP — Dockerfile, RBAC, EMQX fix, operator v0.1.50, mqtt-bridge, doc/iot
2026-04-04 10:29:47 +03:00
Naeel
1e53766c46
feat(iot): Этапы 2-7 — MQTT auth, IoT API, EMQX, mqtt-bridge, E2E demo
...
Этап 2+4: internal/api/handler/iot_device_handler.go
- MQTTAuth: POST /internal/mqtt/auth (без JWT, для EMQX)
- CreateIoTDevice, ListIoTDevices, GetIoTDevice (c password), DeleteIoTDevice, UpdateIoTDevice
- crypto/subtle.ConstantTimeCompare против timing attacks
Этап 4: internal/api/router.go
- /v1/namespaces/{ns}/iot/devices CRUD
- /internal/mqtt/auth (без JWT middleware)
Этап 3: deployments/k8s/emqx.yaml
- EMQX 5.5.1, emqx.conf (HOCON) с HTTP auth backend
- Сервис exposure: 1883 (MQTT), 8083 (WS), 18083 (Dashboard)
Этап 3: iot/cmd/mqtt-bridge/main.go
- paho.mqtt.golang: подписка на +/telemetry/+
- amqp091-go: publish в iot.{namespace}.telemetry
- deployments/k8s/iot-mqtt-bridge.yaml
Этап 7: examples/IOT/ — E2E demo (main.tf, handler.py, README.md)
go.mod: добавлен github.com/eclipse/paho.mqtt.golang v1.5.1
go build ./... — ошибок нет
2026-04-04 09:45:23 +03:00
Naeel
3404af578b
feat(builder): py_compile + node --check при сборке ловят синтаксические ошибки (v0.1.63)
2026-03-23 11:23:01 +03:00
Naeel
7a168185ea
fix: cache lag retry, go.work, провайдер rollback, test v4 no -target
2026-03-23 10:03:26 +03:00
“Naeel”
cb77a7f68e
fix: go.work replace + test destroy targets
2026-03-23 09:30:37 +04:00
Naeel
2e7cd7f4f7
feat(v0.1.60): sha256-based s3Key for content-addressed cache hit
2026-03-23 06:57:18 +03:00
Naeel
c033adec11
feat(v0.1.59): in-cluster registry:2 — insecure HTTP mode, ImageExists error handling
2026-03-23 06:41:30 +03:00
Naeel
9edd43edc5
feat(v0.1.58): ImageExists cache hit, timing analysis, in-cluster registry plan
2026-03-23 06:22:25 +03:00
Naeel
7023e0e6fc
feat(builder): add REGISTRY_PROJECT for easy registry migration
...
DockerHub (flat): REGISTRY_HOST=naeel, REGISTRY_PROJECT=<empty>
-> naeel/{nsPrefix}-{func}:{tag}
Harbor/GCR (project): REGISTRY_HOST=host, REGISTRY_PROJECT=proj
-> host/proj/{func}:{tag}
Switch registry by changing 2 env vars only.
2026-03-22 17:51:05 +03:00
Naeel
c762047234
fix(builder/go1.23): add require sless/fn/handler to server/go.mod at build time
...
go.work replace rule requires explicit require directive in server/go.mod.
Patch appended at kaniko build time - no base image rebuild needed.
2026-03-22 17:28:40 +03:00
Naeel
40474324bd
feat: v0.1.51 + G13/G14/G15 tests (126/126 PASS)
...
- fix: UpdateService IsInvalid → 400 (was 500 for ruby3.0 runtime)
- test: G13 edge cases — 40 tests, 40 PASS (name validation, boundary values,
lifecycle, state transitions, update validation, upload edge cases)
- test: G14 cluster chaos — 20 tests, 20 PASS (self-healing, pod kill,
OOM kill, kaniko interrupt, operator restart)
- test: G15 combined chaos — 21 tests, 21 PASS (CRUD under chaos, upload
during self-heal, concurrent creates, errors after restart, rapid lifecycle)
- doc: progress.md, errors/log.md, decisions/log.md — полная документация сессии
2026-03-22 11:15:46 +03:00
Naeel
a76baa62a3
fix: v0.1.50 — runtime 400 + SLESS_ENTRYPOINT в Deployment
...
Bug 1: services.go — k8s IsInvalid error (CRD enum validation) маппился в 500.
Теперь errors.IsInvalid() → 400 Bad Request (invalid service spec).
Bug 2: service_controller.go buildServiceDeployment не передавал env SLESS_ENTRYPOINT
в под. Добавлен в envVars из svc.Spec.Entrypoint. Без него server.py использовал
fallback handler.handle и не замечал неверный entrypoint.
operator_failure_test.sh 12B-2: обновлён под новое правильное поведение —
create ruby3.0 → 400 (не 201). Старый 201-путь сохранён как warn для совместимости.
2026-03-22 08:11:05 +03:00
Naeel
b86ff3a62e
feat(service): timeout_sec без дефолта; 0=нет таймаута; operator v0.1.48
...
- api/v1alpha1/service_types.go: убрать +kubebuilder:default=30
- invoke.go: TimeoutSec=0 → &http.Client{} (без таймаута)
- services.go: валидация timeout_sec < 0 || > 900 → HTTP 400
- service_resource.go: TF schema Optional (без Computed); 0 → Int64Null()
- deployments/k8s/operator.yaml: v0.1.47 → v0.1.48
- doc/: progress.md + api/design.md (модель Service) + decisions/log.md
- examples/POSTGRES/: bug_hunter.sh, chaos_marathon.sh, chaos_marathon.tf
2026-03-21 16:58:43 +03:00
Naeel
778cbc8b32
fix(runtime): Go panic→500 (recover), Python exception→500+threading+backlog
...
- go1.23 v0.1.2: defer recover() в HTTP handler — panic no longer closes connection → HTTP 500
- python3.11 v0.1.5: try/except в do_GET/_handle_with_body/do_HEAD → 500 вместо EOF
- python3.11 v0.1.5: ThreadingHTTPServer — concurrent requests (был single-thread)
- python3.11 v0.1.6: _HighBacklogHTTPServer(request_queue_size=128) — listen(128) вместо listen(5)
- context.go: go1.23 v0.1.1→v0.1.2, python3.11 v0.1.4→v0.1.6
- operator: v0.1.45 → v0.1.47 (два деплоя подряд с новыми runtime-версиями)
- examples/POSTGRES: stress.tf (10 сервисов), full_test.sh (48 тестов, 4 фазы)
- examples/POSTGRES: README.md, очистка от старых файлов (luceUNDnode.tf, funcs_list.py)
Результат: full_test.sh 48/48 PASS
- Фаза 3 PG-стресс: 40/40 parallel writer OK, 30/30 js-async OK, pgstorm 14k ops 0 err
- Фаза 4 краш-шторм: 75/75 × HTTP 500 (паники не роняют платформу)
2026-03-21 08:42:03 +03:00
Naeel
50f24565ec
fix(source): add /services/{name}/source endpoint; fix 404 for service code view in funcs-console
2026-03-21 07:20:03 +03:00
Naeel
e8d0d78310
fix(api): DELETE несуществующего ресурса — 404 вместо 204 (function/service/trigger/job)
2026-03-21 06:45:55 +03:00
Naeel
6f76ecbc81
fix(invoke): заменить FunctionRef на поля из Function.Spec — FunctionJobSpec самодостаточен
2026-03-20 21:52:49 +03:00
Naeel
8ca8faedd1
feat(job): merge sless_function into sless_job — self-contained build+run
...
- FunctionJobSpec: убран FunctionRef, добавлены Runtime/Entrypoint/Env/S3Key/MemoryMB/TimeoutSec
- FunctionJobStatus: новый ImageRef, новая фаза Building
- FunctionJobReconciler: Building фаза (kaniko), убрана зависимость от Function CRD
Builder+OperatorNamespace как поля struct; аннотация sless.kube5s.ru/build-job guard
- main.go: Builder+OperatorNamespace переданы в FunctionJobReconciler
- jobs.go handler: jobRequest/jobResponse без FunctionRef; новый UploadJobCode handler
- router.go: /jobs/{name}/upload маршрут
- client.go: JobRequest/JobResponse обновлены; UploadJobCode; uploadCodeToURL общий хелпер
- job_resource.go: полная переработка — источник/среда встроены в JobModel, ModifyPlan,
Create с upload, wait_timeout_sec=900 по умолчанию (kaniko + выполнение)
- examples/POSTGRES/functions.tf: раскомментирован, sless_function удалён,
sless_job самодостаточен (inline source_dir/runtime/entrypoint/env_vars)
2026-03-20 21:27:35 +03:00
Naeel
680beb675b
feat: sless_service CRD + ServiceReconciler, RBAC fix, split postgres/functions.tf, operator v0.1.41
2026-03-20 13:03:12 +03:00
Naeel
d7fda15d35
feat: Go runtime v0.1.1 (pgx/v5), stress-go-pgstorm, fix invoke.go dynamic timeout, nginx ingress timeout 900s
...
- runtimes/go1.23: добавлен pgx/v5 v5.7.2 в go.mod, сгенерирован go.sum
- runtimes/go1.23/Dockerfile: один stage golang:1.23-alpine, go mod download кеширует зависимости
- internal/builder/context.go: тег Go runtime v0.1.0 → v0.1.1
- internal/api/handler/invoke.go: таймаут прокси-клиента теперь динамический из Function.Spec.TimeoutSec + 5s буфер (был хардкод 30s)
- examples/POSTGRES/code/stress-go-pgstorm/handler.go: новая функция, 100 горутин, pgxpool, INSERT/COUNT/MAX, параметры: workers/duration_sec/max_delay_ms
- examples/POSTGRES/resources.tf: добавлены sless_function.stress_go_pgstorm + trigger, timeout_sec=700
- deployments/k8s/operator.yaml: nginx ingress proxy-read-timeout=900s, proxy-send-timeout=900s
- examples/*/main.tf: исправлен URL deck-api-test.ngcloud.ru → deck-test.ngcloud.ru (все 9 файлов)
- Оператор: v0.1.39 (pgx/v5) → v0.1.40 (dynamic timeout)
2026-03-19 21:33:41 +03:00
Naeel
d87981713d
test: полный прогон POSTGRES example — changes, delete/recreate, new function
2026-03-19 18:45:18 +03:00
Naeel
8a8b815492
fix: убрать --no-cache из kaniko Args — флаг не поддерживается в gcr.io/kaniko-project/executor:latest, кэш отключён по умолчанию
2026-03-19 17:38:07 +03:00
Naeel
a379091b8a
feat: event-trigger (Вариант A) — TriggerTypeEvent, event-dispatcher, reconcileEvent
2026-03-19 13:44:35 +03:00
Naeel
d286d92a05
fix: invoke.go — forward Content-Length to proxied request (form POST fix)
...
Without ContentLength, Python BaseHTTPRequestHandler read 0 bytes from body.
operator v0.1.37, python runtime v0.1.4, pg-table-writer HTML form
2026-03-19 08:58:35 +03:00
Naeel
a04dfb2d0c
fix+docs: FunctionJob label bugfix, job ErrAlreadyExists, python str→text/plain, operator.yaml v0.1.33, progress.md
...
- controllers/functionjob_controller.go:
- PodTemplate labels: functionjob=, function= (k8s 1.27+ удалил job-name=)
- getJobPodOutput принимает labelSelector вместо jobName
- захват stderr при Failed job; truncateForStatus() helper
- terraform/provider/internal/client/client.go: ErrJobAlreadyExists (409 Conflict)
- terraform/provider/internal/resources/job_resource.go: при конфликте создания — читаем существующий job
- runtimes/python3.11/server.py: str return → text/plain
- internal/builder/context.go: python runtime base image → v0.1.3
- deployments/k8s/operator.yaml: image → v0.1.33
- doc/progress.md: добавлены секции FunctionJob bugfix, str→text/plain, web-console v0.2.0
2026-03-18 17:41:44 +03:00
Naeel
bf9f07385e
feat: web-console — HTML UI + source viewer + trigger toggle
...
- operator: GET /v1/namespaces/{ns}/functions/{name}/source
reads build context tar.gz from S3, strips Dockerfile, returns JSON files
- funcs-service v0.2.0:
- Accept: text/html → dark-themed HTML console with accordion cards
- GET /funcs/{ns}/source/{fn} → proxy to operator (service token auth)
- PATCH /funcs/{ns}/triggers/{name} → proxy enable/disable (only enabled field)
- curl (no text/html Accept) → plain text as before (backward compat)
- highlight.js syntax highlighting per file extension
- operator v0.1.34, funcs-service v0.2.0
2026-03-18 17:24:43 +03:00
Naeel
9bc91841c8
feat: NodeJS pg-info function; funcs endpoint: filter + created_at/last_built_at; operator v0.1.32
2026-03-18 11:03:58 +03:00
“Naeel”
6de90ac5ac
chore: python runtime v0.1.2 + operator v0.1.28
...
- context.go: python3.11 runtime → v0.1.2 (server.py с JSON для всех методов)
- operator.yaml: v0.1.28
2026-03-11 17:08:33 +04:00
“Naeel”
c4559dd365
fix: go1.23 build context — COPY . /app/handler/ вместо COPY handler/
2026-03-11 16:14:42 +04:00