pmcf 4.30.8 → 5.0.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.
Files changed (41) hide show
  1. package/bin/pmcf-diagram +1 -1
  2. package/package.json +7 -7
  3. package/src/base.mjs +81 -182
  4. package/src/cluster.mjs +22 -40
  5. package/src/{network-support.mjs → common-attributes.mjs} +66 -5
  6. package/src/extra-source-service.mjs +8 -7
  7. package/src/host.mjs +50 -53
  8. package/src/initialization-context.mjs +110 -216
  9. package/src/module.mjs +1 -2
  10. package/src/network-address.mjs +2 -2
  11. package/src/network-interfaces/ethernet.mjs +7 -15
  12. package/src/network-interfaces/loopback.mjs +1 -8
  13. package/src/network-interfaces/network-interface.mjs +28 -40
  14. package/src/network-interfaces/skeleton.mjs +14 -9
  15. package/src/network-interfaces/tun.mjs +0 -5
  16. package/src/network-interfaces/wireguard.mjs +0 -4
  17. package/src/network-interfaces/wlan.mjs +7 -18
  18. package/src/network.mjs +39 -43
  19. package/src/owner.mjs +120 -236
  20. package/src/root.mjs +13 -7
  21. package/src/service-owner.mjs +7 -26
  22. package/src/service.mjs +32 -19
  23. package/src/services/alpm.mjs +10 -6
  24. package/src/services/bind.mjs +73 -79
  25. package/src/services/chrony.mjs +3 -4
  26. package/src/services/headscale.mjs +0 -1
  27. package/src/services/influxdb.mjs +2 -2
  28. package/src/services/kea.mjs +16 -6
  29. package/src/services/mosquitto.mjs +4 -1
  30. package/src/services/openldap.mjs +4 -5
  31. package/src/services/postfix.mjs +0 -2
  32. package/src/services/systemd-journal-remote.mjs +12 -2
  33. package/src/services/systemd-journal-upload.mjs +8 -2
  34. package/src/services/systemd-journald.mjs +23 -1
  35. package/src/services/systemd-resolved.mjs +41 -19
  36. package/src/services/systemd-timesyncd.mjs +32 -10
  37. package/src/services/tailscale.mjs +0 -1
  38. package/src/subnet.mjs +38 -34
  39. package/src/type.mjs +86 -1
  40. package/src/utils.mjs +2 -2
  41. package/src/location.mjs +0 -48
package/bin/pmcf-diagram CHANGED
@@ -27,7 +27,7 @@ for await (const host of location.hosts()) {
27
27
 
28
28
  for await (const network of location.networks) {
29
29
  console.log(
30
- ` ${q(network.name)} [label="${network.name}\\n${[...network.subnets()]
30
+ ` ${q(network.name)} [label="${network.name}\\n${[...network.subnets.keys()]
31
31
  .map(s => s.address)
32
32
  .join(" ")}" shape=circle];`
33
33
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcf",
3
- "version": "4.30.8",
3
+ "version": "5.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -50,15 +50,15 @@
50
50
  "lint:docs": "documentation lint ./src**/*.mjs"
51
51
  },
52
52
  "dependencies": {
53
- "aggregated-map": "^1.0.4",
53
+ "aggregated-map": "^1.0.7",
54
54
  "content-entry-transform": "^1.6.9",
55
- "ip-utilties": "^3.1.1",
56
- "npm-pkgbuild": "^20.7.6",
57
- "pacc": "^9.5.0",
55
+ "ip-utilties": "^3.1.3",
56
+ "npm-pkgbuild": "^20.7.10",
57
+ "pacc": "^10.4.0",
58
58
  "package-directory": "^8.2.0"
59
59
  },
60
60
  "devDependencies": {
61
- "@types/node": "^26.0.0",
61
+ "@types/node": "^26.1.0",
62
62
  "ava": "^8.0.1",
63
63
  "c8": "^11.0.0",
64
64
  "documentation": "^14.0.3",
@@ -70,7 +70,7 @@
70
70
  }
71
71
  },
72
72
  "engines": {
73
- "node": ">=26.2.0"
73
+ "node": ">=26.4.0"
74
74
  },
75
75
  "repository": {
76
76
  "type": "git",
package/src/base.mjs CHANGED
@@ -12,20 +12,20 @@ import {
12
12
  parse,
13
13
  globals,
14
14
  expand,
15
+ extract,
15
16
  toExternal,
16
17
  filterPublic,
17
18
  extendingAttributeIterator,
18
- default_attribute,
19
19
  name_attribute_writable,
20
- string_attribute,
20
+ type_attribute,
21
21
  string_attribute_writable,
22
22
  string_set_attribute_writable,
23
- number_attribute_writable,
24
23
  description_attribute_writable,
25
24
  boolean_attribute_writable
26
25
  } from "pacc";
27
26
  import { union } from "./utils.mjs";
28
27
  import { addType } from "pmcf";
28
+ import { owner_attribute } from "./common-attributes.mjs";
29
29
 
30
30
  /**
31
31
  *
@@ -39,15 +39,17 @@ export class Base {
39
39
  static attributes = {
40
40
  name: name_attribute_writable,
41
41
  description: description_attribute_writable,
42
- priority: number_attribute_writable,
43
- directory: string_attribute_writable,
44
- packaging: string_attribute_writable,
45
- disabled: boolean_attribute_writable,
46
- tags: string_set_attribute_writable,
47
- owner: { ...default_attribute, type: "base", owner: false },
48
- type: string_attribute
42
+ owner: owner_attribute,
43
+ type: type_attribute,
44
+ directory: { ...string_attribute_writable, name: "directory" },
45
+ packaging: { ...string_set_attribute_writable, name: "packaging" },
46
+ disabled: { ...boolean_attribute_writable, name: "disabled" },
47
+ tags: { ...string_set_attribute_writable, name: "tags" },
48
+ template: { ...boolean_attribute_writable, name: "template", private: true }
49
49
  };
50
-
50
+ /*asMapEntry = (attribute, value, object) => {
51
+ console.log("asMapEntry",attribute?.name,value);
52
+ return [value.name, value]; };*/
51
53
  static {
52
54
  addType(this);
53
55
  }
@@ -56,7 +58,6 @@ export class Base {
56
58
  return this.name + ".json";
57
59
  }
58
60
 
59
- owner;
60
61
  description;
61
62
  name;
62
63
  properties = {};
@@ -65,76 +66,55 @@ export class Base {
65
66
  _packaging = new Set();
66
67
  _directory;
67
68
 
68
- /**
69
- *
70
- * @param {Base} owner
71
- * @param {object} [data]
72
- */
73
- constructor(owner, data) {
74
- this.owner = owner;
75
-
76
- switch (typeof data) {
77
- case "string":
78
- this.name = data;
79
- break;
69
+ set owner(value) {
70
+ if (this === value || this === value?.owner) {
71
+ this.error("Unable to own myself", value.fullName);
72
+ } else {
73
+ this._owner = value;
80
74
  }
81
75
  }
82
76
 
83
- ownerFor(attribute, data) {
84
- const owners = attribute.type.owners;
77
+ get owner() {
78
+ return this._owner;
79
+ }
85
80
 
86
- if (owners) {
87
- for (const type of owners) {
88
- if (this.typeName === type?.name) {
89
- return this;
90
- }
91
- }
92
- for (const type of owners) {
93
- const owner = this[type?.name];
94
- if (owner) {
95
- return owner;
96
- }
97
- }
81
+ forOwner(owner) {
82
+ /*if (owner === this) {
83
+ this.error("cant own myself");
84
+ }*/
85
+ if (this.owner !== owner) {
86
+ const newObject = Object.create(this);
87
+ newObject.owner = owner;
88
+ return newObject;
98
89
  }
90
+
99
91
  return this;
100
92
  }
101
93
 
102
94
  materializeExtends() {}
103
95
 
104
96
  named(name) {
97
+ if (name[0] === "/") {
98
+ return this.root.named(name.substring(1));
99
+ }
100
+
101
+ const parts = name.split("/");
102
+ const first = parts.shift();
103
+
105
104
  for (const [path, attribute] of extendingAttributeIterator(
106
105
  this.constructor,
107
- (name, attribute) => !attribute.type.primitive
106
+ attribute => !attribute.type.primitive
108
107
  )) {
109
108
  const value = this[path];
110
109
  if (typeof value?.get === "function") {
111
- const object = value.get(name);
112
- // console.log("NAMED", name, object.fullName);
110
+ const object = value.get(first);
113
111
  if (object) {
114
- return object;
112
+ return parts.length >= 1 ? object.named(parts.join("/")) : object;
115
113
  }
116
114
  }
117
115
  }
118
116
  }
119
117
 
120
- typeNamed(typeName, name) {
121
- if (this.owner) {
122
- const object = this.owner.typeNamed(typeName, name); // TODO split
123
- if (object) {
124
- return object;
125
- }
126
- }
127
-
128
- const object = this.named(name);
129
- if (object?.typeName === typeName) {
130
- return object;
131
- }
132
- }
133
-
134
- addObject(object) {
135
- return this.owner.addObject(object);
136
- }
137
-
138
118
  /**
139
119
  * Deliver AggregatedMap of all property Maps.
140
120
  * @param {string[]} directions
@@ -156,7 +136,10 @@ export class Base {
156
136
  unionFromDirections(directions, property) {
157
137
  let collected = new Set();
158
138
  for (const node of this.walkDirections(directions)) {
159
- collected = collected.union(node[property]);
139
+ const value = node[property];
140
+ if (value !== undefined) {
141
+ collected = collected.union(value);
142
+ }
160
143
  }
161
144
 
162
145
  return collected;
@@ -167,22 +150,29 @@ export class Base {
167
150
 
168
151
  for (const [path, attribute] of extendingAttributeIterator(
169
152
  this.constructor,
170
- (name, attribute) => attribute.owner && !attribute.type.primitive
153
+ attribute => attribute.backpointer?.name === "owner"
171
154
  )) {
172
155
  const value = this[path];
173
- if (value) {
156
+
157
+ if (value !== undefined) {
174
158
  if (attribute.collection) {
175
- if (typeof value.values !== "function") {
159
+ if (typeof value.values === "function") {
160
+ all.push(...value.values());
161
+ } else {
176
162
  if (value instanceof Iterator) {
177
163
  all.push(...value);
178
164
  } else {
179
- if (typeof value === "object") {
165
+ if (value instanceof Base) {
166
+ this.error(
167
+ `Unexpected scalar value for "${attribute.name}"`,
168
+ value.fullName
169
+ );
170
+ all.push(value); // TODO should not happen
171
+ } else if (typeof value === "object") {
180
172
  //console.log("NO F", this.fullName, path, value);
181
173
  all.push(...Object.values(value));
182
174
  }
183
175
  }
184
- } else {
185
- all.push(...value.values());
186
176
  }
187
177
  } else {
188
178
  all.push(value);
@@ -229,22 +219,19 @@ export class Base {
229
219
  }
230
220
  }
231
221
 
232
- forOwner(owner) {
233
- if (this.owner !== owner) {
234
- const newObject = Object.create(this);
235
- newObject.owner = owner;
236
- return newObject;
237
- }
238
-
239
- return this;
240
- }
241
-
242
222
  isNamed(name) {
243
223
  return name[0] === "/" ? this.fullName === name : this.name === name;
244
224
  }
245
225
 
246
226
  *find(pattern) {
227
+ const seen = new Set();
228
+
247
229
  for (const node of this.walkDirections(["children"])) {
230
+ if (seen.has(node)) {
231
+ continue;
232
+ }
233
+ seen.add(node);
234
+
248
235
  for (const p of pattern) {
249
236
  if (node.fullName.match(p)) {
250
237
  yield node;
@@ -255,7 +242,8 @@ export class Base {
255
242
  }
256
243
 
257
244
  get typeName() {
258
- return this.constructor.name;
245
+ const type = this.constructor;
246
+ return type.specializationOf?.name || type.name;
259
247
  }
260
248
 
261
249
  /**
@@ -324,11 +312,7 @@ export class Base {
324
312
  }
325
313
 
326
314
  get root() {
327
- return this.owner.root;
328
- }
329
-
330
- get location() {
331
- return this.owner?.location;
315
+ return this.owner?.root;
332
316
  }
333
317
 
334
318
  get host() {
@@ -397,7 +381,7 @@ export class Base {
397
381
  }
398
382
 
399
383
  get services() {
400
- return this.owner?.services || [];
384
+ return this.owner?.services || new Map();
401
385
  }
402
386
 
403
387
  set directory(directory) {
@@ -405,13 +389,16 @@ export class Base {
405
389
  }
406
390
 
407
391
  get directory() {
408
- return this._directory ?? join(this.owner.directory, this.name);
392
+ return (
393
+ this._directory ??
394
+ (this.owner?.directory
395
+ ? join(this.owner.directory, this.name)
396
+ : this.name)
397
+ );
409
398
  }
410
399
 
411
400
  get fullName() {
412
- return this.name
413
- ? join(this.owner.fullName, "/", this.name)
414
- : this.owner.fullName;
401
+ return this.owner ? join(this.owner.fullName, "/", this.name) : this.name;
415
402
  }
416
403
 
417
404
  get derivedPackaging() {
@@ -506,7 +493,11 @@ export class Base {
506
493
  * @return {boolean}
507
494
  */
508
495
  get isTemplate() {
509
- return this.name?.indexOf("*") >= 0 || this.owner?.isTemplate || false;
496
+ //console.log("T", this.name, this.owner?.name, this.owner?.owner?.name);
497
+ return (
498
+ this.template ??
499
+ (this.name?.indexOf("*") >= 0 || this.owner?.isTemplate || false)
500
+ );
510
501
  }
511
502
 
512
503
  /**
@@ -539,98 +530,6 @@ export class Base {
539
530
  }
540
531
 
541
532
  toJSON() {
542
- return extractFrom(this, this.constructor);
543
- }
544
- }
545
-
546
- export function extractFrom(object, type = object?.constructor) {
547
- switch (typeof object) {
548
- case "undefined":
549
- case "string":
550
- case "number":
551
- case "boolean":
552
- return object;
533
+ return extract(this);
553
534
  }
554
-
555
- if (object instanceof Set) {
556
- object = [...object];
557
- }
558
-
559
- if (typeof object[Symbol.iterator] === "function") {
560
- object = [...object].map(o => (o instanceof Base ? extractFrom(o) : o));
561
-
562
- if (object.length === 0) {
563
- return undefined;
564
- }
565
-
566
- if (type?.key) {
567
- return Object.fromEntries(
568
- object.map(o => {
569
- o = extractFrom(o);
570
- const name = o[type.key];
571
- delete o[type.key];
572
- return [name, o];
573
- })
574
- );
575
- }
576
-
577
- return object.length ? object : undefined;
578
- }
579
-
580
- const json = {};
581
-
582
- for (const [path, def] of extendingAttributeIterator(type, filterPublic)) {
583
- const name = path.join(".");
584
- let value = object[name];
585
-
586
- switch (typeof value) {
587
- case "function":
588
- {
589
- value = object[name]();
590
-
591
- if (typeof value?.next === "function") {
592
- value = [...value];
593
- }
594
-
595
- value = extractFrom(value, def.type);
596
- if (value !== undefined) {
597
- json[name] = value;
598
- }
599
- }
600
- break;
601
- case "object":
602
- if (value instanceof Base) {
603
- json[name] = { type: value.typeName };
604
- if (value.name) {
605
- json[name].name = value.name;
606
- }
607
- } else {
608
- if (typeof value[Symbol.iterator] === "function") {
609
- value = extractFrom(value);
610
-
611
- if (value !== undefined) {
612
- json[name] = value;
613
- }
614
- } else {
615
- const resultObject = Object.fromEntries(
616
- Object.entries(value).map(([k, v]) => [
617
- k,
618
- v // extractFrom(v, def.type)
619
- ])
620
- );
621
- if (Object.keys(resultObject).length > 0) {
622
- json[name] = resultObject;
623
- }
624
- }
625
- }
626
- break;
627
- case "undefined":
628
- break;
629
-
630
- default:
631
- json[name] = value;
632
- }
633
- }
634
-
635
- return json;
636
535
  }
package/src/cluster.mjs CHANGED
@@ -1,68 +1,50 @@
1
1
  import { join } from "node:path";
2
2
  import { FileContentProvider } from "npm-pkgbuild";
3
3
  import { FAMILY_IPV4 } from "ip-utilties";
4
- import {
5
- default_attribute_writable,
6
- default_attribute,
7
- number_attribute_writable,
8
- duration_attribute_writable
9
- } from "pacc";
10
- import { Owner } from "./owner.mjs";
4
+ import { number_attribute_writable, duration_attribute_writable } from "pacc";
11
5
  import { Host } from "./host.mjs";
12
6
  import { addType, serviceEndpoints } from "pmcf";
7
+ import {
8
+ networkInterfaces_attribute,
9
+ cluster_attribute
10
+ } from "./common-attributes.mjs";
13
11
  import { writeLines } from "./utils.mjs";
14
12
 
15
13
  export class Cluster extends Host {
16
14
  static name = "cluster";
17
15
  static priority = 1.5;
18
- static owners = [Owner, "network", "location", "root"];
19
16
  static attributes = {
20
- routerId: { ...number_attribute_writable, default: 100 },
17
+ routerId: { ...number_attribute_writable, name: "routerId", default: 100 },
21
18
  masters: {
22
- ...default_attribute_writable,
23
- type: "network_interface",
24
- collection: true
19
+ ...networkInterfaces_attribute,
20
+ name: "masters",
21
+ backpointer: cluster_attribute
25
22
  },
26
23
  backups: {
27
- ...default_attribute_writable,
28
- type: "network_interface",
29
- collection: true
24
+ ...networkInterfaces_attribute,
25
+ name: "backups",
26
+ backpointer: cluster_attribute
30
27
  },
31
28
  members: {
32
- ...default_attribute,
33
- type: "network_interface",
34
- collection: true
29
+ ...networkInterfaces_attribute,
30
+ name: "members"
35
31
  },
36
- checkInterval: { ...duration_attribute_writable, default: 60 }
32
+ checkInterval: {
33
+ ...duration_attribute_writable,
34
+ name: "checkInterval",
35
+ default: 60
36
+ }
37
37
  };
38
38
 
39
39
  static {
40
40
  addType(this);
41
41
  }
42
42
 
43
- _masters = [];
44
- _backups = [];
43
+ masters = [];
44
+ backups = [];
45
45
  routerId = 100;
46
46
  checkInterval = 60;
47
47
 
48
- set masters(value) {
49
- this._masters.push(value);
50
- value.cluster = this;
51
- }
52
-
53
- get masters() {
54
- return this._masters;
55
- }
56
-
57
- set backups(value) {
58
- this._backups.push(value);
59
- value.cluster = this;
60
- }
61
-
62
- get backups() {
63
- return this._backups;
64
- }
65
-
66
48
  get members() {
67
49
  return new Set(this.masters).union(new Set(this.backups));
68
50
  }
@@ -74,7 +56,7 @@ export class Cluster extends Host {
74
56
  )) {
75
57
  const host = ni.host;
76
58
  const packageStagingDir = join(stagingDir, host.name);
77
- const location = `${this.location.name}-${host.name}`;
59
+ const location = `${this.owner.name}-${host.name}`;
78
60
 
79
61
  const packageData = host.packageData;
80
62
  packageData.sources.push(
@@ -1,5 +1,7 @@
1
1
  import {
2
+ default_attribute,
2
3
  default_attribute_writable,
4
+ default_collection_attribute_writable,
3
5
  string_collection_attribute_writable,
4
6
  string_attribute_writable,
5
7
  integer_attribute_writable,
@@ -9,11 +11,70 @@ import {
9
11
 
10
12
  export const networkAddressType = "network|host|network_interface";
11
13
 
12
- export const networks_attribute = {
14
+ export const owner_attribute = {
15
+ ...default_attribute,
16
+ name: "owner",
17
+ type: "owner"
18
+ };
19
+
20
+ export const network_attribute = {
13
21
  ...default_attribute_writable,
22
+ name: "network",
23
+ type: "network"
24
+ };
25
+
26
+ export const networks_attribute = {
27
+ ...default_collection_attribute_writable,
14
28
  name: "networks",
15
29
  type: "network",
16
- collection: true
30
+ backpointer: owner_attribute
31
+ };
32
+
33
+ export const networkInterfaces_attribute = {
34
+ ...default_collection_attribute_writable,
35
+ name: "networkInterfaces",
36
+ type: "network_interface",
37
+ backpointer: owner_attribute
38
+ };
39
+
40
+ export const hosts_attribute = {
41
+ ...default_collection_attribute_writable,
42
+ name: "hosts",
43
+ type: "host",
44
+ backpointer: owner_attribute
45
+ };
46
+
47
+ export const owners_attribute = {
48
+ ...default_collection_attribute_writable,
49
+ name: "owners",
50
+ type: "owner",
51
+ backpointer: owner_attribute
52
+ };
53
+
54
+ export const cluster_attribute = {
55
+ ...default_attribute_writable,
56
+ name: "cluster",
57
+ type: "cluster"
58
+ };
59
+
60
+ export const clusters_attribute = {
61
+ ...default_collection_attribute_writable,
62
+ name: "clusters",
63
+ type: "cluster",
64
+ backpointer: owner_attribute
65
+ };
66
+
67
+ export const subnets_attribute = {
68
+ ...default_collection_attribute_writable,
69
+ name: "subnets",
70
+ type: "subnet",
71
+ backpointer: owner_attribute
72
+ };
73
+
74
+ export const bridges_attribute = {
75
+ ...networks_attribute,
76
+ name: "bridges",
77
+ backpointer: { ...networks_attribute, name: "bridges" }
17
78
  };
18
79
 
19
80
  export const psk_attribute = { ...string_attribute_writable, name: "psk" };
@@ -28,18 +89,18 @@ export const networkAttributes = {
28
89
  scope: {
29
90
  ...string_attribute_writable,
30
91
  name: "scope",
31
- values: ["global", "site", "link", "host"]
92
+ values: new Set(["global", "site", "link", "host"])
32
93
  // default: "global"
33
94
  },
34
95
  class: {
35
96
  ...string_attribute_writable,
36
97
  name: "class",
37
- values: ["10GBASE-T", "1000BASE-T", "100BASE-T", "10BASE-T"]
98
+ values: new Set(["10GBASE-T", "1000BASE-T", "100BASE-T", "10BASE-T"])
38
99
  },
39
100
  kind: {
40
101
  ...string_attribute_writable,
41
102
  name: "kind",
42
- values: ["loopback", "ethernet", "wlan", "wireguard", "fiber", "dsl"]
103
+ values: new Set(["loopback", "ethernet", "wlan", "wireguard", "fiber", "dsl"])
43
104
  },
44
105
  ssid: ssid_attribute,
45
106
  psk: psk_attribute,
@@ -1,15 +1,16 @@
1
- import { default_attribute_writable, addType } from "pacc";
1
+ import { AggregatedMap } from "aggregated-map";
2
+ import { default_collection_attribute_writable, addType } from "pacc";
2
3
  import { Service } from "./service.mjs";
3
4
  import { networkAddressType } from "pmcf";
4
5
 
5
6
  export class ExtraSourceService extends Service {
6
7
  static name = "extra-source-service";
7
- static specializationOf = Service;
8
+
8
9
  static attributes = {
9
10
  source: {
10
- ...default_attribute_writable,
11
- type: networkAddressType,
12
- collection: true
11
+ ...default_collection_attribute_writable,
12
+ name: "source",
13
+ type: networkAddressType
13
14
  }
14
15
  };
15
16
 
@@ -24,9 +25,9 @@ export class ExtraSourceService extends Service {
24
25
  }
25
26
 
26
27
  get services() {
27
- return [
28
+ return new AggregatedMap([
28
29
  this.owner.owner.services,
29
30
  ...this.source.map(s => s.services)
30
- ].flat();
31
+ ]);
31
32
  }
32
33
  }