pmcf 1.9.2 → 1.11.0

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.
@@ -21,7 +21,7 @@ console.log("replaces", `mf-location-${location.name}`);
21
21
  console.log("description", `location definitions for ${location.name}`);
22
22
 
23
23
  async function generateLocationDefs(location, dir) {
24
- const sl = location.dns_servers;
24
+ const sl = (await Array.fromAsync(location.dns.services())).map(s=>s.ipAddress);
25
25
  const s1 = sl.shift();
26
26
 
27
27
  await writeLines(
@@ -51,7 +51,7 @@ async function generateLocationDefs(location, dir) {
51
51
  join(dir, "etc/systemd/timesyncd.conf.d"),
52
52
  `${location.name}.conf`,
53
53
  sectionLines("Time", {
54
- NTP: location.ntp_servers.join(" "),
54
+ NTP: location.ntp.servers.join(" "),
55
55
  PollIntervalMinSec: 60,
56
56
  SaveIntervalSec: 3600
57
57
  })
@@ -8,7 +8,6 @@ import { prepare } from "../src/cmd.mjs";
8
8
  const { world, args, options } = prepare();
9
9
 
10
10
  const location = await world.location(args[0] || "SW");
11
- const ttl = location.dnsRecordTTL;
12
11
  const updates = [
13
12
  Math.ceil(Date.now() / 1000),
14
13
  36000,
@@ -30,7 +29,9 @@ console.log("description", `named defintions for ${location.name}`);
30
29
  }*/
31
30
 
32
31
  async function generateNamedDefs(location, targetDir) {
32
+ const dns = location.dns;
33
33
  const domain = location.domain;
34
+ const ttl = dns.recordTTL;
34
35
 
35
36
  if (domain) {
36
37
  const zones = [];
@@ -106,7 +107,7 @@ async function generateNamedDefs(location, targetDir) {
106
107
  } ${normalizeIPAddress(address)}`
107
108
  );
108
109
 
109
- for (const service of Object.values(host.services)) {
110
+ for (const service of host.services()) {
110
111
  if (service.master && service.alias) {
111
112
  zone.records.add(
112
113
  `${service.alias.padEnd(NAME_LEN, " ")} ${ttl} IN CNAME ${
@@ -115,9 +116,9 @@ async function generateNamedDefs(location, targetDir) {
115
116
  );
116
117
  }
117
118
 
118
- if (service.prefix) {
119
+ if (service.srvPrefix) {
119
120
  zone.records.add(
120
- `${`${service.prefix}.${host.domainName}.`.padEnd(
121
+ `${`${service.srvPrefix}.${host.domainName}.`.padEnd(
121
122
  NAME_LEN,
122
123
  " "
123
124
  )} ${ttl} IN SRV ${String(service.priority).padStart(4)} ${String(
@@ -157,9 +158,8 @@ async function generateNamedDefs(location, targetDir) {
157
158
  zoneConfig.push(` type master;`);
158
159
  zoneConfig.push(` file \"${zone.file}\";`);
159
160
 
160
- const u = location.dnsAllowedUpdates;
161
161
  zoneConfig.push(
162
- ` allow-update { ${u.length ? u.join(";") : "none"}; };`
162
+ ` allow-update { ${dns.allowedUpdates.length ? dns.allowedUpdates.join(";") : "none"}; };`
163
163
  );
164
164
  zoneConfig.push(` notify yes;`);
165
165
  zoneConfig.push(`};`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcf",
3
- "version": "1.9.2",
3
+ "version": "1.11.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/model.mjs CHANGED
@@ -41,6 +41,14 @@ export class Base {
41
41
  }
42
42
  }
43
43
 
44
+ withOwner(owner) {
45
+ if (this.owner !== owner) {
46
+ return new this.constructor(owner, this);
47
+ }
48
+
49
+ return this;
50
+ }
51
+
44
52
  get typeName() {
45
53
  return this.constructor.typeName;
46
54
  }
@@ -77,7 +85,7 @@ export class Base {
77
85
  }
78
86
 
79
87
  get fullName() {
80
- return join(this.owner.fullName, this.name);
88
+ return this.owner ? join(this.owner.fullName, this.name) : this.name;
81
89
  }
82
90
 
83
91
  expand(object) {
@@ -140,6 +148,25 @@ export class Owner extends Base {
140
148
  this.addObject(host);
141
149
  }
142
150
 
151
+ async service(filter) {
152
+ let best;
153
+ for await (const service of this.services(filter)) {
154
+ if (!best || service.priority < best.priority) {
155
+ best = service;
156
+ }
157
+ }
158
+
159
+ return best;
160
+ }
161
+
162
+ async *services(filter) {
163
+ for await (const host of this.hosts()) {
164
+ for await (const service of host.services(filter)) {
165
+ yield service;
166
+ }
167
+ }
168
+ }
169
+
143
170
  network(name) {
144
171
  return this.#networks.get(name);
145
172
  }
@@ -192,7 +219,7 @@ export class Owner extends Base {
192
219
 
193
220
  _resolveBridges() {
194
221
  for (const bridge of this.#bridges) {
195
- console.log(bridgeToJSON(bridge));
222
+ this.info(bridgeToJSON(bridge));
196
223
  for (const network of bridge) {
197
224
  if (typeof network === "string") {
198
225
  const other = this.network(network);
@@ -201,7 +228,7 @@ export class Owner extends Base {
201
228
  bridge.delete(network);
202
229
  bridge.add(other);
203
230
  other.bridge = bridge;
204
- console.log("RESOLVE", network, other, bridgeToJSON(bridge));
231
+ this.info("RESOLVE", network, other, bridgeToJSON(bridge));
205
232
  } else {
206
233
  this.error(`Unresolvabale bridge network`, network);
207
234
  }
@@ -386,9 +413,34 @@ export class World extends Owner {
386
413
  }
387
414
  }
388
415
 
416
+ class DNSService {
417
+ owner;
418
+
419
+ allowedUpdates = [];
420
+ recordTTL = "1W";
421
+ forwardsTo = [];
422
+
423
+ constructor(owner, data) {
424
+ this.owner = owner;
425
+ Object.assign(this, data);
426
+ }
427
+
428
+ async *services() {
429
+ const filter = { type: "dns" };
430
+
431
+ yield* this.owner.services(filter);
432
+
433
+ for (const s of this.forwardsTo) {
434
+ const owner = await this.owner.world.load(s);
435
+ yield* owner.services(filter);
436
+ }
437
+ }
438
+ }
439
+
389
440
  export class Location extends Owner {
390
441
  domain;
391
- dns;
442
+ #dns;
443
+ ntp = { servers: [] };
392
444
  #administratorEmail;
393
445
 
394
446
  static get typeName() {
@@ -398,6 +450,13 @@ export class Location extends Owner {
398
450
  constructor(owner, data) {
399
451
  super(owner, data);
400
452
 
453
+ let dns;
454
+ if (data.dns) {
455
+ dns = data.dns;
456
+ delete data.dns;
457
+ }
458
+
459
+ this.#dns = new DNSService(this, dns);
401
460
  const networks = data.networks;
402
461
  delete data.networks;
403
462
  Object.assign(this, data);
@@ -418,31 +477,10 @@ export class Location extends Owner {
418
477
  }
419
478
  }
420
479
 
421
- async service(filter) {
422
- let best;
423
- for await (const service of this.services(filter)) {
424
- if (!best || service.priority < best.priority) {
425
- best = service;
426
- }
427
- }
428
-
429
- return best;
480
+ get dns() {
481
+ return this.#dns;
430
482
  }
431
483
 
432
- async *services(filter) {
433
- for await (const host of this.hosts()) {
434
- for (const service of Object.values(host.services)) {
435
- if (
436
- !filter ||
437
- filter.type === "*" ||
438
- filter.type === service.type ||
439
- filter.name === service.name
440
- ) {
441
- yield service;
442
- }
443
- }
444
- }
445
- }
446
484
 
447
485
  async *networkAddresses() {
448
486
  for await (const host of this.hosts()) {
@@ -452,14 +490,6 @@ export class Location extends Owner {
452
490
  }
453
491
  }
454
492
 
455
- get dnsAllowedUpdates() {
456
- return this.dns?.allowedUpdates || [];
457
- }
458
-
459
- get dnsRecordTTL() {
460
- return this.dns?.recordTTL || "1W";
461
- }
462
-
463
493
  get administratorEmail() {
464
494
  return this.#administratorEmail || "admin@" + this.domain;
465
495
  }
@@ -538,9 +568,8 @@ export class Network extends Owner {
538
568
 
539
569
  export class Host extends Base {
540
570
  networkInterfaces = {};
541
- services = {};
542
571
  postinstall = [];
543
- #isModel = false;
572
+ #services = [];
544
573
  #extends = [];
545
574
  #provides = new Set();
546
575
  #replaces = new Set();
@@ -618,7 +647,21 @@ export class Host extends Base {
618
647
  delete data.provides;
619
648
  }
620
649
 
621
- Object.assign(this, { services: {}, networkInterfaces: {} }, data);
650
+ if (data.services) {
651
+ for (const [name, sd] of Object.entries(data.services)) {
652
+ sd.name = name;
653
+ new Service(this, sd);
654
+ }
655
+ delete data.services;
656
+ }
657
+
658
+ for (const host of this.extends) {
659
+ for (const service of host.services()) {
660
+ service.withOwner(this);
661
+ }
662
+ }
663
+
664
+ Object.assign(this, { networkInterfaces: {} }, data);
622
665
 
623
666
  owner.addHost(this);
624
667
 
@@ -626,13 +669,6 @@ export class Host extends Base {
626
669
  iface.name = name;
627
670
  this.networkInterfaces[name] = new NetworkInterface(this, iface);
628
671
  }
629
-
630
- for (const [name, data] of Object.entries(
631
- Object.assign({}, ...this.extends.map(e => e.services), this.services)
632
- )) {
633
- data.name = name;
634
- this.services[name] = new Service(this, data);
635
- }
636
672
  }
637
673
 
638
674
  get deployment() {
@@ -648,7 +684,7 @@ export class Host extends Base {
648
684
  }
649
685
 
650
686
  get isModel() {
651
- return (this.#vendor || this.#chassis) ? true : false;
687
+ return this.#vendor || this.#chassis ? true : false;
652
688
  }
653
689
 
654
690
  get model() {
@@ -714,6 +750,23 @@ export class Host extends Base {
714
750
  return this.hostName + "." + this.domain;
715
751
  }
716
752
 
753
+ addService(service) {
754
+ this.#services.push(service);
755
+ }
756
+
757
+ *services(filter) {
758
+ for (const service of this.#services) {
759
+ if (
760
+ !filter ||
761
+ filter.type === "*" ||
762
+ filter.type === service.type ||
763
+ filter.name === service.name
764
+ ) {
765
+ yield service;
766
+ }
767
+ }
768
+ }
769
+
717
770
  *networkAddresses() {
718
771
  for (const [name, networkInterface] of Object.entries(
719
772
  this.networkInterfaces
@@ -756,7 +809,7 @@ export class Host extends Base {
756
809
  ...super.toJSON(),
757
810
  extends: this.extends.map(host => host.name),
758
811
  services: Object.fromEntries(
759
- Object.values(this.services).map(s => [s.name, s.toJSON()])
812
+ [...this.services()].map(s => [s.name, s.toJSON()])
760
813
  )
761
814
  };
762
815
  }
@@ -810,15 +863,15 @@ export class Subnet extends Base {
810
863
  }
811
864
 
812
865
  const ServiceTypes = {
813
- dns: { prefix: "_dns._udp", port: 53 },
814
- ldap: { prefix: "_ldap._tcp", port: 389 },
815
- http: { prefix: "_http._tcp", port: 80 },
816
- https: { prefix: "_http._tcp", port: 443 },
817
- rtsp: { prefix: "_rtsp._tcp", port: 554 },
818
- smtp: { prefix: "_smtp._tcp", port: 25 },
819
- ssh: { prefix: "_ssh._tcp", port: 22 },
820
- imap: { prefix: "_imap._tcp", port: 143 },
821
- imaps: { prefix: "_imaps._tcp", port: 993 },
866
+ dns: { srvPrefix: "_dns._udp", port: 53 },
867
+ ldap: { srvPrefix: "_ldap._tcp", port: 389 },
868
+ http: { srvPrefix: "_http._tcp", port: 80 },
869
+ https: { srvPrefix: "_http._tcp", port: 443 },
870
+ rtsp: { srvPrefix: "_rtsp._tcp", port: 554 },
871
+ smtp: { srvPrefix: "_smtp._tcp", port: 25 },
872
+ ssh: { srvPrefix: "_ssh._tcp", port: 22 },
873
+ imap: { srvPrefix: "_imap._tcp", port: 143 },
874
+ imaps: { srvPrefix: "_imaps._tcp", port: 993 },
822
875
  dhcp: {}
823
876
  };
824
877
 
@@ -858,11 +911,38 @@ export class Service extends Base {
858
911
  }
859
912
 
860
913
  Object.assign(this, data);
914
+
861
915
  this.owner = owner;
916
+
917
+ owner.addService(this);
918
+ }
919
+
920
+ withOwner(owner) {
921
+ if (this.owner !== owner) {
922
+ const data = { name: this.name };
923
+ if (this.alias) {
924
+ data.alias = this.alias;
925
+ }
926
+ if (this.#type) {
927
+ data.type = this.#type;
928
+ }
929
+ if (this.#weight) {
930
+ data.weight = this.#weight;
931
+ }
932
+ if (this.#port) {
933
+ data.port = this.#port;
934
+ }
935
+ if (this.#ipAddress) {
936
+ data.ipAddress = this.#ipAddress;
937
+ }
938
+ return new this.constructor(owner, data);
939
+ }
940
+
941
+ return this;
862
942
  }
863
943
 
864
- get prefix() {
865
- return ServiceTypes[this.type]?.prefix;
944
+ get srvPrefix() {
945
+ return ServiceTypes[this.type]?.srvPrefix;
866
946
  }
867
947
 
868
948
  get ipAddress() {
package/types/model.d.mts CHANGED
@@ -10,6 +10,7 @@ export class Base {
10
10
  owner: any;
11
11
  name: any;
12
12
  description: any;
13
+ withOwner(owner: any): any;
13
14
  get typeName(): any;
14
15
  get world(): any;
15
16
  get location(): any;
@@ -17,7 +18,7 @@ export class Base {
17
18
  network(name: any): Promise<any>;
18
19
  set directory(directory: any);
19
20
  get directory(): any;
20
- get fullName(): string;
21
+ get fullName(): any;
21
22
  expand(object: any): any;
22
23
  error(...args: any[]): void;
23
24
  info(...args: any[]): void;
@@ -30,6 +31,8 @@ export class Owner extends Base {
30
31
  hosts(): AsyncGenerator<any, void, unknown>;
31
32
  addObject(object: any): void;
32
33
  addHost(host: any): void;
34
+ service(filter: any): Promise<any>;
35
+ services(filter: any): AsyncGenerator<any, void, unknown>;
33
36
  network(name: any): any;
34
37
  networks(): AsyncGenerator<any, void, unknown>;
35
38
  addNetwork(network: any): void;
@@ -53,6 +56,7 @@ export class World extends Owner {
53
56
  [k: string]: typeof Location | typeof Host | typeof Network | typeof Subnet | typeof Service;
54
57
  };
55
58
  constructor(directory: any);
59
+ get fullName(): string;
56
60
  get world(): this;
57
61
  load(name: any, options: any): any;
58
62
  loadAll(): Promise<void>;
@@ -70,12 +74,11 @@ export class World extends Owner {
70
74
  }
71
75
  export class Location extends Owner {
72
76
  domain: any;
73
- dns: any;
74
- service(filter: any): Promise<any>;
75
- services(filter: any): AsyncGenerator<any, void, unknown>;
77
+ ntp: {
78
+ servers: any[];
79
+ };
80
+ get dns(): DNSService;
76
81
  networkAddresses(): AsyncGenerator<any, void, unknown>;
77
- get dnsAllowedUpdates(): any;
78
- get dnsRecordTTL(): any;
79
82
  get administratorEmail(): any;
80
83
  #private;
81
84
  }
@@ -92,7 +95,6 @@ export class Network extends Owner {
92
95
  export class Host extends Base {
93
96
  static prepareData(world: any, data: any): Promise<typeof Host>;
94
97
  networkInterfaces: {};
95
- services: {};
96
98
  postinstall: any[];
97
99
  get deployment(): any;
98
100
  get chassis(): any;
@@ -111,6 +113,8 @@ export class Host extends Base {
111
113
  get modelName(): any;
112
114
  get hostName(): any;
113
115
  get domainName(): string;
116
+ addService(service: any): void;
117
+ services(filter: any): Generator<any, void, unknown>;
114
118
  networkAddresses(): Generator<{
115
119
  address: any;
116
120
  networkInterface: any;
@@ -131,7 +135,7 @@ export class Subnet extends Base {
131
135
  }
132
136
  export class Service extends Base {
133
137
  alias: any;
134
- get prefix(): any;
138
+ get srvPrefix(): any;
135
139
  get ipAddress(): any;
136
140
  get port(): any;
137
141
  get priority(): any;
@@ -140,3 +144,12 @@ export class Service extends Base {
140
144
  get type(): any;
141
145
  #private;
142
146
  }
147
+ declare class DNSService {
148
+ constructor(owner: any, data: any);
149
+ owner: any;
150
+ allowedUpdates: any[];
151
+ recordTTL: string;
152
+ forwardsTo: any[];
153
+ services(): AsyncGenerator<any, void, any>;
154
+ }
155
+ export {};