pmcf 1.27.2 → 1.29.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-host-defs +8 -5
- package/bin/pmcf-info +6 -4
- package/bin/pmcf-location-defs +4 -2
- package/bin/pmcf-named-defs +5 -3
- package/bin/pmcf-network +2 -2
- package/package.json +2 -2
- package/src/base.mjs +17 -9
- package/src/cluster.mjs +5 -0
- package/src/cmd.mjs +4 -4
- package/src/dns.mjs +2 -1
- package/src/model.mjs +59 -200
- package/src/owner.mjs +172 -42
- package/src/service.mjs +1 -0
- package/types/base.d.mts +5 -3
- package/types/cmd.d.mts +3 -3
- package/types/model.d.mts +5 -23
- package/types/owner.d.mts +28 -13
package/bin/pmcf-host-defs
CHANGED
|
@@ -4,18 +4,18 @@ import { writeFile, mkdir, copyFile, glob, chmod } from "node:fs/promises";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { Host } from "pmcf";
|
|
6
6
|
import { writeLines, sectionLines } from "../src/utils.mjs";
|
|
7
|
-
import { prepare
|
|
7
|
+
import { prepare } from "../src/cmd.mjs";
|
|
8
8
|
|
|
9
|
-
const {
|
|
9
|
+
const { root, args, options } = prepare();
|
|
10
10
|
|
|
11
11
|
const hostName = args[0];
|
|
12
12
|
|
|
13
|
-
const host = await
|
|
13
|
+
const host = await root.load(hostName, { type: Host });
|
|
14
14
|
|
|
15
15
|
await generateNetworkDefs(host, options.output);
|
|
16
16
|
await generateMachineInfo(host, options.output);
|
|
17
17
|
await copySshKeys(host, options.output);
|
|
18
|
-
await generateKnownHosts(
|
|
18
|
+
await generateKnownHosts(root.hosts(), join(options.output, "root", ".ssh"));
|
|
19
19
|
|
|
20
20
|
console.log("provides", "host", ...host.provides);
|
|
21
21
|
console.log("depends", `location-${host.location.name}`, ...host.depends);
|
|
@@ -153,7 +153,10 @@ async function copySshKeys(host, dir) {
|
|
|
153
153
|
for await (const file of glob("ssh_host_*", { cwd: host.directory })) {
|
|
154
154
|
const destinationFileName = join(sshDir, file);
|
|
155
155
|
await copyFile(join(host.directory, file), destinationFileName);
|
|
156
|
-
await chmod(
|
|
156
|
+
await chmod(
|
|
157
|
+
destinationFileName,
|
|
158
|
+
destinationFileName.endsWith(".pub") ? 0o0644 : 0o0600
|
|
159
|
+
);
|
|
157
160
|
}
|
|
158
161
|
}
|
|
159
162
|
|
package/bin/pmcf-info
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { prepare } from "../src/cmd.mjs";
|
|
3
|
-
const {
|
|
3
|
+
const { root, args } = prepare();
|
|
4
|
+
|
|
5
|
+
await root.loadAll();
|
|
4
6
|
|
|
5
7
|
const objectName = args[0];
|
|
6
8
|
|
|
7
9
|
if (objectName) {
|
|
8
|
-
const object = await
|
|
10
|
+
const object = await root.named(objectName);
|
|
9
11
|
console.log(object.toJSON());
|
|
10
12
|
} else {
|
|
11
|
-
for await (const location of
|
|
13
|
+
for await (const location of root.locations()) {
|
|
12
14
|
console.log(location.name);
|
|
13
|
-
console.log(" ", (await location.service({ type: "dns"}))?.toString());
|
|
15
|
+
console.log(" ", (await location.service({ type: "dns" }))?.toString());
|
|
14
16
|
}
|
|
15
17
|
}
|
package/bin/pmcf-location-defs
CHANGED
|
@@ -6,9 +6,11 @@ import { Location } from "pmcf";
|
|
|
6
6
|
import { writeLines, sectionLines } from "../src/utils.mjs";
|
|
7
7
|
import { prepare } from "../src/cmd.mjs";
|
|
8
8
|
|
|
9
|
-
const {
|
|
9
|
+
const { root, args, options } = prepare();
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
await root.loadAll();
|
|
12
|
+
|
|
13
|
+
const location = await root.load(args[0], { type: Location });
|
|
12
14
|
|
|
13
15
|
await generateLocationDefs(location, options.output);
|
|
14
16
|
|
package/bin/pmcf-named-defs
CHANGED
|
@@ -9,9 +9,11 @@ import {
|
|
|
9
9
|
} from "../src/utils.mjs";
|
|
10
10
|
import { prepare } from "../src/cmd.mjs";
|
|
11
11
|
|
|
12
|
-
const {
|
|
12
|
+
const { root, args, options } = prepare();
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
await root.loadAll();
|
|
15
|
+
|
|
16
|
+
const owner = await root.load(args[0]);
|
|
15
17
|
const updates = [
|
|
16
18
|
Math.ceil(Date.now() / 1000),
|
|
17
19
|
36000,
|
|
@@ -42,7 +44,7 @@ async function generateNamedDefs(owner, targetDir) {
|
|
|
42
44
|
const createRecord = (key, type, value) => {
|
|
43
45
|
return {
|
|
44
46
|
key,
|
|
45
|
-
|
|
47
|
+
/*type,
|
|
46
48
|
value,*/
|
|
47
49
|
toString: () =>
|
|
48
50
|
`${key.padEnd(maxKeyLength, " ")} ${ttl} IN ${type.padEnd(
|
package/bin/pmcf-network
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { prepare } from "../src/cmd.mjs";
|
|
4
4
|
|
|
5
|
-
const {
|
|
5
|
+
const { root, args } = prepare();
|
|
6
6
|
|
|
7
|
-
const location = await
|
|
7
|
+
const location = await root.load(args[0]);
|
|
8
8
|
|
|
9
9
|
function q(str) {
|
|
10
10
|
return str.match(/^\w+$/) ? str : `"${str}"`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmcf",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"pacc": "^3.1.9"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@types/node": "^22.
|
|
46
|
+
"@types/node": "^22.12.0",
|
|
47
47
|
"ava": "^6.2.0",
|
|
48
48
|
"c8": "^10.1.3",
|
|
49
49
|
"documentation": "^14.0.3",
|
package/src/base.mjs
CHANGED
|
@@ -9,6 +9,14 @@ export class Base {
|
|
|
9
9
|
static get typeName() {
|
|
10
10
|
return "base";
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
static get pluralTypeName() {
|
|
14
|
+
return this.typeName + "s";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static get nameLookupName() {
|
|
18
|
+
return this.typeName + "Named";
|
|
19
|
+
}
|
|
12
20
|
|
|
13
21
|
static get typeFileName() {
|
|
14
22
|
return this.typeName + ".json";
|
|
@@ -18,16 +26,14 @@ export class Base {
|
|
|
18
26
|
return "**/" + this.typeFileName;
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
static async prepareData(
|
|
29
|
+
static async prepareData(root, data) {
|
|
22
30
|
return this;
|
|
23
31
|
}
|
|
24
32
|
|
|
25
|
-
static
|
|
26
|
-
if (
|
|
27
|
-
return
|
|
33
|
+
static normalizeName(name) {
|
|
34
|
+
if (name !== undefined) {
|
|
35
|
+
return name.replace(/\/\w+\.json$/, "");
|
|
28
36
|
}
|
|
29
|
-
|
|
30
|
-
return name.replace(/\/\w+\.json$/, "");
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
constructor(owner, data) {
|
|
@@ -43,6 +49,7 @@ export class Base {
|
|
|
43
49
|
|
|
44
50
|
withOwner(owner) {
|
|
45
51
|
if (this.owner !== owner) {
|
|
52
|
+
// @ts-ignore
|
|
46
53
|
return new this.constructor(owner, this);
|
|
47
54
|
}
|
|
48
55
|
|
|
@@ -50,11 +57,12 @@ export class Base {
|
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
get typeName() {
|
|
60
|
+
// @ts-ignore
|
|
53
61
|
return this.constructor.typeName;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
|
-
get
|
|
57
|
-
return this.owner.
|
|
64
|
+
get root() {
|
|
65
|
+
return this.owner.root;
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
get location() {
|
|
@@ -83,7 +91,7 @@ export class Base {
|
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
get fullName() {
|
|
86
|
-
return this.owner
|
|
94
|
+
return this.owner && this.name
|
|
87
95
|
? join(this.owner.fullName, this.name)
|
|
88
96
|
: this.name;
|
|
89
97
|
}
|
package/src/cluster.mjs
CHANGED
package/src/cmd.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
2
|
import { argv, cwd, env } from "node:process";
|
|
3
|
-
import {
|
|
3
|
+
import { Root } from "./model.mjs";
|
|
4
4
|
|
|
5
5
|
export function prepare() {
|
|
6
6
|
const { values, positionals } = parseArgs({
|
|
7
7
|
args: argv.slice(2),
|
|
8
8
|
options: {
|
|
9
|
-
|
|
9
|
+
root: {
|
|
10
10
|
type: "string",
|
|
11
11
|
short: "w",
|
|
12
12
|
default: env.PMCF_WORLD || cwd()
|
|
@@ -20,7 +20,7 @@ export function prepare() {
|
|
|
20
20
|
allowPositionals: true
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const root = new Root(values.root);
|
|
24
24
|
|
|
25
|
-
return {
|
|
25
|
+
return { root, options: values, args: positionals };
|
|
26
26
|
}
|
package/src/dns.mjs
CHANGED
|
@@ -13,6 +13,7 @@ export class DNSService extends Base {
|
|
|
13
13
|
constructor(owner, data) {
|
|
14
14
|
super(owner, data);
|
|
15
15
|
Object.assign(this, data);
|
|
16
|
+
owner.addObject(this);
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
async *services() {
|
|
@@ -21,7 +22,7 @@ export class DNSService extends Base {
|
|
|
21
22
|
yield* this.owner.services(filter);
|
|
22
23
|
|
|
23
24
|
for (const s of asArray(this.forwardsTo)) {
|
|
24
|
-
const owner = await this.owner.
|
|
25
|
+
const owner = await this.owner.root.load(s);
|
|
25
26
|
yield* owner.services(filter);
|
|
26
27
|
}
|
|
27
28
|
}
|
package/src/model.mjs
CHANGED
|
@@ -7,104 +7,92 @@ import {
|
|
|
7
7
|
normalizeIPAddress
|
|
8
8
|
} from "./utils.mjs";
|
|
9
9
|
import { Base } from "./base.mjs";
|
|
10
|
-
import { Owner } from "./owner.mjs";
|
|
10
|
+
import { Owner, Network, Subnet } from "./owner.mjs";
|
|
11
11
|
import { Service } from "./service.mjs";
|
|
12
12
|
import { Cluster } from "./cluster.mjs";
|
|
13
13
|
import { DNSService } from "./dns.mjs";
|
|
14
14
|
|
|
15
|
-
export class
|
|
15
|
+
export class Root extends Owner {
|
|
16
16
|
static get types() {
|
|
17
17
|
return _typesByName;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
static get typeName() {
|
|
21
|
-
return "
|
|
21
|
+
return "root";
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
#byName = new Map();
|
|
25
|
-
|
|
26
24
|
constructor(directory) {
|
|
27
25
|
super(undefined, { name: "" });
|
|
28
26
|
this.directory = directory;
|
|
29
27
|
this.addObject(this);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
_traverse(...args) {
|
|
33
|
-
if (super._traverse(...args)) {
|
|
34
|
-
for (const object of this.#byName.values()) {
|
|
35
|
-
object._traverse(...args);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
30
|
get fullName() {
|
|
45
31
|
return "";
|
|
46
32
|
}
|
|
47
33
|
|
|
48
|
-
get
|
|
34
|
+
get root() {
|
|
49
35
|
return this;
|
|
50
36
|
}
|
|
51
37
|
|
|
52
38
|
async load(name, options) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
let object = this.#byName.get(baseName);
|
|
59
|
-
|
|
60
|
-
if (!object) {
|
|
61
|
-
let path = baseName.split("/");
|
|
62
|
-
path.pop();
|
|
63
|
-
|
|
64
|
-
let data;
|
|
65
|
-
let type = options?.type;
|
|
66
|
-
if (type) {
|
|
67
|
-
data = JSON.parse(
|
|
68
|
-
await readFile(
|
|
69
|
-
join(this.directory, baseName, type.typeFileName),
|
|
70
|
-
"utf8"
|
|
71
|
-
)
|
|
72
|
-
);
|
|
73
|
-
} else {
|
|
74
|
-
for (type of _types) {
|
|
75
|
-
try {
|
|
76
|
-
data = JSON.parse(
|
|
77
|
-
await readFile(
|
|
78
|
-
join(this.directory, baseName, type.typeFileName),
|
|
79
|
-
"utf8"
|
|
80
|
-
)
|
|
81
|
-
);
|
|
82
|
-
break;
|
|
83
|
-
} catch {}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!data) {
|
|
87
|
-
return this.load(path.join("/"), options);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
39
|
+
const fullName = Base.normalizeName(name);
|
|
40
|
+
let object = this.named(fullName);
|
|
41
|
+
if (object) {
|
|
42
|
+
return object;
|
|
43
|
+
}
|
|
90
44
|
|
|
91
|
-
|
|
45
|
+
//console.log("LOAD", fullName);
|
|
92
46
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
data.name = baseName.substring(n);
|
|
47
|
+
let path = fullName.split("/");
|
|
48
|
+
path.pop();
|
|
96
49
|
|
|
97
|
-
|
|
50
|
+
let data;
|
|
51
|
+
let type = options?.type;
|
|
52
|
+
if (type) {
|
|
53
|
+
data = JSON.parse(
|
|
54
|
+
await readFile(
|
|
55
|
+
join(this.directory, fullName, type.typeFileName),
|
|
56
|
+
"utf8"
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
} else {
|
|
60
|
+
for (type of _types) {
|
|
61
|
+
try {
|
|
62
|
+
data = JSON.parse(
|
|
63
|
+
await readFile(
|
|
64
|
+
join(this.directory, fullName, type.typeFileName),
|
|
65
|
+
"utf8"
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
break;
|
|
69
|
+
} catch {}
|
|
70
|
+
}
|
|
98
71
|
|
|
99
|
-
|
|
100
|
-
|
|
72
|
+
if (!data) {
|
|
73
|
+
return this.load(path.join("/"), options);
|
|
74
|
+
}
|
|
101
75
|
}
|
|
102
76
|
|
|
77
|
+
const owner = await this.load(path.join("/"));
|
|
78
|
+
|
|
79
|
+
const length = owner.fullName.length;
|
|
80
|
+
const n = fullName[length] === "/" ? length + 1 : length;
|
|
81
|
+
data.name = fullName.substring(n);
|
|
82
|
+
|
|
83
|
+
type = await type.prepareData(this, data);
|
|
84
|
+
|
|
85
|
+
object = new type(owner, data);
|
|
86
|
+
|
|
87
|
+
this._addObject(type.typeName, fullName, object);
|
|
88
|
+
|
|
89
|
+
//console.log("FINISH LOAD", object.fullName);
|
|
90
|
+
|
|
103
91
|
return object;
|
|
104
92
|
}
|
|
105
93
|
|
|
106
94
|
async loadAll() {
|
|
107
|
-
for (let type of Object.values(
|
|
95
|
+
for (let type of Object.values(Root.types)) {
|
|
108
96
|
for await (const name of glob(type.fileNameGlob, {
|
|
109
97
|
cwd: this.directory
|
|
110
98
|
})) {
|
|
@@ -114,41 +102,6 @@ export class World extends Owner {
|
|
|
114
102
|
|
|
115
103
|
this.execFinalize();
|
|
116
104
|
}
|
|
117
|
-
|
|
118
|
-
addObject(object) {
|
|
119
|
-
this.#byName.set(object.fullName, object);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async named(name) {
|
|
123
|
-
await this.loadAll();
|
|
124
|
-
return this.#byName.get(name);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async *locations() {
|
|
128
|
-
await this.loadAll();
|
|
129
|
-
|
|
130
|
-
for (const object of this.#byName.values()) {
|
|
131
|
-
if (object instanceof Location) {
|
|
132
|
-
yield object;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async *hosts() {
|
|
138
|
-
await this.loadAll();
|
|
139
|
-
|
|
140
|
-
for (const object of this.#byName.values()) {
|
|
141
|
-
if (object instanceof Host) {
|
|
142
|
-
yield object;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async *domains() {
|
|
148
|
-
for await (const location of this.locations()) {
|
|
149
|
-
yield location.domain;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
105
|
}
|
|
153
106
|
|
|
154
107
|
export class Location extends Owner {
|
|
@@ -159,82 +112,6 @@ export class Location extends Owner {
|
|
|
159
112
|
get location() {
|
|
160
113
|
return this;
|
|
161
114
|
}
|
|
162
|
-
|
|
163
|
-
async *hosts() {
|
|
164
|
-
for await (const host of this.owner.hosts()) {
|
|
165
|
-
if (host.location === this) {
|
|
166
|
-
yield host;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export class Network extends Owner {
|
|
173
|
-
kind;
|
|
174
|
-
scope;
|
|
175
|
-
metric;
|
|
176
|
-
ipv4;
|
|
177
|
-
subnet;
|
|
178
|
-
bridge;
|
|
179
|
-
|
|
180
|
-
static get typeName() {
|
|
181
|
-
return "network";
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
constructor(owner, data) {
|
|
185
|
-
super(owner, data);
|
|
186
|
-
|
|
187
|
-
let bridge;
|
|
188
|
-
if (data.bridge) {
|
|
189
|
-
bridge = data.bridge;
|
|
190
|
-
delete data.bridge;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
Object.assign(this, data);
|
|
194
|
-
|
|
195
|
-
const subnetAddress = this.subnetAddress;
|
|
196
|
-
|
|
197
|
-
if (subnetAddress) {
|
|
198
|
-
let subnet = owner.subnet(subnetAddress);
|
|
199
|
-
if (!subnet) {
|
|
200
|
-
subnet = new Subnet(owner, { name: subnetAddress });
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
this.subnet = subnet;
|
|
204
|
-
subnet.networks.add(this);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
owner.addNetwork(this);
|
|
208
|
-
|
|
209
|
-
this.bridge = owner.addBridge(this, bridge);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
get netmask() {
|
|
213
|
-
const m = this.ipv4?.match(/\/(\d+)$/);
|
|
214
|
-
if (m) {
|
|
215
|
-
return parseInt(m[1]);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
get subnetAddress() {
|
|
220
|
-
if (this.ipv4) {
|
|
221
|
-
const [addr, bits] = this.ipv4.split(/\//);
|
|
222
|
-
const parts = addr.split(/\./);
|
|
223
|
-
return parts.slice(0, bits / 8).join(".");
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
get propertyNames() {
|
|
228
|
-
return [
|
|
229
|
-
...super.propertyNames,
|
|
230
|
-
"kind",
|
|
231
|
-
"ipv4",
|
|
232
|
-
"netmask",
|
|
233
|
-
"scope",
|
|
234
|
-
"metric",
|
|
235
|
-
"bridge"
|
|
236
|
-
];
|
|
237
|
-
}
|
|
238
115
|
}
|
|
239
116
|
|
|
240
117
|
export class Host extends Base {
|
|
@@ -256,14 +133,14 @@ export class Host extends Base {
|
|
|
256
133
|
return "host";
|
|
257
134
|
}
|
|
258
135
|
|
|
259
|
-
static async prepareData(
|
|
136
|
+
static async prepareData(root, data) {
|
|
260
137
|
if (data.location) {
|
|
261
|
-
data.location = await
|
|
138
|
+
data.location = await root.load(data.location, { type: Location });
|
|
262
139
|
}
|
|
263
140
|
|
|
264
141
|
if (data.extends) {
|
|
265
142
|
data.extends = await Promise.all(
|
|
266
|
-
asArray(data.extends).map(e =>
|
|
143
|
+
asArray(data.extends).map(e => root.load(e, { type: Host }))
|
|
267
144
|
);
|
|
268
145
|
}
|
|
269
146
|
|
|
@@ -335,7 +212,7 @@ export class Host extends Base {
|
|
|
335
212
|
new NetworkInterface(this, iface);
|
|
336
213
|
}
|
|
337
214
|
|
|
338
|
-
owner.
|
|
215
|
+
owner.addObject(this);
|
|
339
216
|
}
|
|
340
217
|
|
|
341
218
|
_traverse(...args) {
|
|
@@ -452,7 +329,7 @@ export class Host extends Base {
|
|
|
452
329
|
this.networkInterfaces[networkInterface.name] = networkInterface;
|
|
453
330
|
|
|
454
331
|
if (networkInterface.network) {
|
|
455
|
-
networkInterface.network.
|
|
332
|
+
networkInterface.network.addObject(this);
|
|
456
333
|
}
|
|
457
334
|
}
|
|
458
335
|
|
|
@@ -465,7 +342,9 @@ export class Host extends Base {
|
|
|
465
342
|
}
|
|
466
343
|
|
|
467
344
|
get ipAddresses() {
|
|
468
|
-
return [...this.networkAddresses()].map(na =>
|
|
345
|
+
return [...this.networkAddresses()].map(na =>
|
|
346
|
+
normalizeIPAddress(na.address)
|
|
347
|
+
);
|
|
469
348
|
}
|
|
470
349
|
|
|
471
350
|
get ipAddress() {
|
|
@@ -655,25 +534,5 @@ export class NetworkInterface extends Base {
|
|
|
655
534
|
}
|
|
656
535
|
}
|
|
657
536
|
|
|
658
|
-
export class Subnet extends Base {
|
|
659
|
-
networks = new Set();
|
|
660
|
-
|
|
661
|
-
static get typeName() {
|
|
662
|
-
return "subnet";
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
constructor(owner, data) {
|
|
666
|
-
super(owner, data);
|
|
667
|
-
|
|
668
|
-
Object.assign(this, data);
|
|
669
|
-
|
|
670
|
-
owner.addSubnet(this);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
get address() {
|
|
674
|
-
return this.name;
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
|
|
678
537
|
const _types = [Location, Network, Subnet, Host, Cluster, Service, DNSService];
|
|
679
538
|
const _typesByName = Object.fromEntries(_types.map(t => [t.typeName, t]));
|
package/src/owner.mjs
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { asArray, bridgeToJSON } from "./utils.mjs";
|
|
2
|
-
|
|
3
2
|
import { Base } from "./base.mjs";
|
|
4
3
|
import { DNSService } from "./dns.mjs";
|
|
5
4
|
|
|
6
5
|
export class Owner extends Base {
|
|
7
|
-
#
|
|
8
|
-
#networks = new Map();
|
|
9
|
-
#subnets = new Map();
|
|
6
|
+
#membersByType = new Map();
|
|
10
7
|
#bridges = new Set();
|
|
11
8
|
#dns;
|
|
12
9
|
#administratorEmail;
|
|
@@ -34,16 +31,16 @@ export class Owner extends Base {
|
|
|
34
31
|
}
|
|
35
32
|
}
|
|
36
33
|
Object.assign(this, data);
|
|
34
|
+
|
|
35
|
+
owner?.addObject(this);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
_traverse(...args) {
|
|
40
39
|
if (super._traverse(...args)) {
|
|
41
|
-
for (const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
for (const host of this.#hosts.values()) {
|
|
46
|
-
host._traverse(...args);
|
|
40
|
+
for (const typeSlot of this.#membersByType.values()) {
|
|
41
|
+
for (const object of typeSlot.values()) {
|
|
42
|
+
object._traverse(...args);
|
|
43
|
+
}
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
return true;
|
|
@@ -56,19 +53,44 @@ export class Owner extends Base {
|
|
|
56
53
|
return this.#dns;
|
|
57
54
|
}
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
named(name) {
|
|
57
|
+
//console.log("NAMED", this.#membersByType.keys());
|
|
58
|
+
for (const slot of this.#membersByType.values()) {
|
|
59
|
+
const object = slot.get(name);
|
|
60
|
+
if (object) {
|
|
61
|
+
return object;
|
|
62
|
+
}
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
this.
|
|
66
|
+
typeNamed(typeName, name) {
|
|
67
|
+
const typeSlot = this.#membersByType.get(typeName);
|
|
68
|
+
return typeSlot?.get(name);
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
this.#
|
|
71
|
-
|
|
71
|
+
*typeList(typeName) {
|
|
72
|
+
const typeSlot = this.#membersByType.get(typeName);
|
|
73
|
+
if (typeSlot) {
|
|
74
|
+
for (const object of typeSlot.values()) {
|
|
75
|
+
yield object;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_addObject(typeName, fullName, object) {
|
|
81
|
+
let typeSlot = this.#membersByType.get(typeName);
|
|
82
|
+
if (!typeSlot) {
|
|
83
|
+
typeSlot = new Map();
|
|
84
|
+
this.#membersByType.set(typeName, typeSlot);
|
|
85
|
+
}
|
|
86
|
+
typeSlot.set(fullName, object);
|
|
87
|
+
|
|
88
|
+
//console.log(this.toString(),"ADD", typeName, fullName, object.name, this.named(fullName)?.toString());
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
addObject(object) {
|
|
92
|
+
this.owner?.addObject(object);
|
|
93
|
+
this._addObject(object.typeName, object.fullName, object);
|
|
72
94
|
}
|
|
73
95
|
|
|
74
96
|
async service(filter) {
|
|
@@ -90,18 +112,44 @@ export class Owner extends Base {
|
|
|
90
112
|
}
|
|
91
113
|
}
|
|
92
114
|
|
|
115
|
+
locationNamed(name) {
|
|
116
|
+
return this.typeNamed("location", name);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
locations() {
|
|
120
|
+
return this.typeList("location");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
hostNamed(name) {
|
|
124
|
+
return this.typeNamed("host", name);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
hosts() {
|
|
128
|
+
return this.typeList("host");
|
|
129
|
+
}
|
|
130
|
+
|
|
93
131
|
networkNamed(name) {
|
|
94
|
-
return this
|
|
132
|
+
return this.typeNamed("network", name);
|
|
95
133
|
}
|
|
96
134
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
135
|
+
networks() {
|
|
136
|
+
return this.typeList("network");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
subnetNamed(name) {
|
|
140
|
+
return this.typeNamed("subnet", name);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
subnets() {
|
|
144
|
+
return this.typeList("subnet");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
clusterNamed(name) {
|
|
148
|
+
return this.typeNamed("cluster", name);
|
|
101
149
|
}
|
|
102
150
|
|
|
103
|
-
|
|
104
|
-
this
|
|
151
|
+
clusters() {
|
|
152
|
+
return this.typeList("cluster");
|
|
105
153
|
}
|
|
106
154
|
|
|
107
155
|
addBridge(network, destinationNetworks) {
|
|
@@ -167,33 +215,115 @@ export class Owner extends Base {
|
|
|
167
215
|
}
|
|
168
216
|
}
|
|
169
217
|
|
|
170
|
-
|
|
171
|
-
this.#
|
|
218
|
+
get administratorEmail() {
|
|
219
|
+
return this.#administratorEmail || "admin@" + this.domain;
|
|
172
220
|
}
|
|
173
221
|
|
|
174
|
-
|
|
175
|
-
|
|
222
|
+
*domains() {
|
|
223
|
+
for (const location of this.locations()) {
|
|
224
|
+
yield location.domain;
|
|
225
|
+
}
|
|
176
226
|
}
|
|
177
227
|
|
|
178
|
-
|
|
179
|
-
return
|
|
228
|
+
get propertyNames() {
|
|
229
|
+
return [...super.propertyNames, "domain", "administratorEmail", "dns"];
|
|
180
230
|
}
|
|
181
231
|
|
|
182
|
-
|
|
183
|
-
|
|
232
|
+
toJSON() {
|
|
233
|
+
const json = super.toJSON();
|
|
234
|
+
|
|
235
|
+
for (const [typeName, slot] of this.#membersByType) {
|
|
236
|
+
json[typeName] = [...slot.keys()].sort();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return json;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export class Network extends Owner {
|
|
244
|
+
kind;
|
|
245
|
+
scope;
|
|
246
|
+
metric;
|
|
247
|
+
ipv4;
|
|
248
|
+
subnet;
|
|
249
|
+
bridge;
|
|
250
|
+
|
|
251
|
+
static get typeName() {
|
|
252
|
+
return "network";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
constructor(owner, data) {
|
|
256
|
+
super(owner, data);
|
|
257
|
+
|
|
258
|
+
let bridge;
|
|
259
|
+
if (data.bridge) {
|
|
260
|
+
bridge = data.bridge;
|
|
261
|
+
delete data.bridge;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
Object.assign(this, data);
|
|
265
|
+
|
|
266
|
+
const subnetAddress = this.subnetAddress;
|
|
267
|
+
|
|
268
|
+
if (subnetAddress) {
|
|
269
|
+
let subnet = owner.subnetNamed(subnetAddress);
|
|
270
|
+
if (!subnet) {
|
|
271
|
+
subnet = new Subnet(owner, { name: subnetAddress });
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
this.subnet = subnet;
|
|
275
|
+
subnet.networks.add(this);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
owner.addObject(this);
|
|
279
|
+
|
|
280
|
+
this.bridge = owner.addBridge(this, bridge);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
get netmask() {
|
|
284
|
+
const m = this.ipv4?.match(/\/(\d+)$/);
|
|
285
|
+
if (m) {
|
|
286
|
+
return parseInt(m[1]);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
get subnetAddress() {
|
|
291
|
+
if (this.ipv4) {
|
|
292
|
+
const [addr, bits] = this.ipv4.split(/\//);
|
|
293
|
+
const parts = addr.split(/\./);
|
|
294
|
+
return parts.slice(0, bits / 8).join(".");
|
|
295
|
+
}
|
|
184
296
|
}
|
|
185
297
|
|
|
186
298
|
get propertyNames() {
|
|
187
|
-
return [
|
|
299
|
+
return [
|
|
300
|
+
...super.propertyNames,
|
|
301
|
+
"kind",
|
|
302
|
+
"ipv4",
|
|
303
|
+
"netmask",
|
|
304
|
+
"scope",
|
|
305
|
+
"metric",
|
|
306
|
+
"bridge"
|
|
307
|
+
];
|
|
188
308
|
}
|
|
309
|
+
}
|
|
189
310
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
311
|
+
export class Subnet extends Base {
|
|
312
|
+
networks = new Set();
|
|
313
|
+
|
|
314
|
+
static get typeName() {
|
|
315
|
+
return "subnet";
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
constructor(owner, data) {
|
|
319
|
+
super(owner, data);
|
|
320
|
+
|
|
321
|
+
Object.assign(this, data);
|
|
322
|
+
|
|
323
|
+
owner.addObject(this);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
get address() {
|
|
327
|
+
return this.name;
|
|
198
328
|
}
|
|
199
329
|
}
|
package/src/service.mjs
CHANGED
package/types/base.d.mts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
export function extractFrom(object: any, propertyNames: any): {};
|
|
2
2
|
export class Base {
|
|
3
3
|
static get typeName(): string;
|
|
4
|
+
static get pluralTypeName(): string;
|
|
5
|
+
static get nameLookupName(): string;
|
|
4
6
|
static get typeFileName(): string;
|
|
5
7
|
static get fileNameGlob(): string;
|
|
6
|
-
static prepareData(
|
|
7
|
-
static
|
|
8
|
+
static prepareData(root: any, data: any): Promise<typeof Base>;
|
|
9
|
+
static normalizeName(name: any): any;
|
|
8
10
|
constructor(owner: any, data: any);
|
|
9
11
|
owner: any;
|
|
10
12
|
name: any;
|
|
11
13
|
description: any;
|
|
12
14
|
withOwner(owner: any): any;
|
|
13
15
|
get typeName(): any;
|
|
14
|
-
get
|
|
16
|
+
get root(): any;
|
|
15
17
|
get location(): any;
|
|
16
18
|
get host(): any;
|
|
17
19
|
get network(): any;
|
package/types/cmd.d.mts
CHANGED
package/types/model.d.mts
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class Root extends Owner {
|
|
2
2
|
static get types(): {
|
|
3
|
-
[k: string]: typeof DNSService | typeof
|
|
3
|
+
[k: string]: typeof DNSService | typeof Subnet | typeof Cluster | typeof Service | typeof Host;
|
|
4
4
|
};
|
|
5
5
|
constructor(directory: any);
|
|
6
6
|
get fullName(): string;
|
|
7
|
-
get
|
|
7
|
+
get root(): this;
|
|
8
8
|
load(name: any, options: any): any;
|
|
9
9
|
loadAll(): Promise<void>;
|
|
10
|
-
named(name: any): Promise<any>;
|
|
11
|
-
locations(): AsyncGenerator<Location, void, unknown>;
|
|
12
|
-
hosts(): AsyncGenerator<Host, void, unknown>;
|
|
13
|
-
domains(): AsyncGenerator<any, void, unknown>;
|
|
14
|
-
#private;
|
|
15
10
|
}
|
|
16
11
|
export class Location extends Owner {
|
|
17
12
|
get location(): this;
|
|
18
13
|
}
|
|
19
|
-
export class Network extends Owner {
|
|
20
|
-
kind: any;
|
|
21
|
-
scope: any;
|
|
22
|
-
metric: any;
|
|
23
|
-
ipv4: any;
|
|
24
|
-
subnet: any;
|
|
25
|
-
bridge: any;
|
|
26
|
-
get netmask(): number;
|
|
27
|
-
get subnetAddress(): any;
|
|
28
|
-
}
|
|
29
14
|
export class Host extends Base {
|
|
30
|
-
static prepareData(
|
|
15
|
+
static prepareData(root: any, data: any): Promise<typeof Host>;
|
|
31
16
|
networkInterfaces: {};
|
|
32
17
|
postinstall: any[];
|
|
33
18
|
_traverse(...args: any[]): boolean;
|
|
@@ -81,12 +66,9 @@ export class NetworkInterface extends Base {
|
|
|
81
66
|
get kind(): any;
|
|
82
67
|
#private;
|
|
83
68
|
}
|
|
84
|
-
export class Subnet extends Base {
|
|
85
|
-
networks: Set<any>;
|
|
86
|
-
get address(): any;
|
|
87
|
-
}
|
|
88
69
|
import { Owner } from "./owner.mjs";
|
|
89
70
|
import { DNSService } from "./dns.mjs";
|
|
71
|
+
import { Subnet } from "./owner.mjs";
|
|
90
72
|
import { Cluster } from "./cluster.mjs";
|
|
91
73
|
import { Service } from "./service.mjs";
|
|
92
74
|
import { Base } from "./base.mjs";
|
package/types/owner.d.mts
CHANGED
|
@@ -5,27 +5,42 @@ export class Owner extends Base {
|
|
|
5
5
|
};
|
|
6
6
|
_traverse(...args: any[]): boolean;
|
|
7
7
|
get dns(): DNSService;
|
|
8
|
-
|
|
8
|
+
named(name: any): any;
|
|
9
|
+
typeNamed(typeName: any, name: any): any;
|
|
10
|
+
typeList(typeName: any): Generator<any, void, unknown>;
|
|
11
|
+
_addObject(typeName: any, fullName: any, object: any): void;
|
|
9
12
|
addObject(object: any): void;
|
|
10
|
-
addHost(host: any): void;
|
|
11
13
|
service(filter: any): Promise<any>;
|
|
12
14
|
services(filter: any): AsyncGenerator<any, void, unknown>;
|
|
15
|
+
locationNamed(name: any): any;
|
|
16
|
+
locations(): Generator<any, void, unknown>;
|
|
17
|
+
hostNamed(name: any): any;
|
|
18
|
+
hosts(): Generator<any, void, unknown>;
|
|
13
19
|
networkNamed(name: any): any;
|
|
14
|
-
networks():
|
|
15
|
-
|
|
20
|
+
networks(): Generator<any, void, unknown>;
|
|
21
|
+
subnetNamed(name: any): any;
|
|
22
|
+
subnets(): Generator<any, void, unknown>;
|
|
23
|
+
clusterNamed(name: any): any;
|
|
24
|
+
clusters(): Generator<any, void, unknown>;
|
|
16
25
|
addBridge(network: any, destinationNetworks: any): any;
|
|
17
26
|
_resolveBridges(): void;
|
|
18
27
|
networkAddresses(): AsyncGenerator<any, void, unknown>;
|
|
19
|
-
|
|
20
|
-
subnet(name: any): any;
|
|
21
|
-
subnets(): MapIterator<any>;
|
|
22
|
-
toJSON(): {
|
|
23
|
-
networks: any[];
|
|
24
|
-
subnets: any[];
|
|
25
|
-
bridges: any[][];
|
|
26
|
-
hosts: any[];
|
|
27
|
-
};
|
|
28
|
+
domains(): Generator<any, void, unknown>;
|
|
28
29
|
#private;
|
|
29
30
|
}
|
|
31
|
+
export class Network extends Owner {
|
|
32
|
+
kind: any;
|
|
33
|
+
scope: any;
|
|
34
|
+
metric: any;
|
|
35
|
+
ipv4: any;
|
|
36
|
+
subnet: any;
|
|
37
|
+
bridge: any;
|
|
38
|
+
get netmask(): number;
|
|
39
|
+
get subnetAddress(): any;
|
|
40
|
+
}
|
|
41
|
+
export class Subnet extends Base {
|
|
42
|
+
networks: Set<any>;
|
|
43
|
+
get address(): any;
|
|
44
|
+
}
|
|
30
45
|
import { Base } from "./base.mjs";
|
|
31
46
|
import { DNSService } from "./dns.mjs";
|