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/src/owner.mjs CHANGED
@@ -1,199 +1,139 @@
1
1
  import { normalizeCIDR, familyIP, FAMILY_IPV4 } from "ip-utilties";
2
+ import { FileContentProvider } from "npm-pkgbuild";
3
+ import { AggregatedMap } from "aggregated-map";
2
4
  import {
3
- default_attribute_writable,
4
5
  string_set_attribute_writable,
5
6
  string_attribute_writable,
6
- boolean_attribute_writable,
7
7
  email_attribute
8
8
  } from "pacc";
9
- import { addType } from "pacc";
10
- import { asIterator, asArray, union } from "./utils.mjs";
9
+ import { asArray, union } from "./utils.mjs";
11
10
  import { Base } from "./base.mjs";
12
11
  import { Subnet, SUBNET_GLOBAL_IPV4, SUBNET_GLOBAL_IPV6 } from "./subnet.mjs";
13
- import { networks_attribute } from "./network-support.mjs";
14
- import { Host } from "./host.mjs";
15
-
16
- const EMPTY = new Map();
12
+ import {
13
+ networks_attribute,
14
+ owners_attribute,
15
+ hosts_attribute,
16
+ clusters_attribute,
17
+ subnets_attribute,
18
+ networkInterfaces_attribute
19
+ } from "./common-attributes.mjs";
20
+ import { addType, assign } from "pmcf";
21
+ import { loadHooks } from "./hooks.mjs";
17
22
 
18
23
  export class Owner extends Base {
19
24
  static name = "owner";
20
25
  static priority = 2;
21
- static owners = [Owner, "location", "root"];
26
+ static owners = [Owner, "root"];
22
27
  static attributes = {
23
28
  networks: networks_attribute,
24
- hosts: {
25
- ...default_attribute_writable,
26
- type: Host,
27
- collection: true
28
- },
29
- clusters: {
30
- ...default_attribute_writable,
31
- type: "cluster",
32
- collection: true
33
- },
34
- subnets: {
35
- ...default_attribute_writable,
36
- type: Subnet,
37
- collection: true
38
- },
39
- country: string_attribute_writable,
40
- domain: string_attribute_writable,
41
- domains: string_set_attribute_writable,
42
- timezone: string_attribute_writable,
29
+ hosts: hosts_attribute,
30
+ clusters: clusters_attribute,
31
+ owners: owners_attribute,
32
+ subnets: subnets_attribute,
33
+ networkInterfaces: networkInterfaces_attribute,
34
+ country: { ...string_attribute_writable, name: "country" },
35
+ domain: { ...string_attribute_writable, name: "domain" },
36
+ domains: { ...string_set_attribute_writable, name: "domains" },
37
+ timezone: { ...string_attribute_writable, name: "timezone" },
43
38
  architectures: {
44
39
  ...string_set_attribute_writable,
40
+ name: "architectures",
45
41
  description: "all supported architectures"
46
42
  },
47
- locales: { ...string_set_attribute_writable, description: "unix locale" },
48
- administratorEmail: { ...email_attribute, writable: true },
49
- template: { ...boolean_attribute_writable, private: true }
43
+ locales: {
44
+ ...string_set_attribute_writable,
45
+ name: "locales",
46
+ description: "unix locale"
47
+ },
48
+ administratorEmail: {
49
+ ...email_attribute,
50
+ name: "administratorEmail",
51
+ writable: true
52
+ }
50
53
  };
51
54
 
52
55
  static {
53
56
  addType(this);
54
57
  }
55
58
 
56
- _membersByType = new Map();
57
- _bridges = new Set();
58
- _subnets = new Set();
59
+ owners = new Map();
60
+ networkInterfaces = new Map();
61
+ _networks = new Map();
62
+ _clusters = new Map();
63
+ _hosts = new Map();
64
+ _subnets = new Map();
59
65
 
60
66
  /**
61
- * @return {boolean}
67
+ * hosts we own direcly.
62
68
  */
63
- get isTemplate() {
64
- return this.template ?? super.isTemplate;
69
+ get directHosts() {
70
+ return new AggregatedMap([this._hosts, this._clusters]);
65
71
  }
66
72
 
67
- named(name) {
68
- if (name[0] === "/") {
69
- name = name.substring(this.fullName.length + 1);
70
- }
71
-
72
- for (const slot of this._membersByType.values()) {
73
- const object = slot.get(name);
74
- if (object) {
75
- return object;
76
- }
77
- }
78
-
79
- // TODO cascade
80
- const parts = name.split(/\//);
81
-
82
- if (parts.length >= 2) {
83
- const last = parts.pop();
84
-
85
- const next = this.named(parts.join("/"));
86
- if (next) {
87
- return next.named(last);
88
- }
89
- }
73
+ get hosts() {
74
+ return new AggregatedMap(
75
+ [this, ...this.networks.values(), ...this.owners.values()].map(
76
+ node => node.directHosts
77
+ )
78
+ );
90
79
  }
91
80
 
92
- typeNamed(typeName, name) {
93
- const typeSlot = this._membersByType.get(typeName);
94
- if (typeSlot) {
95
- const object = typeSlot.get(
96
- name[0] === "/" ? name.substring(this.fullName.length + 1) : name
97
- );
98
- if (object) {
99
- return object;
100
- }
101
- }
81
+ set hosts(value) {
82
+ this._hosts = value;
83
+ }
102
84
 
103
- return super.typeNamed(typeName, name);
85
+ get clusters() {
86
+ return new AggregatedMap(
87
+ [this, ...this.networks.values(), ...this.owners.values()].map(
88
+ node => node._clusters
89
+ )
90
+ );
104
91
  }
105
92
 
106
- typeList(typeName) {
107
- const typeSlot = this._membersByType.get(typeName);
108
- return (typeSlot || EMPTY).values();
93
+ set clusters(value) {
94
+ this._clusters = value;
109
95
  }
110
96
 
111
- addTypeObject(typeName, name, object) {
112
- const typeSlot = this._membersByType.getOrInsertComputed(
113
- typeName,
114
- () => new Map()
97
+ get networks() {
98
+ return new AggregatedMap(
99
+ [this, ...this.owners.values()].map(node => node._networks)
115
100
  );
116
- typeSlot.set(name, object);
117
101
  }
118
102
 
119
- addObject(object) {
120
- if (object instanceof Subnet) {
121
- this._subnets.add(object);
122
- } else {
123
- if (object.owner && object.owner !== this) {
124
- this.addTypeObject(
125
- object.typeName,
126
- object.owner.name + "/" + object.name,
127
- object
128
- );
129
-
130
- return;
131
- }
132
- this.addTypeObject(object.typeName, object.name, object);
133
- }
103
+ set networks(value) {
104
+ this._networks = value;
134
105
  }
135
106
 
136
107
  get services() {
137
- return [...this.hosts]
138
- .map(host => Array.from(host.services.values()))
139
- .flat();
140
- }
141
-
142
- get locations() {
143
- return this.typeList("location");
108
+ return new AggregatedMap(
109
+ [...this.hosts.values()].map(host => host.services)
110
+ );
144
111
  }
145
112
 
146
- hostNamed(name) {
147
- return this.typeNamed("host", name) || this.typeNamed("cluster", name);
113
+ get network() {
114
+ return [...this.networks.values()][0] || super.network;
148
115
  }
149
116
 
150
- directHosts() {
151
- let hosts = new Set();
152
- for (const type of ["host", "cluster"]) {
153
- hosts = hosts.union(new Set(Array.from(this.typeList(type))));
154
- }
155
-
156
- return hosts;
117
+ get subnets() {
118
+ return this._subnets;
157
119
  }
158
120
 
159
- set hosts(value) {
160
- this.typeNamed("host").set(value.name, value);
121
+ set subnets(value) {
122
+ this.addSubnet(value);
161
123
  }
162
124
 
163
- get hosts() {
164
- let hosts = this.directHosts();
165
-
166
- for (const type of Host.owners) {
167
- for (const object of this.typeList(type)) {
168
- hosts = hosts.union(object.hosts);
169
- }
125
+ addSubnet(address) {
126
+ if (address instanceof Subnet) {
127
+ return assign(subnets_attribute, this, address);
170
128
  }
171
129
 
172
- return hosts;
173
- }
174
-
175
- networkNamed(name) {
176
- return this.typeNamed("network", name);
177
- }
178
-
179
- get networks() {
180
- //return this._membersByType.get("network") || new Map();
181
- return this.typeList("network");
182
- }
183
-
184
- subnetNamed(name) {
185
- return this.subnets.values().find(s => s.name == name);
186
- }
187
-
188
- get subnets() {
189
- return this.unionFromDirections(["this", "owner"], "_subnets");
190
- }
191
-
192
- addSubnet(address) {
193
130
  const { cidr, prefixLength } = normalizeCIDR(address);
194
131
 
195
132
  if (cidr && prefixLength !== 0) {
196
- return this.subnetNamed(cidr) || new Subnet(this, cidr);
133
+ return (
134
+ this._subnets.get(cidr) ||
135
+ assign(subnets_attribute, this, new Subnet(cidr))
136
+ );
197
137
  }
198
138
 
199
139
  let subnet = this.subnetForAddress(address);
@@ -205,109 +145,26 @@ export class Owner extends Base {
205
145
  : SUBNET_GLOBAL_IPV6;
206
146
 
207
147
  this.error(
208
- `Address without subnet ${address}`,
209
- [...this.subnets].map(s => s.address)
148
+ `Address without subnet ${address} available (${[...this.subnets.keys()]})`
210
149
  );
211
150
  }
212
151
 
213
- this._subnets.add(subnet);
152
+ this._subnets.set(subnet.name, subnet);
214
153
  return subnet;
215
154
  }
216
155
 
156
+ /**
157
+ *
158
+ * @param {string} address
159
+ * @returns {Subnet?}
160
+ */
217
161
  subnetForAddress(address) {
218
162
  return this.subnets.values().find(subnet => subnet.matchesAddress(address));
219
163
  }
220
164
 
221
- get clusters() {
222
- //return this._membersByType.get("cluster") || new Map();
223
- return this.typeList("cluster");
224
- }
225
-
226
- get bridges() {
227
- return this._bridges;
228
- }
229
-
230
- addBridge(network, destinationNetworks) {
231
- if (destinationNetworks) {
232
- let bridge;
233
-
234
- for (bridge of this._bridges) {
235
- if (bridge.has(network.name)) {
236
- bridge.delete(network.name);
237
- bridge.add(network);
238
- break;
239
- }
240
-
241
- if (bridge.has(network)) {
242
- break;
243
- }
244
- }
245
-
246
- if (!bridge) {
247
- bridge = new Set([network]);
248
- this._bridges.add(bridge);
249
- }
250
-
251
- for (const nameOrNetwork of asIterator(destinationNetworks)) {
252
- const other =
253
- nameOrNetwork instanceof Owner
254
- ? nameOrNetwork
255
- : this.networkNamed(nameOrNetwork);
256
- if (other) {
257
- if (!bridge.has(other)) {
258
- bridge.add(other);
259
- other.bridge = bridge;
260
- }
261
- } else {
262
- this.error("Unknown destination", nameOrNetwork);
263
- // bridge.add(nameOrNetwork);
264
- // this.finalize(() => this._resolveBridges());
265
- }
266
- }
267
-
268
- return bridge;
269
- }
270
- }
271
-
272
- /*
273
- _resolveBridges() {
274
- for (const bridge of this._bridges) {
275
- const subnets = new Map();
276
-
277
- for (let network of bridge) {
278
- if (typeof network === "string") {
279
- const other = this.networkNamed(network);
280
-
281
- if (other) {
282
- bridge.delete(network);
283
- bridge.add(other);
284
- other.bridge = bridge;
285
- network = other;
286
- } else {
287
- this.error(`Unresolvabale bridge network`, network);
288
- }
289
- }
290
- // enshure only one subnet address in the bridge
291
- for (const subnet of network.subnets) {
292
- const present = subnets.get(subnet.address);
293
- if (present) {
294
- subnet.owner.addObject(present);
295
-
296
- for (const n of subnet.networks) {
297
- present.networks.add(n);
298
- }
299
- } else {
300
- subnets.set(subnet.address, subnet);
301
- }
302
- }
303
- }
304
- }
305
- }
306
- */
307
-
308
165
  get derivedPackaging() {
309
166
  let all = new Set();
310
- for (const host of this.hosts) {
167
+ for (const host of this.hosts.values()) {
311
168
  all = all.union(host.packaging);
312
169
  }
313
170
 
@@ -315,7 +172,7 @@ export class Owner extends Base {
315
172
  }
316
173
 
317
174
  *networkAddresses(filter) {
318
- for (const host of this.hosts) {
175
+ for (const host of this.hosts.hosts()) {
319
176
  yield* host.networkAddresses(filter);
320
177
  }
321
178
  }
@@ -381,7 +238,7 @@ export class Owner extends Base {
381
238
  get domains() {
382
239
  let domains = new Set();
383
240
 
384
- for (const object of this.hosts) {
241
+ for (const object of this.hosts.values()) {
385
242
  domains = domains.union(object.domains);
386
243
  }
387
244
 
@@ -395,7 +252,7 @@ export class Owner extends Base {
395
252
  get domainNames() {
396
253
  let names = new Set();
397
254
 
398
- for (const host of this.hosts) {
255
+ for (const host of this.hosts.values()) {
399
256
  names = names.union(new Set(host.domainNames));
400
257
  }
401
258
 
@@ -415,10 +272,37 @@ export class Owner extends Base {
415
272
 
416
273
  const architectures = new Set();
417
274
 
418
- for (const host of this.hosts) {
275
+ for (const host of this.hosts.values()) {
419
276
  architectures.add(host.architecture);
420
277
  }
421
278
 
422
279
  return architectures;
423
280
  }
281
+
282
+ async *preparePackages(dir) {
283
+ const packageData = {
284
+ sources: [
285
+ new FileContentProvider(dir + "/"),
286
+ new FileContentProvider(
287
+ { dir: this.directory, pattern: "location.json" },
288
+ { destination: "/etc/location/location.json" }
289
+ )
290
+ ],
291
+ outputs: this.outputs,
292
+ properties: {
293
+ name: `${this.typeName}-${this.name}`,
294
+ description: `${this.typeName} definitions for ${this.fullName}`,
295
+ access: "private",
296
+ dependencies: { jq: ">=1.6" },
297
+ provides: ["location"]
298
+ }
299
+ };
300
+
301
+ await loadHooks(
302
+ packageData,
303
+ new URL("location.install", import.meta.url).pathname
304
+ );
305
+
306
+ yield packageData;
307
+ }
424
308
  }
package/src/root.mjs CHANGED
@@ -1,23 +1,29 @@
1
- import { addType } from "pmcf";
2
- import { Location } from "./location.mjs";
1
+ import { Owner, addType } from "pmcf";
3
2
 
4
- export class root extends Location {
3
+ export class root extends Owner {
5
4
  static priority = 3;
6
-
7
5
  static {
8
6
  addType(this);
9
7
  }
10
8
 
11
- constructor(directory) {
12
- super(undefined, "");
9
+ constructor(directory="/") {
10
+ super();
13
11
  this.directory = directory;
14
- this.addObject(this);
12
+ this.name = "";
15
13
  }
16
14
 
17
15
  get fullName() {
18
16
  return "";
19
17
  }
20
18
 
19
+ named(name) {
20
+ if (name === "" || name === "/") {
21
+ return this;
22
+ }
23
+
24
+ return super.named(name);
25
+ }
26
+
21
27
  get root() {
22
28
  return this;
23
29
  }
@@ -1,5 +1,6 @@
1
- import { default_attribute_writable } from "pacc";
2
- import { Base, Service, addType } from "pmcf";
1
+ import { default_collection_attribute_writable } from "pacc";
2
+ import { Base, addType } from "pmcf";
3
+ import { owner_attribute } from "./common-attributes.mjs";
3
4
 
4
5
  export class ServiceOwner extends Base {
5
6
  static name = "service-owner";
@@ -7,9 +8,10 @@ export class ServiceOwner extends Base {
7
8
  static owners = ["owner", "network", "root"];
8
9
  static attributes = {
9
10
  services: {
10
- ...default_attribute_writable,
11
+ ...default_collection_attribute_writable,
12
+ name: "services",
11
13
  type: "service",
12
- collection: true
14
+ backpointer: owner_attribute
13
15
  }
14
16
  };
15
17
 
@@ -27,14 +29,6 @@ export class ServiceOwner extends Base {
27
29
  return this._services;
28
30
  }
29
31
 
30
- addObject(object) {
31
- if (object instanceof Service) {
32
- this._services.set(object.name, object);
33
- } else {
34
- super.addObject(object);
35
- }
36
- }
37
-
38
32
  materializeExtends() {
39
33
  super.materializeExtends();
40
34
 
@@ -46,23 +40,10 @@ export class ServiceOwner extends Base {
46
40
 
47
41
  if (present) {
48
42
  present.extends.add(service);
43
+ present.materializeExtends();
49
44
  } else {
50
45
  this.services = service.forOwner(this);
51
46
  }
52
47
  }
53
48
  }
54
-
55
- typeNamed(typeName, name) {
56
- if (typeName === "service") {
57
- const service = this.services.get(name);
58
- if (service) {
59
- return service;
60
- }
61
- }
62
-
63
- if (typeName === "number") {
64
- throw new Error("invalidType", { cause: typeName });
65
- }
66
- return super.typeNamed(typeName, name);
67
- }
68
49
  }
package/src/service.mjs CHANGED
@@ -3,8 +3,11 @@ import {
3
3
  string_attribute_writable,
4
4
  number_attribute_writable,
5
5
  string_set_attribute,
6
- default_attribute_writable,
7
- boolean_attribute_false
6
+ default_collection_attribute_writable,
7
+ boolean_attribute_false,
8
+ port_attribute_writable,
9
+ type_attribute_writable,
10
+ priority_attribute
8
11
  } from "pacc";
9
12
  import {
10
13
  Base,
@@ -16,7 +19,7 @@ import {
16
19
  addType
17
20
  } from "pmcf";
18
21
  import { asArray } from "./utils.mjs";
19
- import { networkAddressAttributes } from "./network-support.mjs";
22
+ import { networkAddressAttributes } from "./common-attributes.mjs";
20
23
  import {
21
24
  serviceTypeEndpoints,
22
25
  serviceTypes,
@@ -31,20 +34,22 @@ import {
31
34
  } from "./dns-utils.mjs";
32
35
 
33
36
  export const endpointAttributes = {
34
- port: number_attribute_writable,
37
+ port: port_attribute_writable,
35
38
  protocol: {
36
39
  ...string_attribute_writable,
37
- values: ["tcp", "udp", "quic"]
40
+ name: "protocol",
41
+ values: new Set(["tcp", "udp", "quic"])
38
42
  },
39
- type: string_attribute_writable,
40
- types: string_set_attribute,
41
- tls: boolean_attribute_false
43
+ type: type_attribute_writable,
44
+ types: { ...string_set_attribute, name: "types" },
45
+ tls: { ...boolean_attribute_false, name: "tls" }
42
46
  };
43
47
 
44
48
  export class Service extends Base {
45
49
  static name = "service";
46
50
  static priority = 1.1;
47
51
  static owners = [Host, "cluster", "network_interface"];
52
+ static specializationOf = Service;
48
53
  static specializations = {};
49
54
  static factoryFor(owner, value) {
50
55
  const type = value.type ?? value.name;
@@ -61,14 +66,14 @@ export class Service extends Base {
61
66
  ...networkAddressAttributes,
62
67
  ...endpointAttributes,
63
68
  extends: {
64
- ...default_attribute_writable,
65
- type: Service,
66
- collection: true,
67
- owner: false
69
+ ...default_collection_attribute_writable,
70
+ name: "extends",
71
+ type: Service
68
72
  },
69
- alias: string_attribute_writable,
70
- weight: { ...number_attribute_writable /*default: 1*/ },
71
- systemdService: string_attribute_writable
73
+ alias: { ...string_attribute_writable, name: "alias" },
74
+ priority: priority_attribute,
75
+ weight: { ...number_attribute_writable, name: "weight" /*default: 1*/ },
76
+ systemdService: { ...string_attribute_writable, name: "systemdService" }
72
77
  };
73
78
 
74
79
  static {
@@ -100,7 +105,7 @@ export class Service extends Base {
100
105
  }
101
106
 
102
107
  get domainName() {
103
- return this.host.domainName;
108
+ return this.host?.domainName;
104
109
  }
105
110
 
106
111
  get networks() {
@@ -220,6 +225,14 @@ export class Service extends Base {
220
225
  );
221
226
  }
222
227
 
228
+ set priority(value) {
229
+ this._priority = value;
230
+ }
231
+
232
+ get priority() {
233
+ return this.attribute("_priority") ?? this.owner?.priority ?? 1;
234
+ }
235
+
223
236
  set weight(value) {
224
237
  this._weight = value;
225
238
  }
@@ -249,10 +262,10 @@ export class Service extends Base {
249
262
 
250
263
  get packageData() {
251
264
  const packageData = super.packageData;
252
- const location = `${this.location.name}-${this.host.name}`;
253
- packageData.properties.name = `${this.type}-${location}`;
265
+ const name = `${this.owner.name}-${this.host.name}`;
266
+ packageData.properties.name = `${this.type}-${name}`;
254
267
  packageData.properties.description = `${this.type} service definitions for ${this.fullName}`;
255
- packageData.properties.groups.push("service-config", location);
268
+ packageData.properties.groups.push("service-config", name);
256
269
  return packageData;
257
270
  }
258
271