pmcf 4.30.7 → 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.
- package/bin/pmcf-diagram +1 -1
- package/package.json +7 -7
- package/src/base.mjs +81 -182
- package/src/cluster.mjs +22 -40
- package/src/{network-support.mjs → common-attributes.mjs} +66 -5
- package/src/extra-source-service.mjs +8 -7
- package/src/host.mjs +50 -53
- package/src/initialization-context.mjs +110 -216
- package/src/module.mjs +1 -2
- package/src/network-address.mjs +2 -2
- package/src/network-interfaces/ethernet.mjs +7 -15
- package/src/network-interfaces/loopback.mjs +1 -8
- package/src/network-interfaces/network-interface.mjs +28 -40
- package/src/network-interfaces/skeleton.mjs +14 -9
- package/src/network-interfaces/tun.mjs +0 -5
- package/src/network-interfaces/wireguard.mjs +0 -4
- package/src/network-interfaces/wlan.mjs +7 -18
- package/src/network.mjs +39 -43
- package/src/owner.mjs +120 -236
- package/src/root.mjs +13 -7
- package/src/service-owner.mjs +7 -26
- package/src/service.mjs +32 -19
- package/src/services/alpm.mjs +10 -6
- package/src/services/bind.mjs +73 -79
- package/src/services/chrony.mjs +3 -4
- package/src/services/headscale.mjs +0 -1
- package/src/services/influxdb.mjs +2 -2
- package/src/services/kea.mjs +16 -6
- package/src/services/mosquitto.mjs +4 -1
- package/src/services/openldap.mjs +4 -5
- package/src/services/postfix.mjs +0 -2
- package/src/services/systemd-journal-remote.mjs +12 -2
- package/src/services/systemd-journal-upload.mjs +8 -2
- package/src/services/systemd-journald.mjs +23 -1
- package/src/services/systemd-resolved.mjs +41 -19
- package/src/services/systemd-timesyncd.mjs +32 -10
- package/src/services/tailscale.mjs +0 -1
- package/src/subnet.mjs +38 -34
- package/src/type.mjs +86 -1
- package/src/utils.mjs +2 -2
- package/src/location.mjs +0 -48
package/src/host.mjs
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { FileContentProvider } from "npm-pkgbuild";
|
|
4
|
+
import { AggregatedMap } from "aggregated-map";
|
|
4
5
|
import {
|
|
5
|
-
|
|
6
|
+
default_collection_attribute_writable,
|
|
6
7
|
string_attribute,
|
|
7
8
|
string_attribute_writable,
|
|
8
9
|
string_set_attribute_writable,
|
|
9
10
|
number_attribute_writable,
|
|
10
|
-
boolean_attribute_false
|
|
11
|
+
boolean_attribute_false,
|
|
12
|
+
priority_attribute
|
|
11
13
|
} from "pacc";
|
|
12
|
-
import {
|
|
14
|
+
import { addresses, addType, assign } from "pmcf";
|
|
15
|
+
import {
|
|
16
|
+
networkAddressAttributes,
|
|
17
|
+
networkInterfaces_attribute,
|
|
18
|
+
hosts_attribute
|
|
19
|
+
} from "./common-attributes.mjs";
|
|
13
20
|
import { ServiceOwner } from "./service-owner.mjs";
|
|
14
|
-
import { networkAddressAttributes } from "./network-support.mjs";
|
|
15
21
|
import { addHook } from "./hooks.mjs";
|
|
16
22
|
import {
|
|
17
23
|
domainFromDominName,
|
|
@@ -28,29 +34,29 @@ export class Host extends ServiceOwner {
|
|
|
28
34
|
static priority = 1.9;
|
|
29
35
|
static attributes = {
|
|
30
36
|
...networkAddressAttributes,
|
|
31
|
-
networkInterfaces:
|
|
32
|
-
|
|
33
|
-
type: "network_interface",
|
|
34
|
-
collection: true
|
|
35
|
-
},
|
|
36
|
-
aliases: string_set_attribute_writable,
|
|
37
|
+
networkInterfaces: networkInterfaces_attribute,
|
|
38
|
+
aliases: { ...string_set_attribute_writable, name: "aliases" },
|
|
37
39
|
os: {
|
|
38
40
|
...string_attribute_writable,
|
|
39
|
-
|
|
41
|
+
name: "os",
|
|
42
|
+
values: new Set(["osx", "windows", "linux"])
|
|
40
43
|
},
|
|
41
|
-
"machine-id": string_attribute_writable,
|
|
42
|
-
distribution: string_attribute_writable,
|
|
44
|
+
"machine-id": { ...string_attribute_writable, name: "machine-id" },
|
|
45
|
+
distribution: { ...string_attribute_writable, name: "distribution" },
|
|
43
46
|
deployment: {
|
|
44
47
|
...string_attribute_writable,
|
|
45
|
-
|
|
48
|
+
name: "deployment",
|
|
49
|
+
values: new Set(["production", "development"])
|
|
46
50
|
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
priority: priority_attribute,
|
|
52
|
+
weight: { ...number_attribute_writable, name: "weight" },
|
|
53
|
+
serial: { ...string_attribute_writable, name: "serial" },
|
|
54
|
+
vendor: { ...string_attribute_writable, name: "vendor" },
|
|
55
|
+
keymap: { ...string_attribute_writable, name: "keymap" },
|
|
51
56
|
chassis: {
|
|
52
57
|
...string_attribute_writable,
|
|
53
|
-
|
|
58
|
+
name: "chassis",
|
|
59
|
+
values: new Set([
|
|
54
60
|
"phone",
|
|
55
61
|
"tablet",
|
|
56
62
|
"router",
|
|
@@ -64,23 +70,22 @@ export class Host extends ServiceOwner {
|
|
|
64
70
|
"battery",
|
|
65
71
|
"virtual",
|
|
66
72
|
"dehumidifier"
|
|
67
|
-
]
|
|
73
|
+
])
|
|
68
74
|
},
|
|
69
75
|
architecture: {
|
|
70
76
|
...string_attribute_writable,
|
|
71
|
-
|
|
77
|
+
name: "architecture",
|
|
78
|
+
values: new Set(["x86", "x86_64", "aarch64", "armv7", "riscv"])
|
|
72
79
|
},
|
|
73
|
-
replaces: string_set_attribute_writable,
|
|
74
|
-
depends: string_set_attribute_writable,
|
|
75
|
-
provides: string_set_attribute_writable,
|
|
80
|
+
replaces: { ...string_set_attribute_writable, name: "replaces" },
|
|
81
|
+
depends: { ...string_set_attribute_writable, name: "depends" },
|
|
82
|
+
provides: { ...string_set_attribute_writable, name: "provides" },
|
|
76
83
|
extends: {
|
|
77
|
-
...
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
owner: false
|
|
84
|
+
...default_collection_attribute_writable,
|
|
85
|
+
name: "extends",
|
|
86
|
+
type: Host
|
|
81
87
|
},
|
|
82
|
-
model: string_attribute,
|
|
83
|
-
isModel: boolean_attribute_false
|
|
88
|
+
model: { ...string_attribute, name: "model" }
|
|
84
89
|
};
|
|
85
90
|
|
|
86
91
|
static {
|
|
@@ -106,11 +111,12 @@ export class Host extends ServiceOwner {
|
|
|
106
111
|
super.materializeExtends();
|
|
107
112
|
|
|
108
113
|
for (const host of this.walkDirections(["extends"])) {
|
|
109
|
-
for (const
|
|
114
|
+
for (const ni of host.networkInterfaces.values()) {
|
|
110
115
|
const present = this._networkInterfaces.get(ni.name);
|
|
111
116
|
|
|
112
117
|
if (present) {
|
|
113
118
|
present.extends.add(ni);
|
|
119
|
+
present.materializeExtends();
|
|
114
120
|
} else {
|
|
115
121
|
this.networkInterfaces = ni.forOwner(this);
|
|
116
122
|
}
|
|
@@ -292,6 +298,9 @@ export class Host extends ServiceOwner {
|
|
|
292
298
|
);
|
|
293
299
|
}
|
|
294
300
|
|
|
301
|
+
/**
|
|
302
|
+
* @return {Set<string>}
|
|
303
|
+
*/
|
|
295
304
|
get domainNames() {
|
|
296
305
|
return new Set(
|
|
297
306
|
[
|
|
@@ -335,16 +344,6 @@ export class Host extends ServiceOwner {
|
|
|
335
344
|
return [this];
|
|
336
345
|
}
|
|
337
346
|
|
|
338
|
-
typeNamed(typeName, name) {
|
|
339
|
-
if (typeName === NetworkInterface.name) {
|
|
340
|
-
const ni = this._networkInterfaces.get(name);
|
|
341
|
-
if (ni) {
|
|
342
|
-
return ni;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
return super.typeNamed(typeName, name);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
347
|
get network() {
|
|
349
348
|
for (const ni of this.networkInterfaces.values()) {
|
|
350
349
|
if (ni._kind !== "loopback" && ni._network) {
|
|
@@ -371,7 +370,8 @@ export class Host extends ServiceOwner {
|
|
|
371
370
|
this._networkInterfaces.set(networkInterface.name, networkInterface);
|
|
372
371
|
|
|
373
372
|
if (!this.isTemplate && networkInterface.network) {
|
|
374
|
-
networkInterface.network
|
|
373
|
+
assign(hosts_attribute, networkInterface.network, this);
|
|
374
|
+
//networkInterface.network.hosts = this;
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
377
|
|
|
@@ -390,13 +390,9 @@ export class Host extends ServiceOwner {
|
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
get subnets() {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
all = all.union(networkInterface.subnets);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return all;
|
|
393
|
+
return new AggregatedMap(
|
|
394
|
+
[...this.networkInterfaces.values()].map(ni => ni.subnets)
|
|
395
|
+
);
|
|
400
396
|
}
|
|
401
397
|
|
|
402
398
|
async publicKey(type = "ed25519") {
|
|
@@ -421,7 +417,7 @@ export class Host extends ServiceOwner {
|
|
|
421
417
|
Object.assign(packageData.properties, {
|
|
422
418
|
description: `${this.typeName} definitions for ${this.fullName}`,
|
|
423
419
|
dependencies: [
|
|
424
|
-
`${this.
|
|
420
|
+
`${this.owner.typeName}-${this.owner.name}`,
|
|
425
421
|
...this.depends
|
|
426
422
|
],
|
|
427
423
|
provides: [...this.provides],
|
|
@@ -440,9 +436,10 @@ export class Host extends ServiceOwner {
|
|
|
440
436
|
await ni.systemdDefinitions(dir, packageData);
|
|
441
437
|
}
|
|
442
438
|
|
|
443
|
-
await generateKnownHosts(
|
|
444
|
-
|
|
445
|
-
|
|
439
|
+
await generateKnownHosts(
|
|
440
|
+
this.owner.hosts.values(),
|
|
441
|
+
join(dir, "root", ".ssh")
|
|
442
|
+
);
|
|
446
443
|
|
|
447
444
|
for (const [name, service] of this.services) {
|
|
448
445
|
if (service.systemdConfigs) {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { readFile, glob } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import {
|
|
4
|
+
extendingAttributeIterator,
|
|
5
|
+
types,
|
|
6
|
+
resolveTypeLinks,
|
|
7
|
+
create
|
|
8
|
+
} from "pacc";
|
|
9
|
+
import { Base, root, assign } from "pmcf";
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* Keeps track of all in flight object creations and loose ends during config initialization.
|
|
@@ -18,278 +21,174 @@ export class InitializationContext {
|
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
resolveOutstanding() {
|
|
21
|
-
nextOutstanding: for (let { object, attribute,
|
|
24
|
+
nextOutstanding: for (let { object, attribute, value } of this
|
|
22
25
|
.outstandingResolves) {
|
|
23
26
|
value = object.expand(value);
|
|
24
27
|
|
|
25
28
|
for (const type of attribute.type.members || [attribute.type]) {
|
|
26
29
|
for (const node of object.walkDirections(["this", "owner"])) {
|
|
27
|
-
const resolved =
|
|
30
|
+
const resolved = this.named(value, node);
|
|
28
31
|
if (resolved) {
|
|
29
|
-
|
|
32
|
+
assign(attribute, object, resolved);
|
|
30
33
|
continue nextOutstanding;
|
|
31
34
|
}
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
this.error(
|
|
36
|
-
`
|
|
37
|
-
object.root.named(value)?.toString()
|
|
39
|
+
`Unknown ${attribute.name}(${attribute.type.name}): "${value}"`
|
|
38
40
|
);
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
resolveLater(object, attribute,
|
|
43
|
-
this.outstandingResolves.push({ object, attribute,
|
|
44
|
+
resolveLater(object, attribute, value) {
|
|
45
|
+
this.outstandingResolves.push({ object, attribute, value });
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
error(...args) {
|
|
47
49
|
console.error(...args);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
instantiateAndAssign(object, attribute, value) {
|
|
53
|
+
if (attribute.type.primitive) {
|
|
54
|
+
return assign(attribute, object, value);
|
|
55
|
+
}
|
|
54
56
|
if (value !== undefined) {
|
|
55
|
-
if (
|
|
56
|
-
if (attribute.
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (attribute.collection) {
|
|
62
|
-
const current = object[name];
|
|
63
|
-
|
|
64
|
-
switch (typeof current) {
|
|
65
|
-
case "undefined":
|
|
66
|
-
if (attribute.constructor === value.constructor) {
|
|
67
|
-
object[name] = value;
|
|
68
|
-
} else {
|
|
69
|
-
object[name] = asArray(value);
|
|
70
|
-
}
|
|
71
|
-
break;
|
|
72
|
-
case "object":
|
|
73
|
-
if (Array.isArray(current)) {
|
|
74
|
-
if (Array.isArray(value)) {
|
|
75
|
-
current.push(...value);
|
|
76
|
-
} else {
|
|
77
|
-
current.push(value);
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
if (current instanceof Set) {
|
|
81
|
-
if (value instanceof Set) {
|
|
82
|
-
object[name] = current.union(value);
|
|
83
|
-
} else {
|
|
84
|
-
/*if(name === 'extends') {
|
|
85
|
-
console.log("EXT",object.fullName,value.fullName)
|
|
86
|
-
}*/
|
|
87
|
-
object[name].add(value);
|
|
88
|
-
}
|
|
89
|
-
} else if (current instanceof Map) {
|
|
90
|
-
const keyName = attribute.type.key;
|
|
91
|
-
if (keyName) {
|
|
92
|
-
current.set(value[keyName], value);
|
|
93
|
-
} else {
|
|
94
|
-
// TODO
|
|
95
|
-
object[name] = value;
|
|
96
|
-
}
|
|
97
|
-
} else {
|
|
98
|
-
const keyName = attribute.type.key;
|
|
99
|
-
object[name][value[keyName]] = value;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
break;
|
|
103
|
-
case "function":
|
|
104
|
-
if (value instanceof Base) {
|
|
105
|
-
object.addObject(value);
|
|
106
|
-
} else {
|
|
107
|
-
this.error("Unknown collection type", name, current);
|
|
108
|
-
}
|
|
109
|
-
break;
|
|
57
|
+
if (typeof value === "object") {
|
|
58
|
+
if (attribute.type && value instanceof attribute.type) {
|
|
59
|
+
return assign(attribute, object, value);
|
|
110
60
|
}
|
|
111
61
|
} else {
|
|
112
|
-
|
|
62
|
+
const present = this.named(value, object);
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
present &&
|
|
66
|
+
(present.typeName === attribute.type.name ||
|
|
67
|
+
attribute.type.members?.has(present.typeName))
|
|
68
|
+
) {
|
|
69
|
+
return assign(attribute, object, present);
|
|
70
|
+
} else {
|
|
71
|
+
if (attribute.type.constructWithIdentifierOnly) {
|
|
72
|
+
return assign(
|
|
73
|
+
attribute,
|
|
74
|
+
object,
|
|
75
|
+
create(attribute.type, object, value)
|
|
76
|
+
);
|
|
77
|
+
} else {
|
|
78
|
+
return this.resolveLater(object, attribute, value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
113
81
|
}
|
|
82
|
+
return assign(
|
|
83
|
+
attribute,
|
|
84
|
+
object,
|
|
85
|
+
this.read(create(attribute.type, object, value), value)
|
|
86
|
+
);
|
|
114
87
|
}
|
|
115
88
|
}
|
|
116
89
|
|
|
117
|
-
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
return;
|
|
90
|
+
read(object, data, type = object.constructor) {
|
|
91
|
+
if (data?.properties) {
|
|
92
|
+
Object.assign(object.properties, data.properties);
|
|
121
93
|
}
|
|
122
94
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
break;
|
|
130
|
-
|
|
131
|
-
case "boolean":
|
|
132
|
-
case "bigint":
|
|
133
|
-
case "number":
|
|
134
|
-
case "string":
|
|
135
|
-
{
|
|
136
|
-
let o;
|
|
95
|
+
for (const [path, attribute] of extendingAttributeIterator(
|
|
96
|
+
type,
|
|
97
|
+
attribute => attribute.writable
|
|
98
|
+
)) {
|
|
99
|
+
const name = path.join(".");
|
|
100
|
+
const value = object.expand(data[name]);
|
|
137
101
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
102
|
+
if (attribute.collection) {
|
|
103
|
+
if (typeof value === "object") {
|
|
104
|
+
if (Array.isArray(value)) {
|
|
105
|
+
for (const v of value) {
|
|
106
|
+
this.instantiateAndAssign(object, attribute, v);
|
|
142
107
|
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (o) {
|
|
146
|
-
this.assign(object, name, attribute, o);
|
|
147
108
|
} else {
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
object.ownerFor(attribute, value),
|
|
151
|
-
value
|
|
152
|
-
);
|
|
153
|
-
this.read(o, value);
|
|
154
|
-
object.addObject(o);
|
|
109
|
+
if (value instanceof Base) {
|
|
110
|
+
assign(attribute, object, value);
|
|
155
111
|
} else {
|
|
156
|
-
|
|
112
|
+
for (const [objectName, objectData] of Object.entries(value)) {
|
|
113
|
+
if (typeof objectData === "object") {
|
|
114
|
+
objectData[attribute.type.key] = objectName;
|
|
115
|
+
}
|
|
116
|
+
this.instantiateAndAssign(object, attribute, objectData);
|
|
117
|
+
}
|
|
157
118
|
}
|
|
158
119
|
}
|
|
120
|
+
continue;
|
|
159
121
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
case "object":
|
|
164
|
-
if (attribute.type && value instanceof attribute.type) {
|
|
165
|
-
this.assign(object, name, attribute, value);
|
|
166
|
-
} else {
|
|
167
|
-
this.assign(
|
|
168
|
-
object,
|
|
169
|
-
name,
|
|
170
|
-
attribute,
|
|
171
|
-
this.typeFactory(
|
|
172
|
-
attribute.type,
|
|
173
|
-
object.ownerFor(attribute, value),
|
|
174
|
-
value
|
|
175
|
-
)
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
break;
|
|
122
|
+
}
|
|
123
|
+
this.instantiateAndAssign(object, attribute, value);
|
|
179
124
|
}
|
|
180
|
-
}
|
|
181
125
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
126
|
+
if (data.extends) {
|
|
127
|
+
object.materializeExtends();
|
|
128
|
+
}
|
|
185
129
|
|
|
186
|
-
this.read(object, data);
|
|
187
|
-
owner.addObject(object);
|
|
188
130
|
return object;
|
|
189
131
|
}
|
|
190
132
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
Object.assign(object.properties, data.properties);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
this._read(object, data, type);
|
|
133
|
+
async load(fileName, type) {
|
|
134
|
+
const name = fileName.replace(/\/?([^\/]+\.json)?$/, "");
|
|
197
135
|
|
|
198
|
-
|
|
199
|
-
|
|
136
|
+
const object = this.root.named(name);
|
|
137
|
+
if (object) {
|
|
138
|
+
return object;
|
|
200
139
|
}
|
|
201
|
-
}
|
|
202
140
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
this._read(object, data, type.extends);
|
|
206
|
-
}
|
|
141
|
+
if (type === undefined) {
|
|
142
|
+
const tn = fileName.substring(name.length, fileName.length - 5);
|
|
207
143
|
|
|
208
|
-
|
|
209
|
-
if (attribute.writable) {
|
|
210
|
-
const name = path.join(".");
|
|
211
|
-
const value = object.expand(data[name]);
|
|
144
|
+
type = types[tn];
|
|
212
145
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
} else {
|
|
220
|
-
if (value instanceof Base) {
|
|
221
|
-
this.assign(object, name, attribute, value);
|
|
222
|
-
} else {
|
|
223
|
-
for (const [objectName, objectData] of Object.entries(value)) {
|
|
224
|
-
if (typeof objectData === "object") {
|
|
225
|
-
objectData[attribute.type.key] = objectName;
|
|
226
|
-
}
|
|
227
|
-
this.instantiateAndAssign(
|
|
228
|
-
object,
|
|
229
|
-
name,
|
|
230
|
-
attribute,
|
|
231
|
-
objectData
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
146
|
+
if (!type) {
|
|
147
|
+
for (const type of Object.values(types).filter(type => type.fileName)) {
|
|
148
|
+
try {
|
|
149
|
+
return await this.load(fileName, type);
|
|
150
|
+
} catch {}
|
|
238
151
|
}
|
|
239
|
-
|
|
152
|
+
|
|
153
|
+
this.error(`No type for "${fileName}"`);
|
|
240
154
|
}
|
|
241
155
|
}
|
|
242
|
-
}
|
|
243
156
|
|
|
244
|
-
async loadType(name, type) {
|
|
245
157
|
const data = JSON.parse(
|
|
246
|
-
await readFile(
|
|
247
|
-
join(this.directory, name, type.fileName),
|
|
248
|
-
"utf8"
|
|
249
|
-
)
|
|
158
|
+
await readFile(join(this.directory, name, type.fileName), "utf8")
|
|
250
159
|
);
|
|
251
160
|
|
|
252
161
|
let owner;
|
|
253
162
|
if (name[0] === "/") {
|
|
254
163
|
const parentName = name.replace(/\/[^\/]+$/, "");
|
|
164
|
+
|
|
255
165
|
owner = await this.load(parentName);
|
|
166
|
+
|
|
167
|
+
if (!owner) {
|
|
168
|
+
this.error(`No Parent for "${name}" "${parentName}"`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
256
172
|
data.name = name.substring(owner.fullName.length + 1);
|
|
257
173
|
} else {
|
|
258
174
|
owner = this.root;
|
|
259
175
|
data.name = name;
|
|
260
176
|
}
|
|
261
177
|
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
return object;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
async load(name, options) {
|
|
272
|
-
name = name.replace(/\/?([^\/]+\.json)?$/, "");
|
|
273
|
-
|
|
274
|
-
const object = this.root.named(name);
|
|
275
|
-
if (object) {
|
|
276
|
-
return object;
|
|
277
|
-
}
|
|
178
|
+
for (const [path, attribute] of extendingAttributeIterator(
|
|
179
|
+
owner.constructor,
|
|
180
|
+
attribute => attribute.type === type && attribute.collection
|
|
181
|
+
)) {
|
|
182
|
+
const object = create(type, owner, data);
|
|
278
183
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
for (const type of Object.values(types).filter(
|
|
283
|
-
type => type?.fileName
|
|
284
|
-
)) {
|
|
285
|
-
try {
|
|
286
|
-
return await this.loadType(name, type);
|
|
287
|
-
} catch {}
|
|
184
|
+
// set backointer early so that parent properties can be found during load
|
|
185
|
+
if (attribute.backpointer) {
|
|
186
|
+
assign(attribute.backpointer, object, owner);
|
|
288
187
|
}
|
|
188
|
+
return assign(attribute, owner, this.read(object, data));
|
|
289
189
|
}
|
|
290
190
|
|
|
291
|
-
|
|
292
|
-
return name === parentName ? this.root : this.load(parentName, options);
|
|
191
|
+
this.error(`No attribute to assign ${type.name} to ${owner.fullName}`);
|
|
293
192
|
}
|
|
294
193
|
|
|
295
194
|
async loadAll() {
|
|
@@ -300,14 +199,7 @@ export class InitializationContext {
|
|
|
300
199
|
for await (const name of glob("**/" + type.fileName, {
|
|
301
200
|
cwd: this.directory
|
|
302
201
|
})) {
|
|
303
|
-
|
|
304
|
-
const data = JSON.parse(
|
|
305
|
-
await readFile(join(this.directory, name), "utf8")
|
|
306
|
-
);
|
|
307
|
-
this.root.properties = data.properties;
|
|
308
|
-
} else {
|
|
309
|
-
await this.load("/" + name, { type });
|
|
310
|
-
}
|
|
202
|
+
await this.load("/" + name, type);
|
|
311
203
|
}
|
|
312
204
|
}
|
|
313
205
|
}
|
|
@@ -315,7 +207,9 @@ export class InitializationContext {
|
|
|
315
207
|
this.resolveOutstanding();
|
|
316
208
|
}
|
|
317
209
|
|
|
318
|
-
named(name) {
|
|
319
|
-
return
|
|
210
|
+
named(name, base) {
|
|
211
|
+
return name[0] === "/"
|
|
212
|
+
? this.root.named(name.substring(1))
|
|
213
|
+
: base.named(name);
|
|
320
214
|
}
|
|
321
215
|
}
|
package/src/module.mjs
CHANGED
|
@@ -2,13 +2,12 @@ export * from "./type.mjs";
|
|
|
2
2
|
export * from "./base.mjs";
|
|
3
3
|
export * from "./cluster.mjs";
|
|
4
4
|
export * from "./owner.mjs";
|
|
5
|
-
export * from "./location.mjs";
|
|
6
5
|
export * from "./root.mjs";
|
|
7
6
|
export * from "./subnet.mjs";
|
|
8
7
|
export * from "./service-owner.mjs";
|
|
9
8
|
export * from "./network.mjs";
|
|
10
9
|
export * from "./network-address.mjs";
|
|
11
|
-
export * from "./
|
|
10
|
+
export * from "./common-attributes.mjs";
|
|
12
11
|
export * from "./host.mjs";
|
|
13
12
|
export * from "./network-interfaces/network-interface.mjs";
|
|
14
13
|
export * from "./network-interfaces/loopback.mjs";
|
package/src/network-address.mjs
CHANGED
|
@@ -56,8 +56,8 @@ export function addresses(sources, options) {
|
|
|
56
56
|
if (typeof s === "string") {
|
|
57
57
|
return s;
|
|
58
58
|
}
|
|
59
|
-
if (options?.aggregate && s instanceof Owner && s.subnets) {
|
|
60
|
-
return [...s.subnets];
|
|
59
|
+
if (options?.aggregate && s instanceof Owner && s.subnets.size > 0) {
|
|
60
|
+
return [...s.subnets.keys()];
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
return s.networkAddresses
|
|
@@ -1,28 +1,20 @@
|
|
|
1
|
-
import { default_attribute_writable, addType } from "pacc";
|
|
2
1
|
import { NetworkInterface } from "./network-interface.mjs";
|
|
2
|
+
import { addType } from "../type.mjs";
|
|
3
|
+
import { networkInterfaces_attribute } from "../common-attributes.mjs";
|
|
3
4
|
|
|
4
5
|
export class ethernet extends NetworkInterface {
|
|
5
|
-
static specializationOf = NetworkInterface;
|
|
6
6
|
static attributes = {
|
|
7
7
|
arpbridge: {
|
|
8
|
-
...
|
|
9
|
-
|
|
10
|
-
collection: true,
|
|
11
|
-
owner: false
|
|
8
|
+
...networkInterfaces_attribute,
|
|
9
|
+
name: "arpbridge"
|
|
12
10
|
}
|
|
13
11
|
};
|
|
14
12
|
|
|
13
|
+
static commonNamePattern = /^(eth|end|en)\d+$/;
|
|
14
|
+
|
|
15
15
|
static {
|
|
16
16
|
addType(this);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
return name.match(/^eth\d+$/);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
arpbridge;
|
|
24
|
-
|
|
25
|
-
get kind() {
|
|
26
|
-
return this.constructor.name;
|
|
27
|
-
}
|
|
19
|
+
arpbridge = new Map();
|
|
28
20
|
}
|