Skip to content

PR-A: CI safety + bootable ECS monolith + Odoo state on RDS#81

Merged
tushabe merged 3 commits into
energy-iot:local-deploymentfrom
ramaguruprakash:feature/aws-arch-v2
Jul 13, 2026
Merged

PR-A: CI safety + bootable ECS monolith + Odoo state on RDS#81
tushabe merged 3 commits into
energy-iot:local-deploymentfrom
ramaguruprakash:feature/aws-arch-v2

Conversation

@ramaguruprakash

Copy link
Copy Markdown

PR-A of the piecewise production plan (docs/aws-arch-v2-plan.md, included here): make the AWS ECS stack safe, bootable, and durable — the base every later PR builds on. Read-only recon (documented in the plan) showed the ECS stack described by iac/ has never actually been deployed to account 470298448112, so this is a first-time bootstrap, not a migration.

Three parts, one PR, so the result is independently testable:

A1 — CI safety

  • destroy-pipeline.yml no longer runs on push to main. It previously ran terraform destroy -auto-approve on every push to main, racing the deploy pipeline. Now workflow_dispatch only, gated on typing the cluster name.
  • Removed the if: needs.deploy_aws_infrastructure.output.terraform_action != 'destroy' guards — that path doesn't exist (no job outputs are defined), so the conditions were always true; the destroy pipeline was also building and deploying images.
  • Fixed the task-def render chain: the final deploy step used the backend render output, silently discarding the odoo image update (and the odoo-db step rendered with the odoo image).
  • push-to-ecr.sh now pushes an explicit image list instead of grepping compose (which would have tried to push influxdb:1.8).

A2 — the monolith task can actually boot

  • Removed the edge container from the AWS stack. Edges run in the field (or locally) and connect in over ws://<task>:8081; they are not cloud containers.
  • openems-backend.sh renders the Felix configs (Metadata/Odoo, Timedata/InfluxDB) from env vars at startup. Defaults equal the docker-compose values, so local behavior is unchanged; ECS injects the RDS endpoint and Secrets Manager credentials through the same variables.
  • Task definition rewritten (iac/ecs.tf is the source of truth; the CI JSON mirrors it and only gets image URIs stamped): ui (:8089) + backend (:8075/:8079/:8081/:8082) + odoo (:8069) + influxdb, localhost inter-container addressing (containers in one awsvpc task share a network namespace — the previous compose-style hostnames db/odoo16 could never resolve), correct essential flags, container healthchecks, 2 vCPU / 6 GB (was 4/12).
  • Service deploys are stop-then-start (min 0 / max 100): the backend is a singleton (one websocket per edge, one telemetry writer) — two live copies must never coexist.
  • ⚠️ InfluxDB storage is ephemeral in this task (lost on replacement) — accepted for the PR-A base; PR-B moves telemetry to a managed store.

A3 — Odoo state on RDS (durable base)

  • App credentials are generated by Terraform into Secrets Manager and injected via ECS secrets; the execution role is scoped to that single ARN. Hardcoded/mismatched passwords removed from tfvars and the task-def JSON.
  • RDS hardening: deletion protection, 14-day automated backups, final snapshot, encrypted storage. DB security group drops an ssh-from-anywhere rule (RDS has no SSH).
  • Task security group trimmed to served ports only (8069 temp until the ALB PR, 8075, 8081, 8082, 8089). InfluxDB (:8086, no auth) is no longer internet-reachable.
  • Postgres pinned to 15 everywhere — the local image had drifted to postgres:18, which refuses the PG-15 data directory and exceeds Odoo 16's support matrix; tfvars had 18.1. Local image, local data, and RDS now agree.

How it was tested (local — the compose stack mirrors the ECS task)

Check Result
./setup.sh --edges 1 full bootstrap ✅ "All checks passed!" (backend→Postgres, backend→InfluxDB, Edge websocket, edge scheduler/RRD4j)
Entrypoint renders defaults pgHost="db", odooHost="odoo16" in the running container
ECS-style env override (fake RDS host + password containing " & | \) ✅ rendered config correct, quotes Felix-escaped
Edge connects through the env-rendered backend ✅ backend log: Edge.Websocket … Connections: 1; Metadata.Odoo registered edge0
Telemetry persisted ✅ InfluxQL query returns edge0 _sum/ProductionActivePower = 5000 W from measurement data
UI http://localhost:4200 → 200
terraform validate + terraform fmt -check (1.14, containerized) ✅ (validate caught and fixed an invalid SG description charset)
actionlint on both workflows ✅ clean
docker compose config ✅ clean
td JSON ↔ ecs.tf consistency (containers, cpu/mem) ✅ scripted comparison

Not testable locally (needs the account bootstrap below): terraform plan/apply, the actual Fargate boot, and the one-time Odoo DB init on AWS (odoo -d openems -i openems --stop-after-init via aws ecs run-task — runbook in the plan doc).

One-time bootstrap prerequisites (before first deploy)

  1. S3 state bucket eiot-openems-tf-state-file (per iac/backend.tf; uses S3-native locking) — does not exist yet.
  2. Valid AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/ECR_REGISTRY repo secrets with ECS/ECR/RDS/EC2/IAM/SecretsManager permissions (or move the pipeline to OIDC).
  3. First deploy: run the Deploy Pipeline via workflow_dispatch on this branch.

Follow-ups (tracked in docs/aws-arch-v2-plan.md)

  • PR-A2: bump jars — backend to 2026.1.0 (last monolithic release; upstream's own recommendation while the two-tier fixes #3795–#3798 remain unmerged), edge to 2026.7.0. This PR keeps the known-good 2025.11.0 jars to limit blast radius.
  • PR-B: InfluxDB out of the task (managed store) · PR-C: Route 53 + ACM + ALB (wss://) · PR-D: split UI/Odoo into their own services · PR-E: observability, SES, mTLS.

coeguru and others added 3 commits July 12, 2026 11:48
Strangler-fig plan superseding the MVP-shaped draft: PR-A (CI safety +
working monolith task + Odoo state to RDS, edge container removed from
AWS), then InfluxDB extraction, ALB/wss ingress, service split, and
hardening. Backend pinned to 2026.1.0 per upstream guidance; edges track
latest. Includes per-PR cost deltas, exit tests, and open questions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Guru <guru@coefficient.io>
…C2 is the only live env

Read-only recon of account 470298448112: no TF state bucket, no
openems-deployment VPC/log group/ALB. Live: openems-dev-stack EC2
(iac/dev + setup.sh) and a b2b-proxy Lambda. PR-A gains a one-time
bootstrap prerequisite (state bucket, lock table, secret, CI creds).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Guru <guru@coefficient.io>
A1 — CI safety:
- destroy-pipeline: workflow_dispatch only with typed confirmation
  (was: terraform destroy on every push to main), destroy job only
- deploy-pipeline: drop always-true needs.*.output guards, fix render
  chain (final deploy now uses the last render output; odoo-db/edge
  steps removed), edge image no longer built/pushed
- push-to-ecr.sh: explicit image list (was: grep over compose, which
  would try to push influxdb:1.8)

A2 — the monolith task can actually boot:
- openems-backend.sh renders Metadata/Odoo + Timedata/InfluxDB configs
  from env vars at startup (defaults = compose values); ECS injects
  RDS endpoint + Secrets Manager credentials through the same contract
- ecs.tf task def rewritten: ui/backend/odoo/influxdb containers,
  localhost inter-container addressing (awsvpc shared netns), correct
  essential flags + healthchecks, 2 vCPU / 6 GB, edge container removed
  (edges run in the field, not AWS)
- service deploys stop-then-start (min 0 / max 100): backend singleton
- td JSON regenerated to mirror ecs.tf (CI only stamps image URIs)

A3 — Odoo state on RDS:
- app credentials generated by Terraform into Secrets Manager; injected
  via ECS secrets; execution role scoped to that one ARN; hardcoded
  passwords removed from tfvars/task-def
- RDS: deletion protection, 14d backups, final snapshot, encrypted
  storage; DB SG drops the ssh-from-anywhere rule
- openems SG trimmed to served ports only (8069/8075/8081/8082/8089);
  InfluxDB (no auth) no longer internet-reachable
- Postgres pinned to 15 across local image, data dir, and RDS
  (image had drifted to 18 and refused the PG15 data directory)

Verified locally: setup.sh green; ECS-style env override renders
correct configs (incl. special-char passwords); edge connects
(Edge.Websocket Connections: 1); UI 200; telemetry persisted in
InfluxDB. terraform validate + fmt clean; actionlint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Guru <guru@coefficient.io>
@tushabe
tushabe merged commit 6b63f32 into energy-iot:local-deployment Jul 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants