pmcf 1.5.1 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,18 +5,16 @@ import { join } from "node:path";
5
5
  import { writeLines, sectionLines } from "../src/model.mjs";
6
6
  import { prepare } from "../src/cmd.mjs";
7
7
 
8
- const { world, args } = prepare();
8
+ const { world, args, options } = prepare();
9
9
 
10
10
  const hostName = args[0];
11
11
 
12
12
  const host = await world.host(hostName);
13
13
 
14
- const targetDir = args[1] || `pkg/host-${host.hostName}`;
15
-
16
- await generateNetworkDefs(host, targetDir);
17
- await generateMachineInfo(host, targetDir);
18
- await copySshKeys(host, targetDir);
19
- await generateKnownHosts(world.hosts(), join(targetDir, "root", ".ssh"));
14
+ await generateNetworkDefs(host, options.output);
15
+ await generateMachineInfo(host, options.output);
16
+ await copySshKeys(host, options.output);
17
+ await generateKnownHosts(world.hosts(), join(options.output, "root", ".ssh"));
20
18
 
21
19
  console.log("provides", "host", ...host.provides);
22
20
  console.log("depends", `location-${host.location.name}`, ...host.depends);
@@ -5,12 +5,11 @@ import { join } from "node:path";
5
5
  import { writeLines, sectionLines } from "../src/model.mjs";
6
6
  import { prepare } from "../src/cmd.mjs";
7
7
 
8
- const { world, args } = prepare();
8
+ const { world, args, options } = prepare();
9
9
 
10
10
  const location = await world.location(args[0] || "SW");
11
- const targetDir = args[1];
12
11
 
13
- await generateLocationDefs(location, targetDir);
12
+ await generateLocationDefs(location, options.output);
14
13
 
15
14
  console.log(
16
15
  "provides",
@@ -5,10 +5,9 @@ import { createHmac } from "node:crypto";
5
5
  import { writeLines } from "../src/model.mjs";
6
6
  import { prepare } from "../src/cmd.mjs";
7
7
 
8
- const { world, args } = prepare();
8
+ const { world, args, options } = prepare();
9
9
 
10
10
  const location = await world.location(args[0] || "SW");
11
- const targetDir = args[1] || `pkg/mf-named-${location.name}`;
12
11
  const ttl = location.dnsRecordTTL;
13
12
  const updates = [
14
13
  Math.ceil(Date.now() / 1000),
@@ -20,7 +19,7 @@ const updates = [
20
19
 
21
20
  const NAME_LEN = 35;
22
21
 
23
- await generateNamedDefs(location, targetDir);
22
+ await generateNamedDefs(location, options.output);
24
23
 
25
24
  console.log("depends", "mf-named");
26
25
  console.log("replaces", "mf-named-zones");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcf",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/model.mjs CHANGED
@@ -69,7 +69,7 @@ export class Base {
69
69
  return this.owner.host;
70
70
  }
71
71
 
72
- network(name) {
72
+ async network(name) {
73
73
  return this.owner.network(name);
74
74
  }
75
75
 
@@ -113,22 +113,24 @@ export class Base {
113
113
  }
114
114
  }
115
115
 
116
- export class World {
116
+ export class Owner extends Base {
117
+ addHost(host) {}
118
+ addNetwork(network) {}
119
+ async network(name) {}
120
+ }
121
+
122
+ export class World extends Owner {
117
123
  static get types() {
118
124
  return _types;
119
125
  }
120
126
 
121
- directory;
122
127
  #byName = new Map();
123
128
 
124
129
  constructor(directory) {
130
+ super(undefined, { name: "" });
125
131
  this.directory = directory;
126
132
  }
127
133
 
128
- get name() {
129
- return "";
130
- }
131
-
132
134
  get world() {
133
135
  return this;
134
136
  }
@@ -161,7 +163,7 @@ export class World {
161
163
 
162
164
  type = await type.prepareData(this, data);
163
165
  object = new type(owner, data);
164
- this.#byName.set(data.name, object);
166
+ this.#byName.set(object.name, object);
165
167
  }
166
168
 
167
169
  return object;
@@ -216,9 +218,6 @@ export class World {
216
218
  return this._loadType(name, Host);
217
219
  }
218
220
 
219
- addHost(host) {}
220
- network(name) {}
221
-
222
221
  async *subnets() {
223
222
  for await (const location of this.locations()) {
224
223
  yield* location.subnets();
@@ -234,6 +233,225 @@ export class World {
234
233
  }
235
234
  }
236
235
 
236
+ export class Location extends Owner {
237
+ domain;
238
+ dns;
239
+ #administratorEmail;
240
+ #hosts = new Map();
241
+ #networks = new Map();
242
+ #subnets = new Map();
243
+
244
+ static get typeName() {
245
+ return "location";
246
+ }
247
+
248
+ constructor(owner, data) {
249
+ super(owner, data);
250
+
251
+ const networks = data.networks;
252
+ delete data.networks;
253
+ Object.assign(this, data);
254
+
255
+ if (networks) {
256
+ for (const [name, network] of Object.entries(networks)) {
257
+ network.name = name;
258
+ this.addNetwork(network);
259
+ }
260
+
261
+ for (const network of this.#networks.values()) {
262
+ if (network.bridges) {
263
+ network.bridges = new Set(
264
+ network.bridges.map(b => {
265
+ const n = this.network(b);
266
+ if (!n) {
267
+ console.error(`No network named ${b}`);
268
+ }
269
+ return n;
270
+ })
271
+ );
272
+ }
273
+ }
274
+ }
275
+ }
276
+
277
+ async *hosts() {
278
+ for await (const host of this.owner.hosts()) {
279
+ if (host.location === this) {
280
+ yield host;
281
+ }
282
+ }
283
+ }
284
+
285
+ async service(filter) {
286
+ let best;
287
+ for await (const service of this.services(filter)) {
288
+ if (!best || service.priority < best.priority) {
289
+ best = service;
290
+ }
291
+ }
292
+
293
+ return best;
294
+ }
295
+
296
+ async *services(filter) {
297
+ for await (const host of this.hosts()) {
298
+ for (const service of Object.values(host.services)) {
299
+ if (
300
+ !filter ||
301
+ filter.type === "*" ||
302
+ filter.type === service.type ||
303
+ filter.name === service.name
304
+ ) {
305
+ yield service;
306
+ }
307
+ }
308
+ }
309
+ }
310
+
311
+ async *networkAddresses() {
312
+ for await (const host of this.hosts()) {
313
+ for (const networkAddresses of host.networkAddresses()) {
314
+ yield networkAddresses;
315
+ }
316
+ }
317
+ }
318
+
319
+ async network(name) {
320
+ return this.#networks.get(name);
321
+ }
322
+
323
+ async *networks() {
324
+ for (const network of this.#networks.values()) {
325
+ yield network;
326
+ }
327
+ }
328
+
329
+ async *subnets() {
330
+ for (const subnet of this.#subnets.values()) {
331
+ yield subnet;
332
+ }
333
+ }
334
+
335
+ addNetwork(data) {
336
+ if (!data?.name) {
337
+ return undefined;
338
+ }
339
+
340
+ let network = this.#networks.get(data.name);
341
+ if (network) {
342
+ return network;
343
+ }
344
+
345
+ if (data instanceof Network) {
346
+ this.#networks.set(data.name, data);
347
+ return data;
348
+ }
349
+
350
+ network = new Network(this, data);
351
+ this.#networks.set(data.name, network);
352
+
353
+ const subnetAddress = network.subnetAddress;
354
+
355
+ if (subnetAddress) {
356
+ let subnet = this.#subnets.get(subnetAddress);
357
+ if (!subnet) {
358
+ subnet = new Subnet(this, subnetAddress);
359
+ this.#subnets.set(subnetAddress, subnet);
360
+ }
361
+ network.subnet = subnet;
362
+ subnet.networks.add(network);
363
+ }
364
+ return network;
365
+ }
366
+
367
+ addHost(host) {
368
+ this.#hosts.set(host.name, host);
369
+
370
+ for (const [name, iface] of Object.entries(host.networkInterfaces)) {
371
+ const network = this.addNetwork({ name: iface.network });
372
+ if (!network) {
373
+ console.error("Missing network", host.name, name);
374
+ } else {
375
+ network.addHost(host);
376
+ }
377
+ }
378
+ }
379
+
380
+ get dnsAllowedUpdates() {
381
+ return this.dns?.allowedUpdates || [];
382
+ }
383
+
384
+ get dnsRecordTTL() {
385
+ return this.dns?.recordTTL || "1W";
386
+ }
387
+
388
+ get administratorEmail() {
389
+ return this.#administratorEmail || "admin@" + this.domain;
390
+ }
391
+
392
+ get propertyNames() {
393
+ return [...super.propertyNames, "domain" /*, "hosts"*/];
394
+ }
395
+
396
+ toJSON() {
397
+ return {
398
+ ...super.toJSON(),
399
+ hosts: [...this.#hosts.keys()].sort()
400
+ };
401
+ }
402
+ }
403
+
404
+ export class Network extends Base {
405
+ #hosts = new Map();
406
+ kind;
407
+ scope;
408
+ metric;
409
+ ipv4;
410
+ ipv4_netmask;
411
+ subnet;
412
+
413
+ static get typeName() {
414
+ return "network";
415
+ }
416
+
417
+ constructor(owner, data) {
418
+ super(owner, data);
419
+
420
+ Object.assign(this, data);
421
+
422
+ if (this.ipv4) {
423
+ const m = this.ipv4.match(/\/(\d+)$/);
424
+ if (m) {
425
+ this.ipv4_netmask = m[1];
426
+ }
427
+ }
428
+
429
+ owner.addNetwork(this);
430
+ }
431
+
432
+ get subnetAddress() {
433
+ if (this.ipv4) {
434
+ const [addr, bits] = this.ipv4.split(/\//);
435
+ const parts = addr.split(/\./);
436
+ return parts.slice(0, bits / 8).join(".");
437
+ }
438
+ }
439
+
440
+ async *hosts() {
441
+ for (const host of this.#hosts.values()) {
442
+ yield host;
443
+ }
444
+ }
445
+
446
+ addHost(host) {
447
+ this.#hosts.set(host.name, host);
448
+ }
449
+
450
+ get propertyNames() {
451
+ return [...super.propertyNames, "kind", "ipv4", "scope", "metric"];
452
+ }
453
+ }
454
+
237
455
  export class Host extends Base {
238
456
  networkInterfaces = {};
239
457
  services = {};
@@ -446,224 +664,6 @@ export class Host extends Base {
446
664
 
447
665
  export class Model extends Host {}
448
666
 
449
- export class Location extends Base {
450
- domain;
451
- dns;
452
- #administratorEmail;
453
- #hosts = new Map();
454
- #networks = new Map();
455
- #subnets = new Map();
456
-
457
- static get typeName() {
458
- return "location";
459
- }
460
-
461
- constructor(owner, data) {
462
- super(owner, data);
463
-
464
- const networks = data.networks;
465
- delete data.networks;
466
- Object.assign(this, data);
467
-
468
- if (networks) {
469
- for (const [name, network] of Object.entries(networks)) {
470
- network.name = name;
471
- this.addNetwork(network);
472
- }
473
-
474
- for (const network of this.#networks.values()) {
475
- if (network.bridges) {
476
- network.bridges = new Set(
477
- network.bridges.map(b => {
478
- const n = this.network(b);
479
- if (!n) {
480
- console.error(`No network named ${b}`);
481
- }
482
- return n;
483
- })
484
- );
485
- }
486
- }
487
- }
488
- }
489
-
490
- async load() {
491
- for await (const host of this.owner.hosts());
492
- }
493
-
494
- async *hosts() {
495
- for await (const host of this.owner.hosts()) {
496
- if (host.location === this) {
497
- yield host;
498
- }
499
- }
500
- }
501
-
502
- async service(filter) {
503
- let best;
504
- for await (const service of this.services(filter)) {
505
- if (!best || service.priority < best.priority) {
506
- best = service;
507
- }
508
- }
509
-
510
- return best;
511
- }
512
-
513
- async *services(filter) {
514
- for await (const host of this.hosts()) {
515
- for (const service of Object.values(host.services)) {
516
- if (
517
- !filter ||
518
- filter.type === "*" ||
519
- filter.type === service.type ||
520
- filter.name === service.name
521
- ) {
522
- yield service;
523
- }
524
- }
525
- }
526
- }
527
-
528
- network(name) {
529
- return this.#networks.get(name);
530
- }
531
-
532
- async *networkAddresses() {
533
- await this.load();
534
- for await (const host of this.hosts()) {
535
- for (const networkAddresses of host.networkAddresses()) {
536
- yield networkAddresses;
537
- }
538
- }
539
- }
540
-
541
- async *networks() {
542
- await this.load();
543
- for (const network of this.#networks.values()) {
544
- yield network;
545
- }
546
- }
547
-
548
- async *subnets() {
549
- await this.load();
550
- for (const subnet of this.#subnets.values()) {
551
- yield subnet;
552
- }
553
- }
554
-
555
- addNetwork(data) {
556
- if (!data?.name) {
557
- return undefined;
558
- }
559
-
560
- let network = this.#networks.get(data.name);
561
- if (network) {
562
- return network;
563
- }
564
-
565
- network = new Network(this, data);
566
- this.#networks.set(data.name, network);
567
-
568
- const subnetAddress = network.subnetAddress;
569
-
570
- if (subnetAddress) {
571
- let subnet = this.#subnets.get(subnetAddress);
572
- if (!subnet) {
573
- subnet = new Subnet(this, subnetAddress);
574
- this.#subnets.set(subnetAddress, subnet);
575
- }
576
- network.subnet = subnet;
577
- subnet.networks.add(network);
578
- }
579
- return network;
580
- }
581
-
582
- addHost(host) {
583
- this.#hosts.set(host.name, host);
584
-
585
- for (const [name, iface] of Object.entries(host.networkInterfaces)) {
586
- const network = this.addNetwork({ name: iface.network });
587
- if (!network) {
588
- console.error("Missing network", host.name, name);
589
- } else {
590
- network.addHost(host);
591
- }
592
- }
593
- }
594
-
595
- get dnsAllowedUpdates() {
596
- return this.dns?.allowedUpdates || [];
597
- }
598
-
599
- get dnsRecordTTL() {
600
- return this.dns?.recordTTL || "1W";
601
- }
602
-
603
- get administratorEmail() {
604
- return this.#administratorEmail || "admin@" + this.domain;
605
- }
606
-
607
- get propertyNames() {
608
- return [...super.propertyNames, "domain"];
609
- }
610
-
611
- toJSON() {
612
- return {
613
- ...super.toJSON(),
614
- hosts: [...this.#hosts.keys()].sort()
615
- };
616
- }
617
- }
618
-
619
- export class Network extends Base {
620
- #hosts = new Map();
621
- kind;
622
- scope;
623
- metric;
624
- ipv4;
625
- ipv4_netmask;
626
- subnet;
627
-
628
- static get typeName() {
629
- return "network";
630
- }
631
-
632
- constructor(owner, data) {
633
- super(owner, data);
634
-
635
- Object.assign(this, data);
636
-
637
- if (this.ipv4) {
638
- const m = this.ipv4.match(/\/(\d+)$/);
639
- if (m) {
640
- this.ipv4_netmask = m[1];
641
- }
642
- }
643
- }
644
-
645
- get subnetAddress() {
646
- if (this.ipv4) {
647
- const [addr, bits] = this.ipv4.split(/\//);
648
- const parts = addr.split(/\./);
649
- return parts.slice(0, bits / 8).join(".");
650
- }
651
- }
652
-
653
- async *hosts() {
654
- for (const host of this.#hosts.values()) {
655
- yield host;
656
- }
657
- }
658
-
659
- addHost(host) {
660
- this.#hosts.set(host.name, host);
661
- }
662
-
663
- get propertyNames() {
664
- return [...super.propertyNames, "kind", "ipv4", "scope", "metric"];
665
- }
666
- }
667
667
 
668
668
  export class Subnet extends Base {
669
669
  networks = new Set();
@@ -808,8 +808,13 @@ function extractFrom(object, propertyNames) {
808
808
  const json = {};
809
809
  for (const p of propertyNames) {
810
810
  const value = object[p];
811
+
811
812
  if (value !== undefined) {
812
- json[p] = value;
813
+ if (value instanceof Base) {
814
+ json[p] = { name: object.name };
815
+ } else {
816
+ json[p] = value;
817
+ }
813
818
  }
814
819
  }
815
820
  return json;
package/types/model.d.mts CHANGED
@@ -14,7 +14,7 @@ export class Base {
14
14
  get world(): any;
15
15
  get location(): any;
16
16
  get host(): any;
17
- network(name: any): any;
17
+ network(name: any): Promise<any>;
18
18
  set directory(directory: any);
19
19
  get directory(): any;
20
20
  expand(object: any): any;
@@ -23,13 +23,16 @@ export class Base {
23
23
  toJSON(): {};
24
24
  #private;
25
25
  }
26
- export class World {
26
+ export class Owner extends Base {
27
+ addHost(host: any): void;
28
+ addNetwork(network: any): void;
29
+ network(name: any): Promise<void>;
30
+ }
31
+ export class World extends Owner {
27
32
  static get types(): {
28
33
  [k: string]: typeof Location | typeof Host | typeof Network | typeof Subnet | typeof Service;
29
34
  };
30
35
  constructor(directory: any);
31
- directory: any;
32
- get name(): string;
33
36
  get world(): this;
34
37
  _loadType(name: any, type: any): Promise<any>;
35
38
  load(): Promise<void>;
@@ -39,8 +42,6 @@ export class World {
39
42
  domains(): AsyncGenerator<any, void, unknown>;
40
43
  location(name: any): Promise<any>;
41
44
  host(name: any): Promise<any>;
42
- addHost(host: any): void;
43
- network(name: any): void;
44
45
  subnets(): AsyncGenerator<any, void, unknown>;
45
46
  networkAddresses(): AsyncGenerator<{
46
47
  address: any;
@@ -48,6 +49,37 @@ export class World {
48
49
  }, void, unknown>;
49
50
  #private;
50
51
  }
52
+ export class Location extends Owner {
53
+ domain: any;
54
+ dns: any;
55
+ hosts(): AsyncGenerator<any, void, unknown>;
56
+ service(filter: any): Promise<any>;
57
+ services(filter: any): AsyncGenerator<any, void, unknown>;
58
+ networkAddresses(): AsyncGenerator<any, void, unknown>;
59
+ network(name: any): Promise<any>;
60
+ networks(): AsyncGenerator<any, void, unknown>;
61
+ subnets(): AsyncGenerator<any, void, unknown>;
62
+ addNetwork(data: any): any;
63
+ get dnsAllowedUpdates(): any;
64
+ get dnsRecordTTL(): any;
65
+ get administratorEmail(): any;
66
+ toJSON(): {
67
+ hosts: any[];
68
+ };
69
+ #private;
70
+ }
71
+ export class Network extends Base {
72
+ kind: any;
73
+ scope: any;
74
+ metric: any;
75
+ ipv4: any;
76
+ ipv4_netmask: any;
77
+ subnet: any;
78
+ get subnetAddress(): any;
79
+ hosts(): AsyncGenerator<any, void, unknown>;
80
+ addHost(host: any): void;
81
+ #private;
82
+ }
51
83
  export class Host extends Base {
52
84
  static prepareData(world: any, data: any): Promise<typeof Host>;
53
85
  networkInterfaces: {};
@@ -81,38 +113,6 @@ export class Host extends Base {
81
113
  }
82
114
  export class Model extends Host {
83
115
  }
84
- export class Location extends Base {
85
- domain: any;
86
- dns: any;
87
- load(): Promise<void>;
88
- hosts(): AsyncGenerator<any, void, unknown>;
89
- service(filter: any): Promise<any>;
90
- services(filter: any): AsyncGenerator<any, void, unknown>;
91
- networkAddresses(): AsyncGenerator<any, void, unknown>;
92
- networks(): AsyncGenerator<any, void, unknown>;
93
- subnets(): AsyncGenerator<any, void, unknown>;
94
- addNetwork(data: any): any;
95
- addHost(host: any): void;
96
- get dnsAllowedUpdates(): any;
97
- get dnsRecordTTL(): any;
98
- get administratorEmail(): any;
99
- toJSON(): {
100
- hosts: any[];
101
- };
102
- #private;
103
- }
104
- export class Network extends Base {
105
- kind: any;
106
- scope: any;
107
- metric: any;
108
- ipv4: any;
109
- ipv4_netmask: any;
110
- subnet: any;
111
- get subnetAddress(): any;
112
- hosts(): AsyncGenerator<any, void, unknown>;
113
- addHost(host: any): void;
114
- #private;
115
- }
116
116
  export class Subnet extends Base {
117
117
  networks: Set<any>;
118
118
  get address(): any;