pmcf 4.19.2 → 4.20.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 (81) hide show
  1. package/README.md +93 -72
  2. package/package.json +19 -19
  3. package/src/base.mjs +23 -241
  4. package/src/cli.mjs +4 -4
  5. package/src/cluster.mjs +13 -11
  6. package/src/extra-source-service.mjs +7 -10
  7. package/src/host.mjs +30 -44
  8. package/src/initialization-context.mjs +324 -0
  9. package/src/location.mjs +4 -14
  10. package/src/module.mjs +1 -0
  11. package/src/network-interfaces/ethernet.mjs +3 -5
  12. package/src/network-interfaces/loopback.mjs +2 -4
  13. package/src/network-interfaces/network-interface.mjs +3 -5
  14. package/src/network-interfaces/skeleton.mjs +9 -3
  15. package/src/network-interfaces/tun.mjs +2 -4
  16. package/src/network-interfaces/wireguard.mjs +3 -5
  17. package/src/network-interfaces/wlan.mjs +4 -7
  18. package/src/network.mjs +10 -8
  19. package/src/owner.mjs +7 -31
  20. package/src/root.mjs +4 -73
  21. package/src/service-owner.mjs +19 -18
  22. package/src/service.mjs +13 -18
  23. package/src/services/alpm.mjs +4 -9
  24. package/src/services/bind.mjs +424 -388
  25. package/src/services/chrony.mjs +3 -5
  26. package/src/services/headscale.mjs +2 -4
  27. package/src/services/influxdb.mjs +2 -4
  28. package/src/services/kea.mjs +6 -10
  29. package/src/services/mosquitto.mjs +2 -4
  30. package/src/services/openldap.mjs +2 -4
  31. package/src/services/postfix.mjs +2 -4
  32. package/src/services/systemd-journal-remote.mjs +2 -4
  33. package/src/services/systemd-journal-upload.mjs +9 -10
  34. package/src/services/systemd-journald.mjs +2 -4
  35. package/src/services/systemd-resolved.mjs +42 -42
  36. package/src/services/systemd-timesyncd.mjs +9 -13
  37. package/src/services/tailscale.mjs +5 -2
  38. package/src/subnet.mjs +9 -5
  39. package/types/base.d.mts +0 -180
  40. package/types/cli.d.mts +0 -10
  41. package/types/cluster.d.mts +0 -507
  42. package/types/dns-utils.d.mts +0 -14
  43. package/types/endpoint.d.mts +0 -79
  44. package/types/extra-source-service.d.mts +0 -1033
  45. package/types/hooks.d.mts +0 -2
  46. package/types/host-utils.d.mts +0 -1
  47. package/types/host.d.mts +0 -285
  48. package/types/location.d.mts +0 -379
  49. package/types/module.d.mts +0 -36
  50. package/types/network-address.d.mts +0 -41
  51. package/types/network-interfaces/ethernet.d.mts +0 -1189
  52. package/types/network-interfaces/loopback.d.mts +0 -1140
  53. package/types/network-interfaces/network-interface.d.mts +0 -1158
  54. package/types/network-interfaces/skeleton.d.mts +0 -30
  55. package/types/network-interfaces/tun.d.mts +0 -1131
  56. package/types/network-interfaces/wireguard.d.mts +0 -1131
  57. package/types/network-interfaces/wlan.d.mts +0 -1734
  58. package/types/network-support.d.mts +0 -193
  59. package/types/network.d.mts +0 -702
  60. package/types/owner.d.mts +0 -235
  61. package/types/root.d.mts +0 -10
  62. package/types/service-owner.d.mts +0 -14
  63. package/types/service-types.d.mts +0 -246
  64. package/types/service.d.mts +0 -689
  65. package/types/services/alpm.d.mts +0 -805
  66. package/types/services/bind.d.mts +0 -1574
  67. package/types/services/chrony.d.mts +0 -1310
  68. package/types/services/headscale.d.mts +0 -801
  69. package/types/services/influxdb.d.mts +0 -812
  70. package/types/services/kea.d.mts +0 -945
  71. package/types/services/mosquitto.d.mts +0 -876
  72. package/types/services/openldap.d.mts +0 -793
  73. package/types/services/postfix.d.mts +0 -784
  74. package/types/services/systemd-journal-remote.d.mts +0 -1030
  75. package/types/services/systemd-journal-upload.d.mts +0 -932
  76. package/types/services/systemd-journald.d.mts +0 -1317
  77. package/types/services/systemd-resolved.d.mts +0 -1644
  78. package/types/services/systemd-timesyncd.d.mts +0 -1459
  79. package/types/services/tailscale.d.mts +0 -781
  80. package/types/subnet.d.mts +0 -57
  81. package/types/utils.d.mts +0 -37
package/src/cluster.mjs CHANGED
@@ -14,6 +14,7 @@ import { writeLines } from "./utils.mjs";
14
14
 
15
15
  const ClusterTypeDefinition = {
16
16
  name: "cluster",
17
+ priority: 1.5,
17
18
  owners: [Owner.typeDefinition, "network", "location", "root"],
18
19
  extends: Host.typeDefinition,
19
20
  key: "name",
@@ -39,18 +40,16 @@ const ClusterTypeDefinition = {
39
40
  };
40
41
 
41
42
  export class Cluster extends Host {
42
- _masters = [];
43
- _backups = [];
44
- routerId = 100;
45
- checkInterval = 60;
43
+ static typeDefinition = ClusterTypeDefinition;
46
44
 
47
45
  static {
48
46
  addType(this);
49
47
  }
50
48
 
51
- static get typeDefinition() {
52
- return ClusterTypeDefinition;
53
- }
49
+ _masters = [];
50
+ _backups = [];
51
+ routerId = 100;
52
+ checkInterval = 60;
54
53
 
55
54
  set masters(value) {
56
55
  this._masters.push(value);
@@ -166,7 +165,7 @@ export class Cluster extends Host {
166
165
  cfg.push("}", "");
167
166
 
168
167
  for (const endpoint of serviceEndpoints(cluster, {
169
- services: 'type="http"',
168
+ services: "services[types[http]]",
170
169
  endpoints: e =>
171
170
  e.networkInterface && e.networkInterface.kind !== "loopback"
172
171
  })) {
@@ -177,10 +176,13 @@ export class Cluster extends Host {
177
176
  cfg.push(` protocol ${endpoint.protocol.toUpperCase()}`);
178
177
 
179
178
  for (const member of this.members) {
180
- const memberService =
181
- member.findService(`type="${endpoint.type}"`) ||
182
- member.host.findService(`type="${endpoint.type}"`); // TODO
179
+ const memberService = Array.from(
180
+ member.expression(
181
+ `aggregatedServices[types[${endpoint.type}]][0]`
182
+ )
183
+ );
183
184
 
185
+ console.log(member.fullName, endpoint.type, memberService);
184
186
  cfg.push(` real_server ${member.address} ${memberService.port} {`);
185
187
  cfg.push(` weight ${memberService.weight}`);
186
188
 
@@ -17,25 +17,22 @@ export const ExtraSourceServiceTypeDefinition = {
17
17
  };
18
18
 
19
19
  export class ExtraSourceService extends Service {
20
- source = [];
20
+ static typeDefinition = ExtraSourceServiceTypeDefinition;
21
21
 
22
22
  static {
23
23
  addType(this);
24
24
  }
25
25
 
26
- static get typeDefinition() {
27
- return ExtraSourceServiceTypeDefinition;
28
- }
26
+ source = [];
29
27
 
30
28
  get type() {
31
29
  return ExtraSourceServiceTypeDefinition.name;
32
30
  }
33
31
 
34
- *findServices(filter) {
35
- yield* this.owner.owner.findServices(filter);
36
-
37
- for (const s of this.source) {
38
- yield* s.findServices(filter);
39
- }
32
+ get services() {
33
+ return [
34
+ this.owner.owner.services,
35
+ ...this.source.map(s => s.services)
36
+ ].flat();
40
37
  }
41
38
  }
package/src/host.mjs CHANGED
@@ -26,6 +26,7 @@ import { NetworkInterfaceTypeDefinition } from "./network-interfaces/network-int
26
26
 
27
27
  const HostTypeDefinition = {
28
28
  name: "host",
29
+ priority: 1.9,
29
30
  owners: ["owner", "network", "root"],
30
31
  extends: Base.typeDefinition,
31
32
  key: "name",
@@ -76,7 +77,7 @@ const HostTypeDefinition = {
76
77
  },
77
78
  architecture: {
78
79
  ...string_attribute_writable,
79
- values: ["x86", "x86_64", "aarch64", "armv7"]
80
+ values: ["x86", "x86_64", "aarch64", "armv7", "riscv"]
80
81
  },
81
82
  replaces: string_set_attribute_writable,
82
83
  depends: string_set_attribute_writable,
@@ -88,6 +89,12 @@ const HostTypeDefinition = {
88
89
  };
89
90
 
90
91
  export class Host extends ServiceOwner {
92
+ static typeDefinition = HostTypeDefinition;
93
+
94
+ static {
95
+ addType(this);
96
+ }
97
+
91
98
  _aliases = new Set();
92
99
  _networkInterfaces = new Map();
93
100
  _provides = new Set();
@@ -102,29 +109,19 @@ export class Host extends ServiceOwner {
102
109
  _serial;
103
110
  _keymap;
104
111
 
105
- static {
106
- addType(this);
107
- }
108
-
109
- static get typeDefinition() {
110
- return HostTypeDefinition;
111
- }
112
-
113
- read(data, type) {
114
- super.read(data, type);
112
+ materializeExtends() {
113
+ super.materializeExtends();
115
114
 
116
- this.extra = data.extra;
117
- }
115
+ for (const host of this.walkDirections(["extends"])) {
116
+ for (const [name, ni] of host.networkInterfaces) {
117
+ const present = this._networkInterfaces.get(name);
118
118
 
119
- _applyExtends(host) {
120
- super._applyExtends(host);
121
- for (const [name, ni] of host.networkInterfaces) {
122
- const present = this._networkInterfaces.get(name);
123
-
124
- if (present) {
125
- present.extends.push(ni);
126
- } else {
127
- this._networkInterfaces.set(name, ni.forOwner(this));
119
+ if (present) {
120
+ //console.log("LINK", present.fullName, ni.fullName);
121
+ present.extends.push(ni);
122
+ } else {
123
+ this._networkInterfaces.set(name, ni.forOwner(this));
124
+ }
128
125
  }
129
126
  }
130
127
  }
@@ -171,6 +168,13 @@ export class Host extends ServiceOwner {
171
168
  return this.extendedAttribute("_vendor");
172
169
  }
173
170
 
171
+ /**
172
+ * @return {string}
173
+ */
174
+ get id() {
175
+ return this["machine-id"];
176
+ }
177
+
174
178
  set keymap(value) {
175
179
  this._keymap = value;
176
180
  }
@@ -445,13 +449,13 @@ export class Host extends ServiceOwner {
445
449
  await ni.systemdDefinitions(dir, packageData);
446
450
  }
447
451
 
448
- if (this.keymap) {
449
- await writeLines(dir, "etc/vconsole.conf", `KEYMAP=${this.keymap}`);
450
- }
451
-
452
452
  await generateKnownHosts(this.owner.hosts, join(dir, "root", ".ssh"));
453
453
 
454
+ console.log([...this.walkDirections(["extends"])].map(e => e.fullName));
455
+
454
456
  for (const service of this.services) {
457
+ //console.log("SERVICE",service.name);
458
+
455
459
  if (service.systemdConfigs) {
456
460
  for (const { serviceName, configFileName, content } of asArray(
457
461
  service.expand(service.systemdConfigs(this.name))
@@ -468,23 +472,5 @@ export class Host extends ServiceOwner {
468
472
  }
469
473
 
470
474
  yield packageData;
471
-
472
- if (this.extra) {
473
- yield {
474
- sources: [
475
- new FileContentProvider({
476
- dir: join(this.directory, "extra"),
477
- pattern: "**/*"
478
- })
479
- ],
480
- outputs: this.outputs,
481
- properties: {
482
- name: `${this.typeName}-extra-${this.owner.name}-${this.name}`,
483
- description: `additional files for ${this.fullName}`,
484
- access: "private",
485
- dependencies: [packageData.properties.name]
486
- }
487
- };
488
- }
489
475
  }
490
476
  }
@@ -0,0 +1,324 @@
1
+ import { readFile, glob } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { toInternal, attributeIterator, types, resolveTypeLinks } from "pacc";
4
+ import { asArray } from "./utils.mjs";
5
+ import { Base } from "./base.mjs";
6
+ import { Root } from "./root.mjs";
7
+
8
+ /**
9
+ * Keeps track of all in flight object creations and loose ends during config initialization.
10
+ */
11
+ export class InitializationContext {
12
+ outstandingResolves = [];
13
+
14
+ constructor(directory = "/") {
15
+ resolveTypeLinks();
16
+ this.directory = directory;
17
+ this.root = new Root(directory);
18
+ }
19
+
20
+ resolveOutstanding() {
21
+ for (let { object, attribute, name, value } of this.outstandingResolves) {
22
+ value = object.expand(value);
23
+
24
+ for (const type of attribute.type.members || [attribute.type]) {
25
+ const o =
26
+ object.typeNamed(type.name, value) ||
27
+ object.owner.typeNamed(type.name, value) ||
28
+ object.root.typeNamed(type.name, value); // TODO
29
+
30
+ if (o) {
31
+ this.assign(object, name, attribute, o);
32
+ }
33
+ }
34
+
35
+ /*
36
+ this.error(
37
+ `No such object "${value}" (${attribute.type.name}) for attribute ${name}`,
38
+ object.root.named(value)?.toString()
39
+ );*/
40
+ }
41
+ }
42
+
43
+ resolveLater(object, attribute, name, value) {
44
+ this.outstandingResolves.push({ object, attribute, name, value });
45
+ }
46
+
47
+ error(...args) {
48
+ console.error(...args);
49
+ }
50
+
51
+ assign(object, name, attribute, value) {
52
+ value = toInternal(value, attribute);
53
+ value ??= attribute.default;
54
+
55
+ if (value !== undefined) {
56
+ if (attribute.values) {
57
+ if (attribute.values.indexOf(value) < 0) {
58
+ this.error(name, "unknown value", value, attribute.values);
59
+ }
60
+ }
61
+
62
+ if (attribute.collection) {
63
+ const current = object[name];
64
+
65
+ switch (typeof current) {
66
+ case "undefined":
67
+ if (attribute.constructor === value.constructor) {
68
+ object[name] = value;
69
+ } else {
70
+ object[name] = asArray(value);
71
+ }
72
+ break;
73
+ case "object":
74
+ if (Array.isArray(current)) {
75
+ if (Array.isArray(value)) {
76
+ current.push(...value);
77
+ } else {
78
+ current.push(value);
79
+ }
80
+ } else {
81
+ if (current instanceof Set) {
82
+ if (value instanceof Set) {
83
+ object[name] = current.union(value);
84
+ } else {
85
+ object[name].add(value);
86
+ }
87
+ } else if (current instanceof Map) {
88
+ const keyName = attribute.type.key;
89
+ if (keyName) {
90
+ current.set(value[keyName], value);
91
+ } else {
92
+ // TODO
93
+ object[name] = value;
94
+ }
95
+ } else {
96
+ const keyName = attribute.type.key;
97
+ object[name][value[keyName]] = value;
98
+ }
99
+ }
100
+ break;
101
+ case "function":
102
+ if (value instanceof Base) {
103
+ object.addObject(value);
104
+ } else {
105
+ this.error("Unknown collection type", name, current);
106
+ }
107
+ break;
108
+ }
109
+ } else {
110
+ object[name] = value;
111
+ }
112
+ }
113
+ }
114
+
115
+ instantiateAndAssign(object, name, attribute, value) {
116
+ if (attribute.type.primitive) {
117
+ this.assign(object, name, attribute, value);
118
+ return;
119
+ }
120
+
121
+ switch (typeof value) {
122
+ case "undefined":
123
+ return;
124
+
125
+ case "function":
126
+ this.error("Invalid value", name, value);
127
+ break;
128
+
129
+ case "boolean":
130
+ case "bigint":
131
+ case "number":
132
+ case "string":
133
+ {
134
+ let o;
135
+
136
+ for (const type of attribute.type.members || [attribute.type]) {
137
+ o = object.typeNamed(type.name, value);
138
+ if (o) {
139
+ break;
140
+ }
141
+ }
142
+
143
+ if (o) {
144
+ this.assign(object, name, attribute, o);
145
+ } else {
146
+ if (attribute.type.constructWithIdentifierOnly) {
147
+ o = new attribute.type.clazz(
148
+ object.ownerFor(attribute, value),
149
+ value
150
+ );
151
+ this.read(o, value);
152
+ object.addObject(o);
153
+ } else {
154
+ this.resolveLater(object, attribute, name, value);
155
+ }
156
+ }
157
+ }
158
+
159
+ break;
160
+
161
+ case "object":
162
+ if (attribute.type.clazz && value instanceof attribute.type.clazz) {
163
+ this.assign(object, name, attribute, value);
164
+ } else {
165
+ this.assign(
166
+ object,
167
+ name,
168
+ attribute,
169
+ this.typeFactory(
170
+ attribute.type,
171
+ object.ownerFor(attribute, value),
172
+ value
173
+ )
174
+ );
175
+ }
176
+ break;
177
+ }
178
+ }
179
+
180
+ typeFactory(type, owner, data) {
181
+ const factory = type.factoryFor?.(owner, data) || type.clazz;
182
+ const object = new factory(owner);
183
+
184
+ this.read(object, data);
185
+ owner.addObject(object);
186
+ return object;
187
+ }
188
+
189
+ read(object, data, type = object.constructor.typeDefinition) {
190
+ if (data?.properties) {
191
+ Object.assign(object._properties, data.properties);
192
+ }
193
+
194
+ for (const [path, attribute] of attributeIterator(type.attributes)) {
195
+ if (attribute.writable) {
196
+ const name = path.join(".");
197
+ const value = object.expand(data[name]);
198
+
199
+ if (attribute.collection) {
200
+ if (typeof value === "object") {
201
+ if (Array.isArray(value)) {
202
+ for (const v of value) {
203
+ this.instantiateAndAssign(object, name, attribute, v);
204
+ }
205
+ } else {
206
+ if (value instanceof Base) {
207
+ this.assign(object, name, attribute, value);
208
+ } else {
209
+ for (const [objectName, objectData] of Object.entries(value)) {
210
+ if (typeof objectData === "object") {
211
+ //console.log("KEY", objectName, type.name, type.key);
212
+ objectData[attribute.type.key] = objectName;
213
+ }
214
+ this.instantiateAndAssign(
215
+ object,
216
+ name,
217
+ attribute,
218
+ objectData
219
+ );
220
+ }
221
+ }
222
+ }
223
+ continue;
224
+ }
225
+ }
226
+ this.instantiateAndAssign(object, name, attribute, value);
227
+ }
228
+ }
229
+
230
+ if (object.name === undefined && data.name) {
231
+ // TODO
232
+ object.name = data.name;
233
+ }
234
+
235
+ if (type.extends) {
236
+ //console.log("READ EXTENDS",data);
237
+ this.read(object, data, type.extends);
238
+ object.materializeExtends();
239
+ }
240
+ }
241
+
242
+ async loadType(name, type) {
243
+ const data = JSON.parse(
244
+ await readFile(
245
+ join(this.directory, name, type.clazz.typeFileName),
246
+ "utf8"
247
+ )
248
+ );
249
+
250
+ //console.log("LOAD", name);
251
+ let owner;
252
+ if (name[0] === "/") {
253
+ const parentName = name.replace(/\/[^\/]+$/, "");
254
+ owner = await this.load(parentName);
255
+ data.name = name.substring(owner.fullName.length + 1);
256
+ } else {
257
+ owner = this.root;
258
+ data.name = name;
259
+ }
260
+
261
+ //console.log("LOAD", [name, owner.fullName, data.name]);
262
+
263
+ const object = this.typeFactory(type, owner, data);
264
+ this.root.addTypeObject(type.clazz.typeName, name, object);
265
+
266
+ /*if(object.name === undefined || object.name.length === 0) {
267
+ throw "NO name";
268
+ }*/
269
+
270
+ return object;
271
+ }
272
+
273
+ async load(name, options) {
274
+ name = name.replace(/\/?([^\/]+\.json)?$/, "");
275
+
276
+ const object = this.root.named(name);
277
+ if (object) {
278
+ return object;
279
+ }
280
+
281
+ if (options?.type) {
282
+ return this.loadType(name, options.type);
283
+ } else {
284
+ for (const type of Object.values(types).filter(
285
+ type => type?.clazz?.typeFileName
286
+ )) {
287
+ try {
288
+ return await this.loadType(name, type);
289
+ } catch {}
290
+ }
291
+ }
292
+
293
+ const parentName = name.replace(/\/[^\/]$/, "");
294
+ return name === parentName ? this.root : this.load(parentName, options);
295
+ }
296
+
297
+ async loadAll() {
298
+ for (const type of Object.values(types).sort(
299
+ (a, b) => b.priority - a.priority
300
+ )) {
301
+ //console.log("LIST","**/" + type.clazz.typeFileName);
302
+ if (type.clazz?.typeFileName) {
303
+ for await (const name of glob("**/" + type.clazz.typeFileName, {
304
+ cwd: this.directory
305
+ })) {
306
+ if (type === this.root.constructor) {
307
+ const data = JSON.parse(
308
+ await readFile(join(this.directory, name), "utf8")
309
+ );
310
+ this.root._properties = data.properties;
311
+ } else {
312
+ await this.load("/" + name, { type });
313
+ }
314
+ }
315
+ }
316
+ }
317
+
318
+ this.resolveOutstanding();
319
+ }
320
+
321
+ named(name) {
322
+ return this.root.named(name);
323
+ }
324
+ }
package/src/location.mjs CHANGED
@@ -5,34 +5,24 @@ import { loadHooks } from "./hooks.mjs";
5
5
 
6
6
  const LocationTypeDefinition = {
7
7
  name: "location",
8
+ priority: 2,
8
9
  owners: [Owner.typeDefinition, "location", "root"],
9
10
  extends: Owner.typeDefinition,
10
11
  key: "name",
11
- attributes: {
12
- }
12
+ attributes: {}
13
13
  };
14
14
 
15
15
  export class Location extends Owner {
16
+ static typeDefinition = LocationTypeDefinition;
17
+
16
18
  static {
17
19
  addType(this);
18
20
  }
19
21
 
20
- static get typeDefinition() {
21
- return LocationTypeDefinition;
22
- }
23
-
24
22
  get location() {
25
23
  return this;
26
24
  }
27
25
 
28
- locationNamed(name) {
29
- if (this.isNamed(name)) {
30
- return this;
31
- }
32
-
33
- return super.locationNamed(name);
34
- }
35
-
36
26
  get network() {
37
27
  return [...this.typeList("network")][0] || super.network;
38
28
  }
package/src/module.mjs CHANGED
@@ -34,3 +34,4 @@ export * from "./services/systemd-journal-remote.mjs";
34
34
  export * from "./services/systemd-journal-upload.mjs";
35
35
  export * from "./services/systemd-timesyncd.mjs";
36
36
  export * from "./services/systemd-resolved.mjs";
37
+ export * from "./initialization-context.mjs";
@@ -20,20 +20,18 @@ export const EthernetNetworkInterfaceTypeDefinition = {
20
20
  };
21
21
 
22
22
  export class EthernetNetworkInterface extends NetworkInterface {
23
- arpbridge;
23
+ static typeDefinition = EthernetNetworkInterfaceTypeDefinition;
24
24
 
25
25
  static {
26
26
  addType(this);
27
27
  }
28
28
 
29
- static get typeDefinition() {
30
- return EthernetNetworkInterfaceTypeDefinition;
31
- }
32
-
33
29
  static isCommonName(name) {
34
30
  return name.match(/^eth\d+$/);
35
31
  }
36
32
 
33
+ arpbridge;
34
+
37
35
  get kind() {
38
36
  return EthernetNetworkInterfaceTypeDefinition.name;
39
37
  }
@@ -19,14 +19,12 @@ const _localAddresses = new Map([
19
19
  const _localDomains = new Set(["localhost"]);
20
20
 
21
21
  export class LoopbackNetworkInterface extends SkeletonNetworkInterface {
22
+ static typeDefinition = LoopbackNetworkInterfaceTypeDefinition;
23
+
22
24
  static {
23
25
  addType(this);
24
26
  }
25
27
 
26
- static get typeDefinition() {
27
- return LoopbackNetworkInterfaceTypeDefinition;
28
- }
29
-
30
28
  static isCommonName(name) {
31
29
  return name.match(/^lo\d*$/);
32
30
  }
@@ -63,14 +63,12 @@ export const NetworkInterfaceTypeDefinition = {
63
63
  };
64
64
 
65
65
  export class NetworkInterface extends SkeletonNetworkInterface {
66
+ static typeDefinition = NetworkInterfaceTypeDefinition;
67
+
66
68
  static {
67
69
  addType(this);
68
70
  }
69
71
 
70
- static get typeDefinition() {
71
- return NetworkInterfaceTypeDefinition;
72
- }
73
-
74
72
  static isCommonName(name) {
75
73
  return false;
76
74
  }
@@ -178,7 +176,7 @@ export class NetworkInterface extends SkeletonNetworkInterface {
178
176
  }
179
177
 
180
178
  get mtu() {
181
- return this.extendedAttribute("_mtu"); // ?? networkAttributes.mtu.default;
179
+ return this.extendedAttribute("_mtu");
182
180
  }
183
181
 
184
182
  set class(value) {
@@ -4,15 +4,15 @@ import { NetworkAddress, Host, cidrAddresses } from "pmcf";
4
4
  import { ServiceOwner } from "../service-owner.mjs";
5
5
 
6
6
  /**
7
- *
7
+ *
8
8
  */
9
9
  export class SkeletonNetworkInterface extends ServiceOwner {
10
- _network;
11
-
12
10
  static get typeName() {
13
11
  return "network_interface";
14
12
  }
15
13
 
14
+ _network;
15
+
16
16
  get typeName() {
17
17
  return "network_interface";
18
18
  }
@@ -23,6 +23,12 @@ export class SkeletonNetworkInterface extends ServiceOwner {
23
23
  }
24
24
  }
25
25
 
26
+ get aggregatedServices() {
27
+ return this.host
28
+ ? [...this.services, ...this.host.services]
29
+ : this.services;
30
+ }
31
+
26
32
  get hosts() {
27
33
  const host = this.host;
28
34
  if (host) {
@@ -11,14 +11,12 @@ const TUNdNetworkInterfaceTypeDefinition = {
11
11
  };
12
12
 
13
13
  export class TUNNetworkInterface extends NetworkInterface {
14
+ static typeDefinition = TUNdNetworkInterfaceTypeDefinition;
15
+
14
16
  static {
15
17
  addType(this);
16
18
  }
17
19
 
18
- static get typeDefinition() {
19
- return TUNdNetworkInterfaceTypeDefinition;
20
- }
21
-
22
20
  get kind() {
23
21
  return TUNdNetworkInterfaceTypeDefinition.name;
24
22
  }