@@ -108,7 +108,7 @@ Seed-ul curent produce: |
||
| 108 | 108 |
- workerii `dhcp-router` și `mdns-listener` |
| 109 | 109 |
- Work Order-ul existent pentru retragerea numelor legacy |
| 110 | 110 |
|
| 111 |
-`config/local-hosts.tsv` rămâne manifest generat explicit din tabelele runtime. |
|
| 111 |
+`config/local-hosts.tsv` rămâne manifest generat explicit din tabelele runtime, dar scriptul de sync citește manifestul direct din SQLite-ul runtime de pe jumper. |
|
| 112 | 112 |
|
| 113 | 113 |
## Inspecție |
| 114 | 114 |
|
@@ -28,8 +28,8 @@ Implementarea versionată este: |
||
| 28 | 28 |
|--------|-----| |
| 29 | 29 |
| `var/host-manager.sqlite` | sursa de adevăr runtime pentru registry și Work Orders | |
| 30 | 30 |
| `config/hosts.yaml` | seed/snapshot export pentru hosturi și FQDN-uri canonice | |
| 31 |
-| `config/local-hosts.tsv` | manifest DNS generat, cu A records pentru hosturi/aliasuri de host și CNAME records pentru vhosturi | |
|
| 32 |
-| `scripts/sync_local_hosts.sh` | generează și sincronizează `/etc/hosts`, `cloaking-rules.txt` și `/ip dns static` | |
|
| 31 |
+| `config/local-hosts.tsv` | export DNS generat din registry-ul SQLite, cu A records pentru hosturi/aliasuri de host și CNAME records pentru vhosturi | |
|
| 32 |
+| `scripts/sync_local_hosts.sh` | citește manifestul DNS din SQLite-ul runtime de pe jumper și sincronizează `/etc/hosts`, `cloaking-rules.txt` și `/ip dns static` | |
|
| 33 | 33 |
|
| 34 | 34 |
`madagascar.xdev.ro` este domeniul implicit. Pentru orice host real `*.madagascar.xdev.ro`, aliasul scurt este derivat automat. De exemplu, `autonas01.madagascar.xdev.ro` publică și `autonas01`. Vhosturile, de exemplu `pmx.baobab.madagascar.xdev.ro`, se publică drept CNAME către hostul care le servește; aliasul scurt derivat, de exemplu `pmx.baobab`, este tot CNAME. Aliasurile derivate nu se declară separat în registry. |
| 35 | 35 |
|
@@ -40,7 +40,7 @@ Când inventarele se contrazic, ordinea de încredere este: |
||
| 40 | 40 |
1. DHCP lease/reservation pe router (`admin@192.168.2.1`) — autoritatea pentru alocarea IP-urilor pe LAN. Configurațiile statice locale nu au voie să mute un IP peste DHCP; cel mult semnalează o rezervare lipsă sau o intrare veche. |
| 41 | 41 |
2. `cluster/cluster-context/madagascar.json` — autoritatea pentru roluri, topologie și IP-uri de serviciu. Pentru nodurile Proxmox, DNS-ul de serviciu poate folosi interfața `thunderbridge` (`192.168.10.x`) chiar dacă management/WAN este `192.168.2.x`. |
| 42 | 42 |
3. `var/host-manager.sqlite` — registry-ul operațional aprobat, editat prin Madagascar Local Authority. |
| 43 |
-4. `config/local-hosts.tsv` — manifestul DNS local publicat pe jumper și as01. Acesta trebuie să fie derivat sau validat din DHCP plus topologia clusterului, nu folosit ca sursă primară de alocare IP. |
|
| 43 |
+4. `config/local-hosts.tsv` — manifestul DNS local publicat pe jumper și as01. Acesta este un export al registry-ului SQLite și nu sursa primară pentru sync; sincronizarea citește manifestul runtime de pe jumper. |
|
| 44 | 44 |
5. `hosts-local.yaml` — inventar SSH: aliasuri, utilizatori, entrypoint-uri și căi de acces. IP-urile de aici sunt utile pentru audit, dar pot fi stale dacă DHCP spune altceva. |
| 45 | 45 |
6. mDNS (`*.local`) — sursă observată de descoperire și validare. Confirmă prezența unui host sau propune aliasuri, dar nu creează automat intrări `madagascar.xdev.ro`. |
| 46 | 46 |
7. DNS public — folosit doar pentru acces extern. Local, numele interne trebuie shadow-uite exact sau lăsate nerezolvate; wildcard-ul public nu este autoritate pentru LAN. |
@@ -18,10 +18,10 @@ The runtime instance lives on jumper and remains the local source for operationa |
||
| 18 | 18 |
|
| 19 | 19 |
- `var/host-manager.sqlite` - runtime source of truth for host registry and Work Orders |
| 20 | 20 |
- `config/hosts.yaml` - seed/snapshot export for host registry compatibility |
| 21 |
-- `config/local-hosts.tsv` - DNS manifest exported for local resolvers |
|
| 21 |
+- `config/local-hosts.tsv` - DNS manifest export derived from the runtime SQLite registry |
|
| 22 | 22 |
- `config/work-orders.yaml` - seed/snapshot export for confirmable operational changes |
| 23 | 23 |
- `scripts/host_manager.pl` - Perl-only web app |
| 24 |
-- `scripts/sync_local_hosts.sh` - local DNS sync to jumper and as01 |
|
| 24 |
+- `scripts/sync_local_hosts.sh` - local DNS sync to jumper and as01, sourced from the runtime DB on jumper |
|
| 25 | 25 |
- `scripts/ca_manager.sh` - local OpenSSL CA helper for host certificates |
| 26 | 26 |
|
| 27 | 27 |
The public `xdev.ro` zone is maintained in the separate DNS public-zone repository. |
@@ -86,7 +86,7 @@ scripts/deploy_to_jumper.sh --include-config |
||
| 86 | 86 |
|
| 87 | 87 |
The default internal domain is `madagascar.xdev.ro`. Short aliases are derived automatically from FQDNs, so `autonas01.madagascar.xdev.ro` also publishes `autonas01` without declaring it separately. |
| 88 | 88 |
|
| 89 |
-Name removals with operational impact go through a Work Order. A WO records intent first; the operational checklist must be completed before confirmation can update the SQLite registry, mark the WO as confirmed, and regenerate `local-hosts.tsv`. Resolver sync remains an explicit operator step. |
|
| 89 |
+Name removals with operational impact go through a Work Order. A WO records intent first; the operational checklist must be completed before confirmation can update the SQLite registry, mark the WO as confirmed, and regenerate `local-hosts.tsv`. Resolver sync remains an explicit operator step and reads the runtime manifest from the jumper database. |
|
| 90 | 90 |
|
| 91 | 91 |
The local host CA stores private material outside git under `var/ca`. Initialize it on jumper with: |
| 92 | 92 |
|
@@ -1,21 +1,34 @@ |
||
| 1 | 1 |
# Local DNS manifest for the madagascar network. |
| 2 |
-# Generated by scripts/host_manager.pl from config/hosts.yaml. |
|
| 2 |
+# Generated by scripts/host_manager.pl from the runtime SQLite registry. |
|
| 3 | 3 |
# |
| 4 | 4 |
# Format: |
| 5 | 5 |
# ip<TAB>name [aliases...] |
| 6 |
+# CNAME<TAB>alias<TAB>target |
|
| 6 | 7 |
# |
| 7 | 8 |
# Priority rule: |
| 8 | 9 |
# - DHCP lease/reservation on 192.168.2.1 is canonical for LAN IP allocation. |
| 9 | 10 |
# - madagascar.json is canonical for cluster roles and service interfaces. |
| 10 | 11 |
# - This file publishes approved local DNS records derived from those sources. |
| 11 |
-192.168.2.96 andrafiabe.madagascar.xdev.ro pbs.andrafiabe.madagascar.xdev.ro andrafiabe pbs.andrafiabe |
|
| 12 |
-192.168.2.95 anjothibe.madagascar.xdev.ro pbs.anjothibe.madagascar.xdev.ro anjothibe pbs.anjothibe |
|
| 12 |
+192.168.2.96 andrafiabe.madagascar.xdev.ro andrafiabe |
|
| 13 |
+CNAME pbs.andrafiabe.madagascar.xdev.ro andrafiabe.madagascar.xdev.ro |
|
| 14 |
+CNAME pbs.andrafiabe andrafiabe.madagascar.xdev.ro |
|
| 15 |
+192.168.2.95 anjothibe.madagascar.xdev.ro anjothibe |
|
| 16 |
+CNAME pbs.anjothibe.madagascar.xdev.ro anjothibe.madagascar.xdev.ro |
|
| 17 |
+CNAME pbs.anjothibe anjothibe.madagascar.xdev.ro |
|
| 13 | 18 |
192.168.10.21 autonas01.madagascar.xdev.ro autonas01 |
| 14 | 19 |
192.168.10.22 autonas02.madagascar.xdev.ro autonas02 |
| 15 |
-192.168.10.91 baobab.madagascar.xdev.ro pmx.baobab.madagascar.xdev.ro baobab pmx.baobab |
|
| 16 |
-192.168.10.92 ebony.madagascar.xdev.ro pmx.ebony.madagascar.xdev.ro ebony pmx.ebony |
|
| 17 |
-192.168.2.100 jumper.madagascar.xdev.ro hosts.madagascar.xdev.ro jumper hosts |
|
| 20 |
+192.168.10.91 baobab.madagascar.xdev.ro baobab |
|
| 21 |
+CNAME pmx.baobab.madagascar.xdev.ro baobab.madagascar.xdev.ro |
|
| 22 |
+CNAME pmx.baobab baobab.madagascar.xdev.ro |
|
| 23 |
+192.168.10.92 ebony.madagascar.xdev.ro ebony |
|
| 24 |
+CNAME pmx.ebony.madagascar.xdev.ro ebony.madagascar.xdev.ro |
|
| 25 |
+CNAME pmx.ebony ebony.madagascar.xdev.ro |
|
| 26 |
+192.168.2.100 jumper.madagascar.xdev.ro jumper |
|
| 27 |
+CNAME hosts.madagascar.xdev.ro jumper.madagascar.xdev.ro |
|
| 28 |
+CNAME hosts jumper.madagascar.xdev.ro |
|
| 18 | 29 |
192.168.2.102 mazeri.madagascar.xdev.ro mazeri |
| 19 |
-192.168.10.93 tapia.madagascar.xdev.ro pmx.tapia.madagascar.xdev.ro tapia pmx.tapia |
|
| 30 |
+192.168.10.93 tapia.madagascar.xdev.ro tapia |
|
| 31 |
+CNAME pmx.tapia.madagascar.xdev.ro tapia.madagascar.xdev.ro |
|
| 32 |
+CNAME pmx.tapia tapia.madagascar.xdev.ro |
|
| 20 | 33 |
192.168.2.103 toltec.madagascar.xdev.ro toltec |
| 21 | 34 |
192.168.2.107 zabbix.madagascar.xdev.ro zabbix |
@@ -101,4 +101,4 @@ Nu se adaugă wildcard local. Doar acest nume exact trebuie publicat. |
||
| 101 | 101 |
|
| 102 | 102 |
## mDNS discovery |
| 103 | 103 |
|
| 104 |
-`host-manager-mdns` este un listener separat care observă mDNS și scrie direct în tabelul SQLite `mdns_observations`. Listenerul nu modifică host registry-ul, `config/hosts.yaml` sau `config/local-hosts.tsv`. |
|
| 104 |
+`host-manager-mdns` este un listener separat care observă mDNS și scrie direct în tabelul SQLite `mdns_observations`. Listenerul nu modifică host registry-ul, `config/hosts.yaml` sau `config/local-hosts.tsv`. Sync-ul resolverului citește manifestul runtime din SQLite, nu din exportul static. |
|
@@ -26,6 +26,7 @@ my %opt = ( |
||
| 26 | 26 |
local_hosts_tsv => $ENV{HOST_MANAGER_LOCAL_HOSTS_TSV} || "$project_dir/config/local-hosts.tsv",
|
| 27 | 27 |
work_orders => $ENV{HOST_MANAGER_WORK_ORDERS} || "$project_dir/config/work-orders.yaml",
|
| 28 | 28 |
); |
| 29 |
+my $print_local_hosts_tsv = 0; |
|
| 29 | 30 |
|
| 30 | 31 |
while (@ARGV) {
|
| 31 | 32 |
my $arg = shift @ARGV; |
@@ -41,6 +42,8 @@ while (@ARGV) {
|
||
| 41 | 42 |
$opt{local_hosts_tsv} = shift @ARGV;
|
| 42 | 43 |
} elsif ($arg eq '--work-orders') {
|
| 43 | 44 |
$opt{work_orders} = shift @ARGV;
|
| 45 |
+ } elsif ($arg eq '--print-local-hosts-tsv') {
|
|
| 46 |
+ $print_local_hosts_tsv = 1; |
|
| 44 | 47 |
} elsif ($arg eq '--help' || $arg eq '-h') {
|
| 45 | 48 |
usage(); |
| 46 | 49 |
exit 0; |
@@ -49,6 +52,11 @@ while (@ARGV) {
|
||
| 49 | 52 |
} |
| 50 | 53 |
} |
| 51 | 54 |
|
| 55 |
+if ($print_local_hosts_tsv) {
|
|
| 56 |
+ print render_local_hosts_tsv(load_registry()); |
|
| 57 |
+ exit 0; |
|
| 58 |
+} |
|
| 59 |
+ |
|
| 52 | 60 |
my $session_secret = $ENV{HOST_MANAGER_SESSION_SECRET} || random_hex(32);
|
| 53 | 61 |
my %sessions; |
| 54 | 62 |
|
@@ -87,6 +95,7 @@ Environment: |
||
| 87 | 95 |
HOST_MANAGER_DATA Defaults to config/hosts.yaml. |
| 88 | 96 |
HOST_MANAGER_LOCAL_HOSTS_TSV Defaults to config/local-hosts.tsv. |
| 89 | 97 |
HOST_MANAGER_WORK_ORDERS Defaults to config/work-orders.yaml. |
| 98 |
+ --print-local-hosts-tsv Print the runtime DNS manifest and exit. |
|
| 90 | 99 |
|
| 91 | 100 |
SQLite is the runtime source of truth. YAML files seed a new database and remain |
| 92 | 101 |
download/export compatibility artifacts. The nginx vhost keeps registry, CA, |
@@ -7,24 +7,27 @@ set -euo pipefail |
||
| 7 | 7 |
|
| 8 | 8 |
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 9 | 9 |
PROJECT_DIR="$(dirname "$SCRIPT_DIR")" |
| 10 |
-CONFIG_FILE="$PROJECT_DIR/config/local-hosts.tsv" |
|
| 10 |
+HOST_MANAGER="$PROJECT_DIR/scripts/host_manager.pl" |
|
| 11 | 11 |
JUMPER_HOST="jumper.madagascar.xdev.ro" |
| 12 | 12 |
AS01="admin@192.168.2.2" |
| 13 | 13 |
APPLY=false |
| 14 | 14 |
VERIFY=false |
| 15 | 15 |
TARGET="all" |
| 16 |
+SOURCE="jumper" |
|
| 16 | 17 |
NEGATIVE_NAME="nohost.madagascar.xdev.ro" |
| 17 | 18 |
|
| 18 | 19 |
usage() {
|
| 19 | 20 |
cat << EOF |
| 20 |
-Usage: $0 [--apply] [--verify] [--target all|jumper|as01] [-c file] |
|
| 21 |
+Usage: $0 [--apply] [--verify] [--target all|jumper|as01] [--source jumper|local] |
|
| 21 | 22 |
|
| 22 | 23 |
Default mode is dry-run. Use --apply to change remote resolvers. |
| 24 |
+The default manifest source is the runtime SQLite database on jumper. |
|
| 23 | 25 |
|
| 24 | 26 |
Examples: |
| 25 | 27 |
$0 |
| 26 | 28 |
$0 --apply --verify |
| 27 | 29 |
$0 --target as01 --apply |
| 30 |
+ $0 --source local |
|
| 28 | 31 |
EOF |
| 29 | 32 |
} |
| 30 | 33 |
|
@@ -42,7 +45,7 @@ while [[ $# -gt 0 ]]; do |
||
| 42 | 45 |
--apply) APPLY=true; shift ;; |
| 43 | 46 |
--verify) VERIFY=true; shift ;; |
| 44 | 47 |
--target) TARGET="${2:-}"; shift 2 ;;
|
| 45 |
- -c|--config) CONFIG_FILE="${2:-}"; shift 2 ;;
|
|
| 48 |
+ --source) SOURCE="${2:-}"; shift 2 ;;
|
|
| 46 | 49 |
-h|--help) usage; exit 0 ;; |
| 47 | 50 |
*) die "Unknown option: $1" ;; |
| 48 | 51 |
esac |
@@ -53,16 +56,20 @@ case "$TARGET" in |
||
| 53 | 56 |
*) die "Invalid target: $TARGET" ;; |
| 54 | 57 |
esac |
| 55 | 58 |
|
| 59 |
+case "$SOURCE" in |
|
| 60 |
+ jumper|local) ;; |
|
| 61 |
+ *) die "Invalid source: $SOURCE" ;; |
|
| 62 |
+esac |
|
| 63 |
+ |
|
| 56 | 64 |
if [[ "$TARGET" == "is-vpn-gw" ]]; then |
| 57 | 65 |
log "Target is-vpn-gw is deprecated; use jumper" |
| 58 | 66 |
TARGET="jumper" |
| 59 | 67 |
fi |
| 60 | 68 |
|
| 61 |
-[[ -f "$CONFIG_FILE" ]] || die "Missing config file: $CONFIG_FILE" |
|
| 62 |
- |
|
| 63 | 69 |
WORK_DIR="$(mktemp -d)" |
| 64 | 70 |
trap 'rm -rf "$WORK_DIR"' EXIT |
| 65 | 71 |
|
| 72 |
+MANIFEST_FILE="$WORK_DIR/local-hosts.tsv" |
|
| 66 | 73 |
HOSTS_ROWS="$WORK_DIR/hosts.rows" |
| 67 | 74 |
CLOAK_ROWS="$WORK_DIR/cloak.rows" |
| 68 | 75 |
NAMES_FILE="$WORK_DIR/names.txt" |
@@ -93,6 +100,23 @@ run_jumper_payload() {
|
||
| 93 | 100 |
fi |
| 94 | 101 |
} |
| 95 | 102 |
|
| 103 |
+fetch_manifest() {
|
|
| 104 |
+ case "$SOURCE" in |
|
| 105 |
+ local) |
|
| 106 |
+ perl "$HOST_MANAGER" --print-local-hosts-tsv |
|
| 107 |
+ ;; |
|
| 108 |
+ jumper) |
|
| 109 |
+ if is_local_jumper; then |
|
| 110 |
+ perl "$HOST_MANAGER" --print-local-hosts-tsv |
|
| 111 |
+ else |
|
| 112 |
+ ssh "$JUMPER_HOST" "perl /usr/local/xdev-host-manager/scripts/host_manager.pl --print-local-hosts-tsv" |
|
| 113 |
+ fi |
|
| 114 |
+ ;; |
|
| 115 |
+ esac > "$MANIFEST_FILE" |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+fetch_manifest |
|
| 119 |
+ |
|
| 96 | 120 |
while IFS= read -r line || [[ -n "$line" ]]; do |
| 97 | 121 |
[[ -z "${line//[[:space:]]/}" ]] && continue
|
| 98 | 122 |
[[ "$line" =~ ^[[:space:]]*# ]] && continue |
@@ -145,7 +169,7 @@ while IFS= read -r line || [[ -n "$line" ]]; do |
||
| 145 | 169 |
printf '/ip dns static add name="%s" type=A address=%s comment="xdev-local managed"\n' "$ros_name" "$ros_ip" |
| 146 | 170 |
} >> "$MIKROTIK_RSC" |
| 147 | 171 |
done |
| 148 |
-done < "$CONFIG_FILE" |
|
| 172 |
+done < "$MANIFEST_FILE" |
|
| 149 | 173 |
|
| 150 | 174 |
sort -u "$NAMES_FILE" -o "$NAMES_FILE" |
| 151 | 175 |
printf '/ip dns cache flush\n' >> "$MIKROTIK_RSC" |