Commit graph

513 commits

Author SHA1 Message Date
012a8ece95 Migrate images from codeberg.org to git.mcintire.me
Some checks failed
Production Deployment / Run ExUnit Tests (push) Failing after 59s
Production Deployment / Build and Push Docker Image (push) Has been skipped
2026-07-24 14:38:50 -05:00
b5e3c1f977 fix: reduce health-check probe pressure to stop readiness-flapping downtime
Three changes targeting the root cause of production up/down alerting:

1. Skip BruteForceProtection for /health and /health/live paths
   (removes unnecessary Repo.get_by(IpBlock) DB query from every
   k8s probe, matching the existing /socket/agent exemption).

2. Relax k8s readiness probe: periodSeconds 5→10, timeoutSeconds
   2→5, failureThreshold 2→3, successThreshold 3→2 so transient
   DB/Redis blips don't cascade into full service unavailability.

3. Use the persistent Towerops.Redix connection for health checks
   instead of opening a brand-new TCP connection (handshake→AUTH→
   PING→close) on every probe. Towerops.Redix.Fake gains a
   set_ping_response/2 toggle for testing failure paths.
2026-06-08 16:08:31 -05:00
196c9473a4 ops(k8s): point liveness/startup at /health/live, scale to 2 replicas
Now that the image serving /health/live is live, switch liveness and startup
probes to the shallow endpoint so transient db/redis blips can't kill or block
a healthy pod; readiness stays on the deep /health. Run 2 replicas so a single
pod restart no longer means full downtime.
2026-05-20 12:22:53 -05:00
a9579b84f0 fix: H11 — load session salts from env vars instead of hardcoded 8-byte values
SESSION_SIGNING_SALT, SESSION_ENCRYPTION_SALT, and LIVE_VIEW_SIGNING_SALT
are now loaded from environment variables in production. Dev/test keep the
previous defaults via config.exs. k8s/secrets.yaml has placeholder entries;
the user fills in real values before applying.
2026-05-12 14:03:31 -05:00
03f364a956 feat(insights): LLM-powered insight enrichment
Adds an optional plain-language summary and recommended action to every
active insight. A new Oban cron worker runs every 5 minutes, picks up
unenriched insights, and asks the configured LLM to restate the finding
and suggest one specific action grounded in the structured metadata.

- Migration: adds llm_summary, recommended_action, llm_model,
  llm_enriched_at columns to preseem_insights
- Towerops.LLM context with swappable behaviour; real client uses Req
  with the standard Req.Test plug for test isolation
- MockClient + InsightPrompt module (builds chat messages, parses JSON
  with code-fence stripping and a raw-text fallback)
- Worker logs and skips on rate limits / missing key / parse errors so
  insights still render without an AI summary when the LLM is unavailable
- Optional towerops-llm k8s secret with example template; deployment.yaml
  references it as optional in both init and main containers
- UI renders summary + recommended action callout on /insights and on
  the org-level insights page
2026-05-09 16:41:48 -05:00
50324c61ce feat(metrics): expose Prometheus /metrics via PromEx on :9568
Add PromEx with Application/BEAM/Phoenix/LiveView/Ecto/Oban plugins plus
a custom plugin that bridges existing Towerops Oban/Redis telemetry events.
The metrics HTTP server runs isolated on port 9568 so scrape traffic never
traverses the public Traefik IngressRoute.

The pod template carries prometheus.io annotations (scrape, port, path, job)
so the external Prometheus on 10.0.15.31 discovers each pod through the
existing kubernetes-pods scrape job (apiserver-proxy).
2026-05-08 10:25:25 -05:00
222253b7c8 ci: move container image to codeberg.org/gmcintire/towerops
The repo got renamed towerops-web → towerops on the Codeberg side,
so the published image follows: image is now
codeberg.org/gmcintire/towerops with the same main-<ts>-<sha> tag
pattern. Login URL is the hardcoded env.REGISTRY rather than
secrets.REGISTRY_URL so a stale URL secret can't push to the wrong
registry.
2026-05-05 10:57:24 -05:00
bd4e29331f ops: mount HRRR data NFS share at /data
Adds the same NFS volume that microwaveprop uses (10.0.15.103:/data) so
towerops can read the shared HRRR grids and render maps from them.
2026-04-30 10:27:12 -05:00
95babfcc49 ops: tighten readiness gate to prevent downtime during rolling deploys
With 1 replica, the old pod was torn down too quickly after the new pod
passed its first health check. Increase successThreshold to 3 (15s of
consecutive checks) and minReadySeconds to 30 to ensure Traefik has fully
propagated the new endpoint before the old pod is terminated.
2026-04-29 13:49:42 -05:00
17bb5a9117 ops: scale towerops deployment to 1 replica 2026-04-29 11:14:20 -05:00
9720223487
remove obsolete flux manifest and imagepolicy annotations 2026-04-29 11:00:13 -05:00
FluxCD
c76a354d89 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1777403311-23304e1 [skip ci] 2026-04-28 19:10:01 +00:00
FluxCD
08cdbe355b chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1777398683-e7bca61 [skip ci] 2026-04-28 17:53:44 +00:00
e7bca6174c feat(on_call): schedules list with gantt timeline (chunk 2)
Resolver
- Resolver.resolve_range/3: returns the contiguous on-call segments for a
  schedule across [start_at, end_at). Walks layer handoffs + override
  boundaries, drops gap segments, and merges adjacent same-user segments.

UserColor module
- New Towerops.OnCall.UserColor with deterministic id -> color mapping
  (Tailwind class + matching #RRGGBB hex). Refactored ScheduleLive.Show
  to use it instead of its own per-page index palette so the same person
  gets the same color across the schedules list and detail pages.

ScheduleLive.Index
- Date navigation: Today / prev / next + 1/2/4-week range selector.
- URL-driven: ?start=YYYY-MM-DD&range=N for shareable views; falls back
  to defaults on malformed values.
- Per-row card: schedule name link, on-call-now avatar swatch, day-of-week
  header strip, gantt strip rendered as a CSS grid with one column per day,
  Today marker overlay.

Tests: 5 new resolver tests, 9 new UserColor tests, 5 new ScheduleLive
integration tests. Full suite: 10,210 / 0 failures. Format/dialyzer clean.

Also: cleaned up two stale inline comments in k8s/deployment.yaml that
disagreed with the values they sat next to (replicas/maxSurge).
2026-04-28 12:48:52 -05:00
e4686f31ce chore: pending worktree changes (k8s probe, profile loader, e2e Makefile)
- k8s/deployment.yaml: bump startup-probe failureThreshold from 12 to 24
  (70s -> 130s max startup time) to give the app more headroom on cold start.
- lib/towerops/profiles/yaml_profiles.ex: defer YAML profile loading from
  init/1 to a handle_info(:load_profiles, ...) so the supervisor (and Bandit)
  come up immediately and the profiles populate in the background within ~60s.
- e2e/Makefile: convenience target wrappers around the existing npm scripts.
2026-04-28 12:39:26 -05:00
FluxCD
2e6729777b chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1777396805-e822bc9 [skip ci] 2026-04-28 17:23:42 +00:00
FluxCD
135d9b2720 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1777312851-3dce118 [skip ci] 2026-04-27 18:04:14 +00:00
FluxCD
bbf8cfacf2 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1777043250-85dd821 [skip ci] 2026-04-24 15:13:53 +00:00
FluxCD
36e58d4d9f chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1776794780-0751069 [skip ci] 2026-04-21 18:08:21 +00:00
FluxCD
0e0cf7163e chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1776787421-9cb4c59 [skip ci] 2026-04-21 17:55:18 +00:00
FluxCD
093c24a783 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1776785720-0350ced [skip ci] 2026-04-21 15:37:36 +00:00
FluxCD
8a3d024453 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1776783978-91e3181 [skip ci] 2026-04-21 15:08:30 +00:00
FluxCD
2d6c7d28e2 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1776782753-04e7d5a [skip ci] 2026-04-21 14:47:58 +00:00
FluxCD
eeacfa4e70 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1776782194-2653e25 [skip ci] 2026-04-21 14:40:03 +00:00
FluxCD
cc2cad10a7 chore: update towerops image to git.mcintire.me/graham/towerops-web:main-1776278121-ecb30b2 [skip ci] 2026-04-15 18:45:21 +00:00
ecb30b2785 fix(flux): add imagepolicy setter markers to deployment (#238)
Without these comments the ImageUpdateAutomation with strategy=Setters
has nothing to rewrite, so new image tags detected by ImagePolicy never
get committed back to main and the cluster never rolls out new builds.

Reviewed-on: graham/towerops-web#238
2026-04-15 13:33:08 -05:00
c9cb95129c fix/production-workflow-conflict (#208)
Co-authored-by: Forgejo Actions <actions@git.mcintire.me>
Reviewed-on: graham/towerops-web#208
2026-03-28 12:42:23 -05:00
fc03ed7b0e Disable SSL for database connections on private network (#97)
Every timeout stack trace pointed at ssl_gen_statem.call/2 — the OTP 27
SSL gen_statem hanging during recv. PG is on private network (10.0.15.20)
and SSL verify was already disabled (verify_none), providing no security
benefit while adding CPU overhead and the gen_statem layer that caused
all connection timeouts.

Removed DATABASE_SSL and DATABASE_SSL_VERIFY env vars from both the
init container and main container. Also disabled SSL on the PG server
(ssl=off in postgresql.conf, hostssl→host in pg_hba.conf).

Reviewed-on: graham/towerops-web#97
2026-03-20 12:48:05 -05:00
8a54f9a866 Increase CPU limits to fix SSL connection timeouts (#96)
Pods were running at 500m/500m (100% of limit) with 44-47% of scheduling
periods being CPU-throttled. SSL decryption is CPU-intensive — when the
BEAM gets throttled mid ssl_gen_statem:call/2, the SSL recv stalls until
the cgroup allows CPU again, causing the 15s DBConnection timeout.

This was the actual root cause of "client timed out because it queued
and checked out the connection for longer than 15000ms" errors. Previous
fixes (TCP keepalive, pool tuning, oban pruner) were treating symptoms.

- CPU limit: 500m → 2000m (4 cores burst capacity)
- CPU request: 100m → 500m (guarantee adequate baseline)

Reviewed-on: graham/towerops-web#96
2026-03-20 12:24:06 -05:00
071729f65c Reduce pool size and deployment surge to prevent PG connection exhaustion (#94)
PG max_connections=100 (97 usable). With pool_size=15 and maxSurge=100%,
rolling deploys briefly run 4 pods × 15 = 60 pool connections plus Oban
notifiers, exceeding the limit and causing too_many_connections errors
that cascade into ssl recv: closed timeouts.

- pool_size: 15 → 10 (steady state: 2×10=20, deploy: 3×10=30)
- maxSurge: 100% → 1 (max 3 pods during rollout instead of 4)

Reviewed-on: graham/towerops-web#94
2026-03-20 10:39:52 -05:00
b03f280b65 fix-ci-docker (#59)
Co-authored-by: Forgejo Actions <actions@git.mcintire.me>
Reviewed-on: graham/towerops-web#59
2026-03-17 13:13:09 -05:00
06c5d14455 ui/remove-device-type-column (#49)
Co-authored-by: Forgejo Actions <actions@git.mcintire.me>
Reviewed-on: graham/towerops-web#49
2026-03-16 16:38:00 -05:00
8abf01ccb1 fix-mobile-qr-device-info-width (#43)
Co-authored-by: Forgejo Actions <actions@git.mcintire.me>
Reviewed-on: graham/towerops-web#43
2026-03-16 14:02:31 -05:00
Forgejo Actions
011d82ce26 chore: update production image to production-1773007128-e91d74d [skip ci] 2026-03-08 22:04:51 +00:00
CI
bf7004c770 chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772816933-2a61626 [skip ci] 2026-03-06 17:16:12 +00:00
d0e7eb4308
feat: add Stripe meter ID configuration
- Add stripe_meter_id to dev, runtime, and test configs
- Add STRIPE_METER_ID to k8s deployment secret references
- Use real Stripe meter and price IDs from Stripe setup
- Meter: mtr_test_61UHPU067veEZ7bhl41S77kvnTfgyODY
- Price: price_1T81XBS77kvnTfgyPlw1jF8N ($1/device/month)
- Include setup script for Stripe billing configuration
2026-03-06 11:08:06 -06:00
20f05584dc
fix: use k8s secret for Stripe env vars instead of hardcoded values
- Changed from hardcoded placeholder values to secretKeyRef
- References towerops-billing secret (with optional: true)
- Won't crash if secret doesn't exist yet
- User can create secret later with real Stripe keys
2026-03-06 11:08:06 -06:00
3523676359
feat: configure Stripe environment variables for dev and k8s
- Add Stripe test API keys to dev.exs for local development
- Add placeholder Stripe env vars to k8s deployment to prevent startup crashes
- Includes secret_key, webhook_secret, and price_id configuration
2026-03-06 11:08:05 -06:00
CI
1c081623aa chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772813291-f832130 [skip ci] 2026-03-06 16:14:54 +00:00
CI
43532007b8 chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772807346-b5e8e00 [skip ci] 2026-03-06 14:32:10 +00:00
CI
bc7922f476 chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772806694-acf7e55 [skip ci] 2026-03-06 14:21:09 +00:00
CI
a083c7069c chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772806349-1e072c7 [skip ci] 2026-03-06 14:15:35 +00:00
CI
e47b08c44f chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772805892-52329cf [skip ci] 2026-03-06 14:11:25 +00:00
CI
1038cc3d42 chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772805491-0c7d195 [skip ci] 2026-03-06 14:01:06 +00:00
CI
4ebe215a90 chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772804771-b5cf562 [skip ci] 2026-03-06 13:49:06 +00:00
CI
be9ebff63e chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772804218-9e525aa [skip ci] 2026-03-06 13:39:48 +00:00
CI
3ed732fecc chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772803826-1f49e1f [skip ci] 2026-03-06 13:33:19 +00:00
CI
d3c4a9cc32 chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772760484-7a13368 [skip ci] 2026-03-06 01:41:10 +00:00
CI
0bd82678ef chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772759087-9300415 [skip ci] 2026-03-06 01:15:38 +00:00
CI
964d9dab76 chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772736989-9e6d006 [skip ci] 2026-03-05 18:59:57 +00:00