Commit Graph

69 Commits

Author SHA1 Message Date
root
d498c81d5b Add per-backup status dot (green/yellow/red/unknown) to the UI
backup-k8s-apps.sh now tracks step-level failures (manifests, secret,
db_dump, pvc_data) into an ERRORS array during the per-app loop, and
writes a .meta.json sidecar alongside each archive once all 3 storage
tiers are known - apps included, final size, the error list, and
per-tier ok/failed/skipped status. Sidecar is mirrored to VM/R2 the
same best-effort way the .sha256 sidecar already is, and cleaned up
by both local and R2 retention pruning plus manual delete.

modules/backups.py reads these sidecars (never decompresses the
archive) to compute a status per backup at list-render time:
  - red: any recorded error, or any tier status starting with "failed"
  - yellow: no errors, but size deviates >40% from the rolling average
    of the last 5 backups sharing the same app-combination (apps_key)
  - green: no errors, size within range (or first backup of its
    app-combination - nothing to compare against yet)
  - unknown: no sidecar at all (legacy myapps-backup-* archives, or
    any k8s backup made before this shipped) - no backfill attempted,
    old runs never recorded step-level failures to reconstruct from

/backups route now passes get_local_backups_with_status()/
get_vm_backups_with_status() instead of the plain filename lists
(get_local_backups()/get_vm_backups() themselves are untouched -
/restore and /api/backups still use the plain versions, they don't
need the dot). Template renders a colored dot next to each entry with
a tooltip showing apps/size.

Verified: real n8n backup produces a correct sidecar synced to all 3
tiers; JSON-writer argv parsing and the red/yellow/green/unknown
decision logic each checked against synthetic cases; full Jinja render
checked against real local + VM data pulled from the live pod.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017avLHFqkiti3g62Anq9sVA
2026-08-21 02:46:50 +02:00
root
de0b1ee4db Fix backups Audit/Details for k8s-format archives + broken local access
Two separate bugs found while testing the Audit/Details UI against a
real k8s-format backup (myapps-k8s-backup-*):

1. Format-hardcoded checks. audit_backup()'s Internal Structure and
   Volume Count checks assumed the legacy Docker-era archive layout
   (volumes/*.tar.gz, compose-files/) and would fail every k8s-format
   backup (per-app dirs with manifests.yaml/db-dump.sql.gz/pvc-data.tar.gz)
   even when it's perfectly healthy - same root cause as the
   myapps-backup-*/myapps-k8s-backup-* prefix bug fixed earlier, just in
   the audit checks instead of the listing/delete glob. cloud_backup.py's
   r2_audit_backup() had the identical unpatched filename regex, and
   app.py's /api/backups/details route had its own, which outright
   400'd any k8s-format filename before even looking at it.

2. A bigger, separate bug this surfaced: get_local_backups(),
   get_vm_backups(), and _resolve_archive_path() all branch on
   RUNNING_ON_MAIN_SERVER to decide between direct filesystem access and
   SSH-to-self - and from inside the management-platform pod that flag's
   hostname check can be wrong for the pod's own ephemeral hostname
   depending on how it's evaluated, sending these down the SSH branch
   using a topology (separate warm-standby-on-the-VM SSH path) that
   doesn't apply to a pod that already has /root hostPath-mounted in.
   Fixed by trying direct filesystem access first wherever the archive
   would already be locally reachable, falling back to the existing SSH
   paths otherwise - this preserves the original warm-standby-on-VM
   failover design (a real second deployment of this platform on the VM
   host, kept reachable via SSH when the main server is down) completely
   unchanged; it only adds the fast local path for the case where the
   caller already has direct filesystem access.

Verified against both a real k8s-format backup (odoo, single-app) and a
real legacy-format backup on disk - both audit correctly now, with
format-appropriate checks and labels.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017avLHFqkiti3g62Anq9sVA
2026-08-21 02:00:07 +02:00
root
a8f996422c Rewrite Application Sites page to reflect real k8s state
modules/sites.py was still a fully Docker-era hardcoded registry:
container names (odoo-clean-odoo-1, frappe-erpnext, nextcloud-app,
mautic-app, n8n-app) that no longer exist post-migration, checked via
`docker inspect` over SSH, plus hardcoded domain/port fields -
nextcloud and mautic even had domain: None, silently falling back to
dead Docker host-port URLs while their real Ingress domains
(next.cloud.nav.ovh, mautics.nav.ovh) sat unused.

Now sources everything live from the cluster:
- Domain + TLS from the actual Ingress object per app (via the new
  get_ingress_info() in modules/kubernetes.py), not a static guess.
  Odoo/Nextcloud's Ingress lives in `default` (see prior commit for the
  RBAC this needed); n8n/mautic/erpnext's lives in their own namespace.
- App/DB/cache/worker/scheduler status from real Deployment state
  (list_deployments_for_namespace(), new in modules/kubernetes.py)
  instead of `docker inspect`.
- Health probe now hits the real domain directly from the pod (it has
  normal internet egress) instead of SSH-ing back out to the host to
  curl a public HTTPS URL, which is what the RUNNING_ON_MAIN_SERVER
  branch would have done for a pod whose hostname never matches the
  main-server hostname check.

Same API/template contract as before (get_sites_list/get_site_health
return the same field shapes) - templates/pages/sites.html needs no
changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017avLHFqkiti3g62Anq9sVA
2026-08-21 01:43:38 +02:00
root
4dd4b8ef9b Checkout: hostPath-mount the VPS's own CloudOps checkout instead of cloning
18 straight clone failures today (early EOF / invalid index-pack) even with
http.postBuffer/http.version tuning applied — Gitea's HTTP endpoint itself is
degraded right now, not something fixable client-side. Sidesteps it entirely:
the docker-agent pod template now hostPath-mounts /root/CloudOps (read-only,
see k3s-cloud-init.groovy) and Checkout just `cp -r`s from it, no network
fetch at all. Build/SonarQube paths revert to ./platform/ (no more repo/
subdirectory, since we're not cloning into one).

Real tradeoff, accepted deliberately: builds now reflect whatever's on the
VPS's disk at build time, not necessarily what's pushed to Gitea. Depends on
/root/CloudOps being kept current via the normal git pull workflow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 11:55:41 +02:00
root
3c90fe9ce8 Replace Jenkins Git plugin checkout with a plain shell clone + retry loop
The Git plugin's checkout([...]) step doesn't expose http.postBuffer/
http.version tuning, which is what's reliably fixed every stuck
push/clone today (VPS and both laptops) — meanwhile checkout was failing
~10 times in a row, consistently dying at 84-95% during the shallow clone
(early EOF / invalid index-pack). Bypasses the plugin entirely: a plain
`git clone` with those settings applied, wrapped in its own 8-attempt
bash retry loop, using the existing dd13f593-06b1-4a5a-9477-2df0d186b490
credential (confirmed via credentials.xml to be a UsernamePasswordCredentialsImpl,
compatible with the usernamePassword binding as-is).

Code now lands in a repo/ subdirectory instead of the workspace root, so
every stage referencing a repo-relative path was updated to match:
- Build Docker Image: ./platform/ -> ./repo/platform/
- SonarQube Analysis: -Dsonar.sources=platform -> -Dsonar.sources=repo/platform
Deploy to Kubernetes needed no changes — it only references the already-built
image tag and hardcoded kubectl args, no filesystem paths into the checkout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 11:46:39 +02:00
root
a6fb9e5e18 Wire management-platform's backup/restore routes to the k8s scripts
api_backup_run and restore_start were still hardcoded to the Docker-era
backup-myapps.sh/restore-myapps.sh, which target Docker volumes that no
longer exist for the 5 apps now running in k3s (n8n, odoo, mautic,
nextcloud, frappe/erpnext) — every backup/restore triggered from the UI
has been silently hollow for these apps since the migration.

- api_backup_run: /root/backup-myapps.sh -> /root/CloudOps/backup/backup-k8s-apps.sh
- restore_start: switched from the old image-relative path (which resolved
  to /app/restore-myapps.sh, baked into the Docker image from platform/)
  to an absolute /root/CloudOps/backup/restore-k8s-apps.sh path — the new
  backup/ folder is a sibling of platform/, not part of the Docker build
  context, so it's only reachable via the pod's existing /root hostPath
  mount, the same way api_backup_run already reaches its script.

--apps flag shape and the job-log streaming contract are unchanged, so no
frontend/template changes needed for the core flow. modules/backups.py's
three hardcoded myapps-backup-* references (get_local_backups, get_vm_backups
x2, delete_backup's filename regex) now also recognize the new
myapps-k8s-backup-* prefix, so both backup lineages stay visible/manageable
in the UI.

Depends on the previous commit (scoped ServiceAccount + k3s kubectl access
for the pod) to actually function when triggered from the UI.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 11:30:14 +02:00
b4308b7d15 fix jenkinsfile structure, add retry(5) to checkout 2026-08-14 12:52:00 +01:00
8f6add243f add retry(5) to checkout stage - gitea git-upload-pack drops connections intermittently 2026-08-14 12:49:06 +01:00
root
9791d541de fix jenkins checkout: skip default full checkout, use shallow clone 2026-08-14 13:37:52 +02:00
a284269574 test push after jenkins checkout fix 2026-08-14 12:33:28 +01:00
84f80b7779 Add read-only Kubernetes cluster view alongside Docker container view
New modules/kubernetes.py lists pods and deployments across the 8 app
namespaces via the in-cluster management-platform-viewer-sa (read-only,
no secrets/exec/log), with metrics-server usage as a best-effort extra
that degrades silently when unreachable. New /cluster page and
/api/cluster endpoint, nav entry, and templates render pods/deployments
grouped by namespace using the existing card/badge design system.
Additive only — no existing Docker routes or views touched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 11:40:03 +01:00
5c9d5372a2 fix deploy stage: use k3s kubectl, mask token from logs 2026-08-06 01:31:40 +01:00
6af8e5f791 sonar sidecar container, unique image tags, real k8s deploy stage 2026-08-06 01:06:24 +01:00
78d114f41d switch to k8s agent, remove docker deploy placeholder 2026-08-06 00:02:16 +01:00
04bbbb192b Change : sonarqubefix , backup.py 2026-06-21 19:31:24 +01:00
32feb9d4eb Change : UI/UX design 2026-06-21 19:16:07 +01:00
ae267a6d9b Change : UI/UX design 2026-06-21 18:56:18 +01:00
b43c87de73 Change : display 2026-06-21 18:15:36 +01:00
9b2bc907aa Change : display 2026-06-21 18:05:52 +01:00
6ee29a462e Change : Backup pick 2026-06-21 01:17:51 +01:00
bf9c4a01b2 Change : Backup pick 2026-06-21 00:20:37 +01:00
c3e3a3b28c Change : dashboard , containers 2026-06-12 21:49:47 +01:00
df99603d9e ADD SonarQube 2026-06-10 17:16:30 +01:00
c9db50638e ADD SonarQube 2026-06-10 17:10:43 +01:00
ec53903726 ADD SonarQube 2026-06-10 17:06:03 +01:00
4e39130210 fix jenkins build 2026-06-08 13:30:25 +01:00
dd384aebe4 fix jenkins build 2026-06-08 13:26:55 +01:00
e2fd7e7c91 ADD: remove architecture , fix sites 2026-06-07 18:35:25 +01:00
515fc94754 ADD: remove architecture , fix sites 2026-06-07 18:31:10 +01:00
d4d15da0df ADD: sites and architecture module fix 2026-06-07 18:16:20 +01:00
c3fbb0b9da ADD: sites and architecture module fix 2026-06-07 18:11:02 +01:00
f51d5755c2 ADD: sites and architecture module fix 2026-06-07 18:06:09 +01:00
6df165d8d7 ADD: sites and architecture module 2026-06-07 17:52:26 +01:00
dbc83830ef fix: hostname 2026-06-06 15:45:36 +01:00
a7c3e3e7fe fix: restore script 2026-06-06 15:10:39 +01:00
715993af46 fix: restore script 2026-06-05 17:37:45 +01:00
0d7468dd7f fix: remove BuildKit due to missing buildx component 2026-06-04 15:55:49 +01:00
c37f83433c fix: remove BuildKit due to missing buildx component 2026-06-04 15:42:04 +01:00
eacf533e9f fix: remove BuildKit due to missing buildx component 2026-06-04 15:40:55 +01:00
3ee079b18e fix: use psutil for reliable CPU and memory metrics 2026-06-04 15:36:39 +01:00
b3d3c0d457 fix: use psutil for reliable CPU and memory metrics 2026-06-04 15:24:02 +01:00
47600ccd42 fix: remove /proc/sys/kernel/hostname mount in docker run 2026-06-04 15:12:35 +01:00
7255c510b3 fix: cpu/memory , test webhook 2026-06-04 14:53:34 +01:00
92908695ae fix: cpu/memory , test webhook 2026-06-04 14:42:36 +01:00
7a3f3113f3 fix: cpu/memory , test webhook 2026-06-04 14:37:55 +01:00
a89fe1ecfd fix: cpu/memory , test webhook 2026-06-04 14:29:22 +01:00
a5bd4b75cf fix: cpu/memory , test webhook 2026-06-04 14:16:45 +01:00
d2a7e72dd0 fix: cpu/memory 2026-06-04 13:53:46 +01:00
a5ddeba7be fix: add docker CLI and host passwd mount 2026-06-04 13:07:08 +01:00
161e5f8a86 fix: add docker CLI and host passwd mount 2026-06-04 12:59:05 +01:00