Showing 6 changed files with 84 additions and 33 deletions
+13 -0
.doc/host-manager.md
@@ -90,6 +90,19 @@ Secretul nu se comite în repo. Dacă avem nevoie de integrare cu un manager de
90 90
 ./scripts/sync_local_hosts.sh --apply --verify
91 91
 ```
92 92
 
93
+## Convenții de nume
94
+
95
+`madagascar.xdev.ro` este domeniul implicit al rețelei interne. În `config/hosts.yaml` se declară doar numele canonice/FQDN-urile necesare.
96
+
97
+Pentru orice nume `*.madagascar.xdev.ro`, aplicația derivă automat aliasul scurt prin eliminarea sufixului `.madagascar.xdev.ro`.
98
+
99
+Exemple:
100
+
101
+- `autonas01.madagascar.xdev.ro` produce automat aliasul `autonas01`
102
+- `pmx.baobab.madagascar.xdev.ro` produce automat aliasul `pmx.baobab`
103
+
104
+Aliasurile derivate nu se declară separat în `hosts.yaml`. Ele apar în API, monitoring export și `local-hosts.tsv` ca nume efective.
105
+
93 106
 ## Git și managementul cheilor
94 107
 
95 108
 Varianta obligatorie pentru servicii automate este să citească `config/hosts.yaml` din git, nu să depindă de HTTP neautentificat. Serviciile care sincronizează DNS, monitorizare sau inventare primesc chei dedicate, cu acces minim.
+4 -1
.doc/local-hosts.md
@@ -24,9 +24,12 @@ Implementarea versionată este:
24 24
 
25 25
 | Fișier | Rol |
26 26
 |--------|-----|
27
-| `config/local-hosts.tsv` | sursa unică pentru IP-uri, hostname-uri și aliasuri locale |
27
+| `config/hosts.yaml` | registrul versionat pentru hosturi și FQDN-uri canonice |
28
+| `config/local-hosts.tsv` | manifest DNS generat, cu aliasuri scurte derivate |
28 29
 | `scripts/sync_local_hosts.sh` | generează și sincronizează `/etc/hosts`, `cloaking-rules.txt` și `/ip dns static` |
29 30
 
31
+`madagascar.xdev.ro` este domeniul implicit. Pentru orice nume `*.madagascar.xdev.ro`, aliasul scurt este derivat automat. De exemplu, `autonas01.madagascar.xdev.ro` publică și `autonas01`, iar `pmx.baobab.madagascar.xdev.ro` publică și `pmx.baobab`. Aliasurile derivate nu se declară separat în `config/hosts.yaml`.
32
+
30 33
 ## Ierarhia surselor
31 34
 
32 35
 Când inventarele se contrazic, ordinea de încredere este:
+2 -0
README.md
@@ -22,6 +22,8 @@ Secrets live outside git in `/etc/xdev/host-manager.env`.
22 22
 
23 23
 The web UI is OTP-protected for all registry data, downloads, exports, and writes. Automation should consume this repository through git with dedicated read-only keys, not through unauthenticated HTTP.
24 24
 
25
+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.
26
+
25 27
 The local host CA stores private material outside git under `var/ca`. Initialize it on jumper with:
26 28
 
27 29
 ```bash
+0 -16
config/hosts.yaml
@@ -14,8 +14,6 @@ hosts:
14 14
     names:
15 15
       - "baobab.madagascar.xdev.ro"
16 16
       - "pmx.baobab.madagascar.xdev.ro"
17
-      - "baobab"
18
-      - "pmx.baobab"
19 17
     roles:
20 18
       - "proxmox"
21 19
       - "pmx"
@@ -31,8 +29,6 @@ hosts:
31 29
     names:
32 30
       - "ebony.madagascar.xdev.ro"
33 31
       - "pmx.ebony.madagascar.xdev.ro"
34
-      - "ebony"
35
-      - "pmx.ebony"
36 32
     roles:
37 33
       - "proxmox"
38 34
       - "pmx"
@@ -48,8 +44,6 @@ hosts:
48 44
     names:
49 45
       - "tapia.madagascar.xdev.ro"
50 46
       - "pmx.tapia.madagascar.xdev.ro"
51
-      - "tapia"
52
-      - "pmx.tapia"
53 47
     roles:
54 48
       - "proxmox"
55 49
       - "pmx"
@@ -64,7 +58,6 @@ hosts:
64 58
     dns_ip: "192.168.10.21"
65 59
     names:
66 60
       - "autonas01.madagascar.xdev.ro"
67
-      - "autonas01"
68 61
     roles:
69 62
       - "storage"
70 63
     sources:
@@ -77,7 +70,6 @@ hosts:
77 70
     dns_ip: "192.168.10.22"
78 71
     names:
79 72
       - "autonas02.madagascar.xdev.ro"
80
-      - "autonas02"
81 73
     roles:
82 74
       - "storage"
83 75
     sources:
@@ -91,8 +83,6 @@ hosts:
91 83
     names:
92 84
       - "anjothibe.madagascar.xdev.ro"
93 85
       - "pbs.anjothibe.madagascar.xdev.ro"
94
-      - "anjothibe"
95
-      - "pbs.anjothibe"
96 86
     roles:
97 87
       - "pbs"
98 88
       - "backup"
@@ -108,8 +98,6 @@ hosts:
108 98
     names:
109 99
       - "andrafiabe.madagascar.xdev.ro"
110 100
       - "pbs.andrafiabe.madagascar.xdev.ro"
111
-      - "andrafiabe"
112
-      - "pbs.andrafiabe"
113 101
     roles:
114 102
       - "pbs"
115 103
       - "backup"
@@ -124,7 +112,6 @@ hosts:
124 112
     dns_ip: "192.168.2.102"
125 113
     names:
126 114
       - "mazeri.madagascar.xdev.ro"
127
-      - "mazeri"
128 115
     roles:
129 116
       - "service"
130 117
     sources:
@@ -138,7 +125,6 @@ hosts:
138 125
     dns_ip: "192.168.2.103"
139 126
     names:
140 127
       - "toltec.madagascar.xdev.ro"
141
-      - "toltec"
142 128
     roles:
143 129
       - "service"
144 130
     sources:
@@ -152,7 +138,6 @@ hosts:
152 138
     dns_ip: "192.168.2.107"
153 139
     names:
154 140
       - "zabbix.madagascar.xdev.ro"
155
-      - "zabbix"
156 141
     roles:
157 142
       - "monitoring"
158 143
     sources:
@@ -167,7 +152,6 @@ hosts:
167 152
     names:
168 153
       - "jumper.madagascar.xdev.ro"
169 154
       - "hosts.madagascar.xdev.ro"
170
-      - "jumper"
171 155
     roles:
172 156
       - "entrypoint"
173 157
       - "dns"
+7 -10
config/local-hosts.tsv
@@ -1,24 +1,21 @@
1 1
 # Local DNS manifest for the madagascar network.
2
+# Generated by scripts/host_manager.pl from config/hosts.yaml.
2 3
 #
3 4
 # Format:
4 5
 # hosts_ip<TAB>dns_ip<TAB>name [aliases...]
5 6
 #
6
-# hosts_ip is written to /etc/hosts on is-vpn-gw.
7
-# dns_ip is written to dnscrypt-proxy cloaking rules and MikroTik static DNS.
8
-# Use different values only for host-local exceptions such as jumper.
9
-#
10 7
 # Priority rule:
11 8
 # - DHCP lease/reservation on 192.168.2.1 is canonical for LAN IP allocation.
12 9
 # - madagascar.json is canonical for cluster roles and service interfaces.
13 10
 # - This file publishes approved local DNS records derived from those sources.
14
-192.168.10.91	192.168.10.91	baobab.madagascar.xdev.ro pmx.baobab.madagascar.xdev.ro baobab pmx.baobab
15
-192.168.10.92	192.168.10.92	ebony.madagascar.xdev.ro pmx.ebony.madagascar.xdev.ro ebony pmx.ebony
16
-192.168.10.93	192.168.10.93	tapia.madagascar.xdev.ro pmx.tapia.madagascar.xdev.ro tapia pmx.tapia
11
+192.168.2.96	192.168.2.96	andrafiabe.madagascar.xdev.ro pbs.andrafiabe.madagascar.xdev.ro andrafiabe pbs.andrafiabe
12
+192.168.2.95	192.168.2.95	anjothibe.madagascar.xdev.ro pbs.anjothibe.madagascar.xdev.ro anjothibe pbs.anjothibe
17 13
 192.168.10.21	192.168.10.21	autonas01.madagascar.xdev.ro autonas01
18 14
 192.168.10.22	192.168.10.22	autonas02.madagascar.xdev.ro autonas02
19
-192.168.2.95	192.168.2.95	anjothibe.madagascar.xdev.ro pbs.anjothibe.madagascar.xdev.ro anjothibe pbs.anjothibe
20
-192.168.2.96	192.168.2.96	andrafiabe.madagascar.xdev.ro pbs.andrafiabe.madagascar.xdev.ro andrafiabe pbs.andrafiabe
15
+192.168.10.91	192.168.10.91	baobab.madagascar.xdev.ro pmx.baobab.madagascar.xdev.ro baobab pmx.baobab
16
+192.168.10.92	192.168.10.92	ebony.madagascar.xdev.ro pmx.ebony.madagascar.xdev.ro ebony pmx.ebony
17
+127.0.0.1	192.168.2.100	jumper.madagascar.xdev.ro hosts.madagascar.xdev.ro jumper hosts
21 18
 192.168.2.102	192.168.2.102	mazeri.madagascar.xdev.ro mazeri
19
+192.168.10.93	192.168.10.93	tapia.madagascar.xdev.ro pmx.tapia.madagascar.xdev.ro tapia pmx.tapia
22 20
 192.168.2.103	192.168.2.103	toltec.madagascar.xdev.ro toltec
23 21
 192.168.2.107	192.168.2.107	zabbix.madagascar.xdev.ro zabbix
24
-127.0.0.1	192.168.2.100	jumper.madagascar.xdev.ro hosts.madagascar.xdev.ro jumper
+58 -6
scripts/host_manager.pl
@@ -192,11 +192,12 @@ sub save_registry {
192 192
 sub registry_payload {
193 193
     my ($registry) = @_;
194 194
     my $problems = analyze_hosts($registry->{hosts});
195
+    my @hosts = map { host_payload($_) } @{ $registry->{hosts} };
195 196
     return {
196 197
         version => $registry->{version},
197 198
         updated_at => $registry->{updated_at},
198 199
         policy => $registry->{policy},
199
-        hosts => $registry->{hosts},
200
+        hosts => \@hosts,
200 201
         problems => $problems,
201 202
         counts => {
202 203
             hosts => scalar @{ $registry->{hosts} },
@@ -214,7 +215,7 @@ sub upsert_host {
214 215
     my $dns_ip = clean_scalar($payload->{dns_ip} || '');
215 216
     return send_json($client, 400, { error => 'missing_ip' }) unless $hosts_ip && $dns_ip;
216 217
 
217
-    my @names = clean_list($payload->{names});
218
+    my @names = remove_derived_names(clean_list($payload->{names}));
218 219
     return send_json($client, 400, { error => 'missing_names' }) unless @names;
219 220
 
220 221
     my $registry = load_registry();
@@ -271,6 +272,11 @@ sub analyze_hosts {
271 272
         for my $name (@{ $host->{names} || [] }) {
272 273
             push @problems, problem($host, 'duplicate-name', "Duplicate name $name") if $names{$name}++;
273 274
         }
275
+        my %declared = map { $_ => 1 } @{ $host->{names} || [] };
276
+        for my $derived (derived_names($host)) {
277
+            push @problems, problem($host, 'redundant-derived-name', "Name $derived is derived from madagascar.xdev.ro")
278
+                if $declared{$derived};
279
+        }
274 280
         if (($host->{hosts_ip} || '') ne ($host->{dns_ip} || '') && ($host->{hosts_ip} || '') ne '127.0.0.1') {
275 281
             push @problems, problem($host, 'split-ip', 'hosts_ip differs from dns_ip; check that this is intentional');
276 282
         }
@@ -278,6 +284,48 @@ sub analyze_hosts {
278 284
     return \@problems;
279 285
 }
280 286
 
287
+sub host_payload {
288
+    my ($host) = @_;
289
+    my %copy = %$host;
290
+    $copy{names} = [ effective_names($host) ];
291
+    $copy{declared_names} = [ @{ $host->{names} || [] } ];
292
+    $copy{derived_names} = [ derived_names($host) ];
293
+    return \%copy;
294
+}
295
+
296
+sub effective_names {
297
+    my ($host) = @_;
298
+    my @names = @{ $host->{names} || [] };
299
+    push @names, derived_names($host);
300
+    return unique_preserve(@names);
301
+}
302
+
303
+sub derived_names {
304
+    my ($host) = @_;
305
+    my @derived;
306
+    for my $name (@{ $host->{names} || [] }) {
307
+        next unless $name =~ /^(.+)\.madagascar\.xdev\.ro$/;
308
+        push @derived, $1 if length $1;
309
+    }
310
+    return unique_preserve(@derived);
311
+}
312
+
313
+sub remove_derived_names {
314
+    my @names = @_;
315
+    my %derived;
316
+    for my $name (@names) {
317
+        next unless $name =~ /^(.+)\.madagascar\.xdev\.ro$/;
318
+        $derived{$1} = 1;
319
+    }
320
+    return grep { !$derived{$_} } @names;
321
+}
322
+
323
+sub unique_preserve {
324
+    my @values = @_;
325
+    my %seen;
326
+    return grep { !$seen{$_}++ } @values;
327
+}
328
+
281 329
 sub problem {
282 330
     my ($host, $code, $message) = @_;
283 331
     return { host_id => $host->{id}, code => $code, message => $message };
@@ -297,8 +345,9 @@ sub render_local_hosts_tsv {
297 345
     $out .= "# - This file publishes approved local DNS records derived from those sources.\n";
298 346
     for my $host (sort { $a->{id} cmp $b->{id} } @{ $registry->{hosts} }) {
299 347
         next unless ($host->{status} || 'active') eq 'active';
300
-        next unless @{ $host->{names} || [] };
301
-        $out .= join("\t", $host->{hosts_ip}, $host->{dns_ip}, join(' ', @{ $host->{names} })) . "\n";
348
+        my @names = effective_names($host);
349
+        next unless @names;
350
+        $out .= join("\t", $host->{hosts_ip}, $host->{dns_ip}, join(' ', @names)) . "\n";
302 351
     }
303 352
     return $out;
304 353
 }
@@ -309,11 +358,14 @@ sub render_monitoring {
309 358
     for my $host (sort { $a->{id} cmp $b->{id} } @{ $registry->{hosts} }) {
310 359
         next unless ($host->{status} || 'active') eq 'active';
311 360
         next if ($host->{monitoring} || 'pending') eq 'disabled';
361
+        my @names = effective_names($host);
312 362
         push @hosts, {
313 363
             id => $host->{id},
314
-            primary_name => $host->{names}[0],
364
+            primary_name => $names[0],
315 365
             address => $host->{dns_ip},
316
-            aliases => [ @{ $host->{names} || [] } ],
366
+            aliases => \@names,
367
+            declared_names => [ @{ $host->{names} || [] } ],
368
+            derived_names => [ derived_names($host) ],
317 369
             roles => [ @{ $host->{roles} || [] } ],
318 370
             monitoring => $host->{monitoring} || 'pending',
319 371
             notes => $host->{notes} || '',