pmcf 1.9.1 → 1.10.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
  })
@@ -106,7 +106,7 @@ async function generateNamedDefs(location, targetDir) {
106
106
  } ${normalizeIPAddress(address)}`
107
107
  );
108
108
 
109
- for (const service of Object.values(host.services)) {
109
+ for (const service of host.services()) {
110
110
  if (service.master && service.alias) {
111
111
  zone.records.add(
112
112
  `${service.alias.padEnd(NAME_LEN, " ")} ${ttl} IN CNAME ${
@@ -115,9 +115,9 @@ async function generateNamedDefs(location, targetDir) {
115
115
  );
116
116
  }
117
117
 
118
- if (service.prefix) {
118
+ if (service.srvPrefix) {
119
119
  zone.records.add(
120
- `${`${service.prefix}.${host.domainName}.`.padEnd(
120
+ `${`${service.srvPrefix}.${host.domainName}.`.padEnd(
121
121
  NAME_LEN,
122
122
  " "
123
123
  )} ${ttl} IN SRV ${String(service.priority).padStart(4)} ${String(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcf",
3
- "version": "1.9.1",
3
+ "version": "1.10.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) {
@@ -192,7 +200,7 @@ export class Owner extends Base {
192
200
 
193
201
  _resolveBridges() {
194
202
  for (const bridge of this.#bridges) {
195
- console.log(bridgeToJSON(bridge));
203
+ this.info(bridgeToJSON(bridge));
196
204
  for (const network of bridge) {
197
205
  if (typeof network === "string") {
198
206
  const other = this.network(network);
@@ -201,7 +209,7 @@ export class Owner extends Base {
201
209
  bridge.delete(network);
202
210
  bridge.add(other);
203
211
  other.bridge = bridge;
204
- console.log("RESOLVE", network, other, bridgeToJSON(bridge));
212
+ this.info("RESOLVE", network, other, bridgeToJSON(bridge));
205
213
  } else {
206
214
  this.error(`Unresolvabale bridge network`, network);
207
215
  }
@@ -386,9 +394,31 @@ export class World extends Owner {
386
394
  }
387
395
  }
388
396
 
397
+ class DNSService {
398
+ owner;
399
+ forwardsTo = [];
400
+ constructor(owner, data) {
401
+ this.owner = owner;
402
+ Object.assign(this, data);
403
+ }
404
+
405
+ async *services() {
406
+ const filter = { type: "dns" };
407
+
408
+ yield* this.owner.services(filter);
409
+
410
+ for (const s of this.forwardsTo) {
411
+ const host = await this.owner.world.load(s);
412
+
413
+ yield* host.services(filter);
414
+ }
415
+ }
416
+ }
417
+
389
418
  export class Location extends Owner {
390
419
  domain;
391
- dns;
420
+ #dns;
421
+ ntp = { servers: [] };
392
422
  #administratorEmail;
393
423
 
394
424
  static get typeName() {
@@ -398,6 +428,13 @@ export class Location extends Owner {
398
428
  constructor(owner, data) {
399
429
  super(owner, data);
400
430
 
431
+ let dns;
432
+ if (data.dns) {
433
+ dns = data.dns;
434
+ delete data.dns;
435
+ }
436
+
437
+ this.#dns = new DNSService(this, dns);
401
438
  const networks = data.networks;
402
439
  delete data.networks;
403
440
  Object.assign(this, data);
@@ -418,6 +455,10 @@ export class Location extends Owner {
418
455
  }
419
456
  }
420
457
 
458
+ get dns() {
459
+ return this.#dns;
460
+ }
461
+
421
462
  async service(filter) {
422
463
  let best;
423
464
  for await (const service of this.services(filter)) {
@@ -431,15 +472,8 @@ export class Location extends Owner {
431
472
 
432
473
  async *services(filter) {
433
474
  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
- }
475
+ for await (const service of host.services(filter)) {
476
+ yield service;
443
477
  }
444
478
  }
445
479
  }
@@ -538,9 +572,8 @@ export class Network extends Owner {
538
572
 
539
573
  export class Host extends Base {
540
574
  networkInterfaces = {};
541
- services = {};
542
575
  postinstall = [];
543
- #isModel = false;
576
+ #services = [];
544
577
  #extends = [];
545
578
  #provides = new Set();
546
579
  #replaces = new Set();
@@ -572,11 +605,6 @@ export class Host extends Base {
572
605
  constructor(owner, data) {
573
606
  super(owner, data);
574
607
 
575
- if (data.model) {
576
- this.#isModel = true;
577
- delete data.model;
578
- }
579
-
580
608
  if (data.location !== undefined) {
581
609
  this.#location = data.location;
582
610
  delete data.location;
@@ -623,7 +651,21 @@ export class Host extends Base {
623
651
  delete data.provides;
624
652
  }
625
653
 
626
- Object.assign(this, { services: {}, networkInterfaces: {} }, data);
654
+ if (data.services) {
655
+ for (const [name, sd] of Object.entries(data.services)) {
656
+ sd.name = name;
657
+ new Service(this, sd);
658
+ }
659
+ delete data.services;
660
+ }
661
+
662
+ for (const host of this.extends) {
663
+ for (const service of host.services()) {
664
+ service.withOwner(this);
665
+ }
666
+ }
667
+
668
+ Object.assign(this, { networkInterfaces: {} }, data);
627
669
 
628
670
  owner.addHost(this);
629
671
 
@@ -631,13 +673,6 @@ export class Host extends Base {
631
673
  iface.name = name;
632
674
  this.networkInterfaces[name] = new NetworkInterface(this, iface);
633
675
  }
634
-
635
- for (const [name, data] of Object.entries(
636
- Object.assign({}, ...this.extends.map(e => e.services), this.services)
637
- )) {
638
- data.name = name;
639
- this.services[name] = new Service(this, data);
640
- }
641
676
  }
642
677
 
643
678
  get deployment() {
@@ -652,6 +687,14 @@ export class Host extends Base {
652
687
  return this.#vendor || this.extends.find(e => e.vendor)?.vendor;
653
688
  }
654
689
 
690
+ get isModel() {
691
+ return this.#vendor || this.#chassis ? true : false;
692
+ }
693
+
694
+ get model() {
695
+ return this.extends.find(h => h.isModel);
696
+ }
697
+
655
698
  get extends() {
656
699
  return this.#extends.map(e => this.expand(e));
657
700
  }
@@ -694,14 +737,6 @@ export class Host extends Base {
694
737
  return this.#distribution || this.extends.find(e => e.distribution);
695
738
  }
696
739
 
697
- get isModel() {
698
- return this.#isModel;
699
- }
700
-
701
- get model() {
702
- return this.extends.find(h => h.isModel);
703
- }
704
-
705
740
  get domain() {
706
741
  return this.location?.domain;
707
742
  }
@@ -719,6 +754,23 @@ export class Host extends Base {
719
754
  return this.hostName + "." + this.domain;
720
755
  }
721
756
 
757
+ addService(service) {
758
+ this.#services.push(service);
759
+ }
760
+
761
+ *services(filter) {
762
+ for (const service of this.#services) {
763
+ if (
764
+ !filter ||
765
+ filter.type === "*" ||
766
+ filter.type === service.type ||
767
+ filter.name === service.name
768
+ ) {
769
+ yield service;
770
+ }
771
+ }
772
+ }
773
+
722
774
  *networkAddresses() {
723
775
  for (const [name, networkInterface] of Object.entries(
724
776
  this.networkInterfaces
@@ -761,7 +813,7 @@ export class Host extends Base {
761
813
  ...super.toJSON(),
762
814
  extends: this.extends.map(host => host.name),
763
815
  services: Object.fromEntries(
764
- Object.values(this.services).map(s => [s.name, s.toJSON()])
816
+ [...this.services()].map(s => [s.name, s.toJSON()])
765
817
  )
766
818
  };
767
819
  }
@@ -815,15 +867,15 @@ export class Subnet extends Base {
815
867
  }
816
868
 
817
869
  const ServiceTypes = {
818
- dns: { prefix: "_dns._udp", port: 53 },
819
- ldap: { prefix: "_ldap._tcp", port: 389 },
820
- http: { prefix: "_http._tcp", port: 80 },
821
- https: { prefix: "_http._tcp", port: 443 },
822
- rtsp: { prefix: "_rtsp._tcp", port: 554 },
823
- smtp: { prefix: "_smtp._tcp", port: 25 },
824
- ssh: { prefix: "_ssh._tcp", port: 22 },
825
- imap: { prefix: "_imap._tcp", port: 143 },
826
- imaps: { prefix: "_imaps._tcp", port: 993 },
870
+ dns: { srvPrefix: "_dns._udp", port: 53 },
871
+ ldap: { srvPrefix: "_ldap._tcp", port: 389 },
872
+ http: { srvPrefix: "_http._tcp", port: 80 },
873
+ https: { srvPrefix: "_http._tcp", port: 443 },
874
+ rtsp: { srvPrefix: "_rtsp._tcp", port: 554 },
875
+ smtp: { srvPrefix: "_smtp._tcp", port: 25 },
876
+ ssh: { srvPrefix: "_ssh._tcp", port: 22 },
877
+ imap: { srvPrefix: "_imap._tcp", port: 143 },
878
+ imaps: { srvPrefix: "_imaps._tcp", port: 993 },
827
879
  dhcp: {}
828
880
  };
829
881
 
@@ -863,11 +915,38 @@ export class Service extends Base {
863
915
  }
864
916
 
865
917
  Object.assign(this, data);
918
+
866
919
  this.owner = owner;
920
+
921
+ owner.addService(this);
922
+ }
923
+
924
+ withOwner(owner) {
925
+ if (this.owner !== owner) {
926
+ const data = { name: this.name };
927
+ if (this.alias) {
928
+ data.alias = this.alias;
929
+ }
930
+ if (this.#type) {
931
+ data.type = this.#type;
932
+ }
933
+ if (this.#weight) {
934
+ data.weight = this.#weight;
935
+ }
936
+ if (this.#port) {
937
+ data.port = this.#port;
938
+ }
939
+ if (this.#ipAddress) {
940
+ data.ipAddress = this.#ipAddress;
941
+ }
942
+ return new this.constructor(owner, data);
943
+ }
944
+
945
+ return this;
867
946
  }
868
947
 
869
- get prefix() {
870
- return ServiceTypes[this.type]?.prefix;
948
+ get srvPrefix() {
949
+ return ServiceTypes[this.type]?.srvPrefix;
871
950
  }
872
951
 
873
952
  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;
@@ -53,6 +54,7 @@ export class World extends Owner {
53
54
  [k: string]: typeof Location | typeof Host | typeof Network | typeof Subnet | typeof Service;
54
55
  };
55
56
  constructor(directory: any);
57
+ get fullName(): string;
56
58
  get world(): this;
57
59
  load(name: any, options: any): any;
58
60
  loadAll(): Promise<void>;
@@ -70,7 +72,10 @@ export class World extends Owner {
70
72
  }
71
73
  export class Location extends Owner {
72
74
  domain: any;
73
- dns: any;
75
+ ntp: {
76
+ servers: any[];
77
+ };
78
+ get dns(): DNSService;
74
79
  service(filter: any): Promise<any>;
75
80
  services(filter: any): AsyncGenerator<any, void, unknown>;
76
81
  networkAddresses(): AsyncGenerator<any, void, unknown>;
@@ -92,11 +97,12 @@ export class Network extends Owner {
92
97
  export class Host extends Base {
93
98
  static prepareData(world: any, data: any): Promise<typeof Host>;
94
99
  networkInterfaces: {};
95
- services: {};
96
100
  postinstall: any[];
97
101
  get deployment(): any;
98
102
  get chassis(): any;
99
103
  get vendor(): any;
104
+ get isModel(): boolean;
105
+ get model(): any;
100
106
  get extends(): any[];
101
107
  get provides(): Set<any>;
102
108
  get replaces(): Set<any>;
@@ -105,12 +111,12 @@ export class Host extends Base {
105
111
  get master(): boolean;
106
112
  get os(): any;
107
113
  get distribution(): any;
108
- get isModel(): boolean;
109
- get model(): any;
110
114
  get domain(): any;
111
115
  get modelName(): any;
112
116
  get hostName(): any;
113
117
  get domainName(): string;
118
+ addService(service: any): void;
119
+ services(filter: any): Generator<any, void, unknown>;
114
120
  networkAddresses(): Generator<{
115
121
  address: any;
116
122
  networkInterface: any;
@@ -131,7 +137,7 @@ export class Subnet extends Base {
131
137
  }
132
138
  export class Service extends Base {
133
139
  alias: any;
134
- get prefix(): any;
140
+ get srvPrefix(): any;
135
141
  get ipAddress(): any;
136
142
  get port(): any;
137
143
  get priority(): any;
@@ -140,3 +146,10 @@ export class Service extends Base {
140
146
  get type(): any;
141
147
  #private;
142
148
  }
149
+ declare class DNSService {
150
+ constructor(owner: any, data: any);
151
+ owner: any;
152
+ forwardsTo: any[];
153
+ services(): AsyncGenerator<any, void, any>;
154
+ }
155
+ export {};