From f66549ae7e3a1eb4205c0e91164ea96630c215cc Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 30 Jun 2026 08:24:52 -0400 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20ENVIRONMENTS.md=20+=20compare-prod-?= =?UTF-8?q?dev.sh=20=E2=80=94=20prod/dev=20split,=20one-command=20drift=20?= =?UTF-8?q?compare?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- ENVIRONMENTS.md | 31 +++++++++++++++++++++++++++ compare-prod-dev.sh | 51 ++++++++++++++++++++++++++++++++++++++++++++ hiveiq-openmetal | 2 +- hiveiq-openmetal-dev | 1 + 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 ENVIRONMENTS.md create mode 100755 compare-prod-dev.sh create mode 160000 hiveiq-openmetal-dev diff --git a/ENVIRONMENTS.md b/ENVIRONMENTS.md new file mode 100644 index 0000000..1b7b9fc --- /dev/null +++ b/ENVIRONMENTS.md @@ -0,0 +1,31 @@ +# HiveOps Deployment Environments + +**Two repos, one per environment — no duplication.** Production config lives only in the prod +repo; dev config lives only in the dev repo. + +| Env | Repo (cloned as) | Config path | Live URL | VM | +|-----|------------------|-------------|----------|----| +| **PRODUCTION** | `hiveiq-openmetal-prod` (`hiveiq-openmetal/`) | `hiveops/instances/services/` | bcos.cloud | 173.231.195.250 | +| **DEV / staging** | `hiveiq-openmetal-dev/` | `hiveops/instances/dev/` | bcos.dev | 173.231.195.251 | + +Production also keeps its other instances in the **prod** repo: `database`, `browser`, `ollama`, +`logging`, and the `bcos-*` services (mail, office, share, proxy, gitea, odoo). **Dev is all-in-one** +— one VM bundles postgres/kafka/registry/etc that prod splits across VMs. + +## Compare dev vs prod +The two repos are **structurally parallel** (`compose/.yml`, `nginx/conf.d/.conf`): + +```bash +./compare-prod-dev.sh # drift summary — which configs differ or are env-only +./compare-prod-dev.sh incident # full diff of a specific service +# or diff directly: +diff hiveiq-openmetal-dev/hiveops/instances/dev/nginx/conf.d/api.conf \ + hiveiq-openmetal/hiveops/instances/services/nginx/conf.d/api.conf +``` + +(For this to work, clone **both** repos side by side under this directory.) + +## Source of truth +The live VMs are **hand-managed** (not git-fed). These repos are the **reference/backup** — keep +them in sync with the VMs whenever you change deployment config. `.env` **secrets are gitignored**: +they live only on the VMs and in **Vaultwarden** (`pw.bcos.cloud`). diff --git a/compare-prod-dev.sh b/compare-prod-dev.sh new file mode 100755 index 0000000..099712a --- /dev/null +++ b/compare-prod-dev.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# Compare bcos.dev (DEV) vs bcos.cloud (PROD) deployment config, side by side. +# +# ./compare-prod-dev.sh # DRIFT SUMMARY: which configs differ / are env-only +# ./compare-prod-dev.sh incident # FULL DIFF of every config matching "incident" +# ./compare-prod-dev.sh api # FULL DIFF of the nginx api.conf, etc. +# +# PROD = hiveiq-openmetal/hiveops/instances/services (bcos.cloud, 173.231.195.250) +# DEV = hiveiq-openmetal-dev/hiveops/instances/dev (bcos.dev, 173.231.195.251) +# +# Both repos are structurally parallel: compose/.yml + nginx/conf.d/.conf. +set -uo pipefail +HERE=$(cd "$(dirname "$0")" && pwd) +PROD="$HERE/hiveiq-openmetal/hiveops/instances/services" +DEV="$HERE/hiveiq-openmetal-dev/hiveops/instances/dev" +[ -d "$PROD" ] || { echo "PROD config not found: $PROD"; exit 1; } +[ -d "$DEV" ] || { echo "DEV config not found: $DEV (clone hiveiq-openmetal-dev next to hiveiq-openmetal)"; exit 1; } + +FILTER="${1:-}" + +scan() { # $1 = subdir ; $2 = glob + local sub="$1" glob="$2" df pf n + echo "## $sub" + for df in "$DEV/$sub"/$glob; do + [ -e "$df" ] || continue; n=$(basename "$df") + pf="$PROD/$sub/$n" + if [ ! -e "$pf" ]; then echo " [dev-only] $n" + elif ! diff -q "$pf" "$df" >/dev/null 2>&1; then echo " [DIFFERS] $n"; fi + done + for pf in "$PROD/$sub"/$glob; do + [ -e "$pf" ] || continue; n=$(basename "$pf") + [ -e "$DEV/$sub/$n" ] || echo " [prod-only] $n" + done +} + +if [ -n "$FILTER" ]; then + echo "=== FULL DIFF (prod → dev) for *$FILTER* ===" + for sub in compose nginx/conf.d; do + for df in "$DEV/$sub/"*"$FILTER"*; do + [ -e "$df" ] || continue; n=$(basename "$df"); pf="$PROD/$sub/$n" + echo "--- $sub/$n ---" + if [ -e "$pf" ]; then diff -u "$pf" "$df" || true; else echo " (dev-only — no prod counterpart)"; fi + done + done +else + echo "=== DRIFT SUMMARY: bcos.dev (DEV) vs bcos.cloud (PROD) ===" + scan compose '*.yml' + scan nginx/conf.d '*.conf' + echo "" + echo "→ './compare-prod-dev.sh ' for the full diff of one config (e.g. incident, api, auth)." +fi diff --git a/hiveiq-openmetal b/hiveiq-openmetal index a62c9b7..bc2c5db 160000 --- a/hiveiq-openmetal +++ b/hiveiq-openmetal @@ -1 +1 @@ -Subproject commit a62c9b712da9fdaf8351c70e3aa0a5955d32bdb8 +Subproject commit bc2c5dbb0d19227ffb8e1dab64284b62613ef3bc diff --git a/hiveiq-openmetal-dev b/hiveiq-openmetal-dev new file mode 160000 index 0000000..f9ab5ea --- /dev/null +++ b/hiveiq-openmetal-dev @@ -0,0 +1 @@ +Subproject commit f9ab5ea35e05b9510f79d266649f9db398fb123d From 4d19f1023eaf71deaed90f9638e0d7bc27eea7be Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 30 Jun 2026 08:44:48 -0400 Subject: [PATCH 2/3] chore: nest prod+dev repos under hiveiq-openmetal/ ; move compare script + ENVIRONMENTS.md into it Co-Authored-By: Claude Opus 4.8 --- ENVIRONMENTS.md | 31 --------------------------- compare-prod-dev.sh | 51 --------------------------------------------- 2 files changed, 82 deletions(-) delete mode 100644 ENVIRONMENTS.md delete mode 100755 compare-prod-dev.sh diff --git a/ENVIRONMENTS.md b/ENVIRONMENTS.md deleted file mode 100644 index 1b7b9fc..0000000 --- a/ENVIRONMENTS.md +++ /dev/null @@ -1,31 +0,0 @@ -# HiveOps Deployment Environments - -**Two repos, one per environment — no duplication.** Production config lives only in the prod -repo; dev config lives only in the dev repo. - -| Env | Repo (cloned as) | Config path | Live URL | VM | -|-----|------------------|-------------|----------|----| -| **PRODUCTION** | `hiveiq-openmetal-prod` (`hiveiq-openmetal/`) | `hiveops/instances/services/` | bcos.cloud | 173.231.195.250 | -| **DEV / staging** | `hiveiq-openmetal-dev/` | `hiveops/instances/dev/` | bcos.dev | 173.231.195.251 | - -Production also keeps its other instances in the **prod** repo: `database`, `browser`, `ollama`, -`logging`, and the `bcos-*` services (mail, office, share, proxy, gitea, odoo). **Dev is all-in-one** -— one VM bundles postgres/kafka/registry/etc that prod splits across VMs. - -## Compare dev vs prod -The two repos are **structurally parallel** (`compose/.yml`, `nginx/conf.d/.conf`): - -```bash -./compare-prod-dev.sh # drift summary — which configs differ or are env-only -./compare-prod-dev.sh incident # full diff of a specific service -# or diff directly: -diff hiveiq-openmetal-dev/hiveops/instances/dev/nginx/conf.d/api.conf \ - hiveiq-openmetal/hiveops/instances/services/nginx/conf.d/api.conf -``` - -(For this to work, clone **both** repos side by side under this directory.) - -## Source of truth -The live VMs are **hand-managed** (not git-fed). These repos are the **reference/backup** — keep -them in sync with the VMs whenever you change deployment config. `.env` **secrets are gitignored**: -they live only on the VMs and in **Vaultwarden** (`pw.bcos.cloud`). diff --git a/compare-prod-dev.sh b/compare-prod-dev.sh deleted file mode 100755 index 099712a..0000000 --- a/compare-prod-dev.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env bash -# Compare bcos.dev (DEV) vs bcos.cloud (PROD) deployment config, side by side. -# -# ./compare-prod-dev.sh # DRIFT SUMMARY: which configs differ / are env-only -# ./compare-prod-dev.sh incident # FULL DIFF of every config matching "incident" -# ./compare-prod-dev.sh api # FULL DIFF of the nginx api.conf, etc. -# -# PROD = hiveiq-openmetal/hiveops/instances/services (bcos.cloud, 173.231.195.250) -# DEV = hiveiq-openmetal-dev/hiveops/instances/dev (bcos.dev, 173.231.195.251) -# -# Both repos are structurally parallel: compose/.yml + nginx/conf.d/.conf. -set -uo pipefail -HERE=$(cd "$(dirname "$0")" && pwd) -PROD="$HERE/hiveiq-openmetal/hiveops/instances/services" -DEV="$HERE/hiveiq-openmetal-dev/hiveops/instances/dev" -[ -d "$PROD" ] || { echo "PROD config not found: $PROD"; exit 1; } -[ -d "$DEV" ] || { echo "DEV config not found: $DEV (clone hiveiq-openmetal-dev next to hiveiq-openmetal)"; exit 1; } - -FILTER="${1:-}" - -scan() { # $1 = subdir ; $2 = glob - local sub="$1" glob="$2" df pf n - echo "## $sub" - for df in "$DEV/$sub"/$glob; do - [ -e "$df" ] || continue; n=$(basename "$df") - pf="$PROD/$sub/$n" - if [ ! -e "$pf" ]; then echo " [dev-only] $n" - elif ! diff -q "$pf" "$df" >/dev/null 2>&1; then echo " [DIFFERS] $n"; fi - done - for pf in "$PROD/$sub"/$glob; do - [ -e "$pf" ] || continue; n=$(basename "$pf") - [ -e "$DEV/$sub/$n" ] || echo " [prod-only] $n" - done -} - -if [ -n "$FILTER" ]; then - echo "=== FULL DIFF (prod → dev) for *$FILTER* ===" - for sub in compose nginx/conf.d; do - for df in "$DEV/$sub/"*"$FILTER"*; do - [ -e "$df" ] || continue; n=$(basename "$df"); pf="$PROD/$sub/$n" - echo "--- $sub/$n ---" - if [ -e "$pf" ]; then diff -u "$pf" "$df" || true; else echo " (dev-only — no prod counterpart)"; fi - done - done -else - echo "=== DRIFT SUMMARY: bcos.dev (DEV) vs bcos.cloud (PROD) ===" - scan compose '*.yml' - scan nginx/conf.d '*.conf' - echo "" - echo "→ './compare-prod-dev.sh ' for the full diff of one config (e.g. incident, api, auth)." -fi From 23d6e2e9b1181ee56d987dbf46b2330013835ade Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 30 Jun 2026 08:46:33 -0400 Subject: [PATCH 3/3] chore(umbrella): untrack nested repos as gitlinks; track compare script + ENVIRONMENTS.md under hiveiq-openmetal/ Co-Authored-By: Claude Opus 4.8 --- .gitignore | 6 ++++ hiveiq-openmetal | 1 - hiveiq-openmetal-dev | 1 - hiveiq-openmetal/ENVIRONMENTS.md | 31 +++++++++++++++++ hiveiq-openmetal/compare-prod-dev.sh | 51 ++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 .gitignore delete mode 160000 hiveiq-openmetal delete mode 160000 hiveiq-openmetal-dev create mode 100644 hiveiq-openmetal/ENVIRONMENTS.md create mode 100755 hiveiq-openmetal/compare-prod-dev.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c2e272 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ + +# nested repos — independent, not tracked by this umbrella +/hiveiq-openmetal/hiveiq-openmetal-prod/ +/hiveiq-openmetal/hiveiq-openmetal-dev/ +/hiveiq-devops/ +/hiveiq-docs/ diff --git a/hiveiq-openmetal b/hiveiq-openmetal deleted file mode 160000 index bc2c5db..0000000 --- a/hiveiq-openmetal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bc2c5dbb0d19227ffb8e1dab64284b62613ef3bc diff --git a/hiveiq-openmetal-dev b/hiveiq-openmetal-dev deleted file mode 160000 index f9ab5ea..0000000 --- a/hiveiq-openmetal-dev +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f9ab5ea35e05b9510f79d266649f9db398fb123d diff --git a/hiveiq-openmetal/ENVIRONMENTS.md b/hiveiq-openmetal/ENVIRONMENTS.md new file mode 100644 index 0000000..1b7b9fc --- /dev/null +++ b/hiveiq-openmetal/ENVIRONMENTS.md @@ -0,0 +1,31 @@ +# HiveOps Deployment Environments + +**Two repos, one per environment — no duplication.** Production config lives only in the prod +repo; dev config lives only in the dev repo. + +| Env | Repo (cloned as) | Config path | Live URL | VM | +|-----|------------------|-------------|----------|----| +| **PRODUCTION** | `hiveiq-openmetal-prod` (`hiveiq-openmetal/`) | `hiveops/instances/services/` | bcos.cloud | 173.231.195.250 | +| **DEV / staging** | `hiveiq-openmetal-dev/` | `hiveops/instances/dev/` | bcos.dev | 173.231.195.251 | + +Production also keeps its other instances in the **prod** repo: `database`, `browser`, `ollama`, +`logging`, and the `bcos-*` services (mail, office, share, proxy, gitea, odoo). **Dev is all-in-one** +— one VM bundles postgres/kafka/registry/etc that prod splits across VMs. + +## Compare dev vs prod +The two repos are **structurally parallel** (`compose/.yml`, `nginx/conf.d/.conf`): + +```bash +./compare-prod-dev.sh # drift summary — which configs differ or are env-only +./compare-prod-dev.sh incident # full diff of a specific service +# or diff directly: +diff hiveiq-openmetal-dev/hiveops/instances/dev/nginx/conf.d/api.conf \ + hiveiq-openmetal/hiveops/instances/services/nginx/conf.d/api.conf +``` + +(For this to work, clone **both** repos side by side under this directory.) + +## Source of truth +The live VMs are **hand-managed** (not git-fed). These repos are the **reference/backup** — keep +them in sync with the VMs whenever you change deployment config. `.env` **secrets are gitignored**: +they live only on the VMs and in **Vaultwarden** (`pw.bcos.cloud`). diff --git a/hiveiq-openmetal/compare-prod-dev.sh b/hiveiq-openmetal/compare-prod-dev.sh new file mode 100755 index 0000000..9af7382 --- /dev/null +++ b/hiveiq-openmetal/compare-prod-dev.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# Compare bcos.dev (DEV) vs bcos.cloud (PROD) deployment config, side by side. +# +# ./compare-prod-dev.sh # DRIFT SUMMARY: which configs differ / are env-only +# ./compare-prod-dev.sh incident # FULL DIFF of every config matching "incident" +# ./compare-prod-dev.sh api # FULL DIFF of the nginx api.conf, etc. +# +# PROD = hiveiq-openmetal/hiveops/instances/services (bcos.cloud, 173.231.195.250) +# DEV = hiveiq-openmetal-dev/hiveops/instances/dev (bcos.dev, 173.231.195.251) +# +# Both repos are structurally parallel: compose/.yml + nginx/conf.d/.conf. +set -uo pipefail +HERE=$(cd "$(dirname "$0")" && pwd) +PROD="$HERE/hiveiq-openmetal-prod/hiveops/instances/services" +DEV="$HERE/hiveiq-openmetal-dev/hiveops/instances/dev" +[ -d "$PROD" ] || { echo "PROD config not found: $PROD"; exit 1; } +[ -d "$DEV" ] || { echo "DEV config not found: $DEV (clone hiveiq-openmetal-dev next to hiveiq-openmetal)"; exit 1; } + +FILTER="${1:-}" + +scan() { # $1 = subdir ; $2 = glob + local sub="$1" glob="$2" df pf n + echo "## $sub" + for df in "$DEV/$sub"/$glob; do + [ -e "$df" ] || continue; n=$(basename "$df") + pf="$PROD/$sub/$n" + if [ ! -e "$pf" ]; then echo " [dev-only] $n" + elif ! diff -q "$pf" "$df" >/dev/null 2>&1; then echo " [DIFFERS] $n"; fi + done + for pf in "$PROD/$sub"/$glob; do + [ -e "$pf" ] || continue; n=$(basename "$pf") + [ -e "$DEV/$sub/$n" ] || echo " [prod-only] $n" + done +} + +if [ -n "$FILTER" ]; then + echo "=== FULL DIFF (prod → dev) for *$FILTER* ===" + for sub in compose nginx/conf.d; do + for df in "$DEV/$sub/"*"$FILTER"*; do + [ -e "$df" ] || continue; n=$(basename "$df"); pf="$PROD/$sub/$n" + echo "--- $sub/$n ---" + if [ -e "$pf" ]; then diff -u "$pf" "$df" || true; else echo " (dev-only — no prod counterpart)"; fi + done + done +else + echo "=== DRIFT SUMMARY: bcos.dev (DEV) vs bcos.cloud (PROD) ===" + scan compose '*.yml' + scan nginx/conf.d '*.conf' + echo "" + echo "→ './compare-prod-dev.sh ' for the full diff of one config (e.g. incident, api, auth)." +fi