pmcf 1.52.1 → 1.52.3
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 +6 -156
- package/package.json +3 -2
- package/src/host-utils.mjs +157 -0
- package/src/host.mjs +5 -3
- package/types/host-utils.d.mts +4 -0
package/bin/pmcf-host-defs
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { writeFile, mkdir, copyFile, glob, chmod } from "node:fs/promises";
|
|
4
3
|
import { join } from "node:path";
|
|
5
4
|
import { types } from "pmcf";
|
|
6
|
-
import { writeLines, sectionLines } from "../src/utils.mjs";
|
|
7
5
|
import { prepare } from "../src/cmd.mjs";
|
|
6
|
+
import {
|
|
7
|
+
generateNetworkDefs,
|
|
8
|
+
generateMachineInfo,
|
|
9
|
+
copySshKeys,
|
|
10
|
+
generateKnownHosts
|
|
11
|
+
} from "../src/host-utils.mjs";
|
|
8
12
|
|
|
9
13
|
const { root, args, options } = await prepare();
|
|
10
14
|
|
|
@@ -25,157 +29,3 @@ console.log("depends", `location-${host.location.name}`, ...host.depends);
|
|
|
25
29
|
console.log("replaces", `mf-${host.hostName}`, ...host.replaces);
|
|
26
30
|
console.log("description", `host definitions for ${host.domainName}`);
|
|
27
31
|
console.log("backup", "root/.ssh/known_hosts");
|
|
28
|
-
|
|
29
|
-
async function generateMachineInfo(host, dir) {
|
|
30
|
-
const etcDir = join(dir, "etc");
|
|
31
|
-
await writeLines(
|
|
32
|
-
etcDir,
|
|
33
|
-
"machine-info",
|
|
34
|
-
Object.entries({
|
|
35
|
-
CHASSIS: host.chassis,
|
|
36
|
-
DEPLOYMENT: host.deployment,
|
|
37
|
-
LOCATION: host.location.name,
|
|
38
|
-
HARDWARE_VENDOR: host.vendor,
|
|
39
|
-
HARDWARE_MODEL: host.modelName
|
|
40
|
-
}).map(([k, v]) => `${k}=${v}`)
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
await writeLines(etcDir, "machine-id", host["machine-id"]);
|
|
44
|
-
await writeLines(etcDir, "hostname", host.hostName);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function generateNetworkDefs(host, dir) {
|
|
48
|
-
const networkDir = join(dir, "etc/systemd/network");
|
|
49
|
-
|
|
50
|
-
for (const ni of host.networkInterfaces.values()) {
|
|
51
|
-
if (ni.name !== "eth0" && ni.hwaddr) {
|
|
52
|
-
await writeLines(networkDir, `${ni.name}.link`, [
|
|
53
|
-
sectionLines("Match", { MACAddress: ni.hwaddr }),
|
|
54
|
-
"",
|
|
55
|
-
sectionLines("Link", { Name: ni.name })
|
|
56
|
-
]);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const networkSections = [sectionLines("Match", { Name: ni.name })];
|
|
60
|
-
|
|
61
|
-
for (const Address of ni.cidrAddresses) {
|
|
62
|
-
networkSections.push(
|
|
63
|
-
"",
|
|
64
|
-
sectionLines("Address", {
|
|
65
|
-
Address
|
|
66
|
-
})
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
switch (ni.kind) {
|
|
71
|
-
case "ethernet":
|
|
72
|
-
case "wifi":
|
|
73
|
-
const routeSectionExtra = ni.destination
|
|
74
|
-
? { Destination: ni.destination }
|
|
75
|
-
: { Gateway: ni.gatewayAddress };
|
|
76
|
-
|
|
77
|
-
const networkSectionExtra = ni.arpbridge
|
|
78
|
-
? {
|
|
79
|
-
IPForward: "yes",
|
|
80
|
-
IPv4ProxyARP: "yes"
|
|
81
|
-
}
|
|
82
|
-
: {};
|
|
83
|
-
|
|
84
|
-
networkSections.push(
|
|
85
|
-
"",
|
|
86
|
-
sectionLines("Network", {
|
|
87
|
-
...networkSectionExtra,
|
|
88
|
-
DHCP: "no",
|
|
89
|
-
DHCPServer: "no",
|
|
90
|
-
MulticastDNS: "yes",
|
|
91
|
-
LinkLocalAddressing: "ipv6",
|
|
92
|
-
IPv6LinkLocalAddressGenerationMode: "stable-privacy"
|
|
93
|
-
}),
|
|
94
|
-
"",
|
|
95
|
-
sectionLines("Route", {
|
|
96
|
-
...routeSectionExtra,
|
|
97
|
-
Scope: ni.scope,
|
|
98
|
-
Metric: ni.metric,
|
|
99
|
-
InitialCongestionWindow: 20,
|
|
100
|
-
InitialAdvertisedReceiveWindow: 20
|
|
101
|
-
}),
|
|
102
|
-
"",
|
|
103
|
-
sectionLines("IPv6AcceptRA", {
|
|
104
|
-
UseAutonomousPrefix: "true",
|
|
105
|
-
UseOnLinkPrefix: "true",
|
|
106
|
-
DHCPv6Client: "false",
|
|
107
|
-
Token: "eui64"
|
|
108
|
-
})
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
if (ni.arpbridge) {
|
|
112
|
-
networkSections.push(
|
|
113
|
-
"",
|
|
114
|
-
sectionLines("Link", { Promiscuous: "yes" })
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
await writeLines(networkDir, `${ni.name}.network`, networkSections);
|
|
120
|
-
|
|
121
|
-
switch (ni?.kind) {
|
|
122
|
-
case "wireguard":
|
|
123
|
-
{
|
|
124
|
-
}
|
|
125
|
-
break;
|
|
126
|
-
case "wifi": {
|
|
127
|
-
const d = join(dir, "etc/wpa_supplicant");
|
|
128
|
-
await mkdir(d, { recursive: true });
|
|
129
|
-
writeFile(
|
|
130
|
-
join(d, `wpa_supplicant-${ni.name}.conf`),
|
|
131
|
-
`country=${host.location.country}
|
|
132
|
-
ctrl_interface=DIR=/run/wpa_supplicant GROUP=netdev
|
|
133
|
-
update_config=1
|
|
134
|
-
p2p_disabled=1
|
|
135
|
-
network={
|
|
136
|
-
ssid="${ni.ssid}"
|
|
137
|
-
psk=${ni.psk}
|
|
138
|
-
scan_ssid=1
|
|
139
|
-
}`,
|
|
140
|
-
"utf8"
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
host.postinstall.push(
|
|
144
|
-
`systemctl enable wpa_supplicant@${ni.name}.service`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async function copySshKeys(host, dir) {
|
|
152
|
-
const sshDir = join(dir, "etc", "ssh");
|
|
153
|
-
|
|
154
|
-
await mkdir(sshDir, { recursive: true });
|
|
155
|
-
|
|
156
|
-
for await (const file of glob("ssh_host_*", { cwd: host.directory })) {
|
|
157
|
-
const destinationFileName = join(sshDir, file);
|
|
158
|
-
await copyFile(join(host.directory, file), destinationFileName);
|
|
159
|
-
await chmod(
|
|
160
|
-
destinationFileName,
|
|
161
|
-
destinationFileName.endsWith(".pub") ? 0o0644 : 0o0600
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async function generateKnownHosts(hosts, dir) {
|
|
167
|
-
const keys = [];
|
|
168
|
-
for await (const host of hosts) {
|
|
169
|
-
try {
|
|
170
|
-
const [alg, key, desc] = (await host.publicKey("ed25519")).split(/\s+/);
|
|
171
|
-
|
|
172
|
-
keys.push(`${host.domainName} ${alg} ${key}`);
|
|
173
|
-
|
|
174
|
-
for await (const addr of host.networkAddresses()) {
|
|
175
|
-
keys.push(`${addr.address} ${alg} ${key}`);
|
|
176
|
-
}
|
|
177
|
-
} catch {}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
await writeLines(dir, "known_hosts", keys);
|
|
181
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmcf",
|
|
3
|
-
"version": "1.52.
|
|
3
|
+
"version": "1.52.3",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"lint:typescript": "tsc --allowJs --checkJs --noEmit --resolveJsonModule --target es2024 --lib esnext -m esnext --module nodenext --moduleResolution nodenext ./src**/*.mjs"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"npm-pkgbuild": "^16.0.1",
|
|
43
44
|
"pacc": "^3.3.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"c8": "^10.1.3",
|
|
49
50
|
"documentation": "^14.0.3",
|
|
50
51
|
"semantic-release": "^24.2.3",
|
|
51
|
-
"typescript": "^5.
|
|
52
|
+
"typescript": "^5.8.2"
|
|
52
53
|
},
|
|
53
54
|
"engines": {
|
|
54
55
|
"node": ">=22.14.0"
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { writeFile, mkdir, copyFile, glob, chmod } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { writeLines, sectionLines } from "../src/utils.mjs";
|
|
4
|
+
|
|
5
|
+
export async function generateMachineInfo(host, dir) {
|
|
6
|
+
const etcDir = join(dir, "etc");
|
|
7
|
+
await writeLines(
|
|
8
|
+
etcDir,
|
|
9
|
+
"machine-info",
|
|
10
|
+
Object.entries({
|
|
11
|
+
CHASSIS: host.chassis,
|
|
12
|
+
DEPLOYMENT: host.deployment,
|
|
13
|
+
LOCATION: host.location.name,
|
|
14
|
+
HARDWARE_VENDOR: host.vendor,
|
|
15
|
+
HARDWARE_MODEL: host.modelName
|
|
16
|
+
}).map(([k, v]) => `${k}=${v}`)
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
await writeLines(etcDir, "machine-id", host["machine-id"]);
|
|
20
|
+
await writeLines(etcDir, "hostname", host.hostName);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function generateNetworkDefs(host, dir) {
|
|
24
|
+
const networkDir = join(dir, "etc/systemd/network");
|
|
25
|
+
|
|
26
|
+
for (const ni of host.networkInterfaces.values()) {
|
|
27
|
+
if (ni.name !== "eth0" && ni.hwaddr) {
|
|
28
|
+
await writeLines(networkDir, `${ni.name}.link`, [
|
|
29
|
+
sectionLines("Match", { MACAddress: ni.hwaddr }),
|
|
30
|
+
"",
|
|
31
|
+
sectionLines("Link", { Name: ni.name })
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const networkSections = [sectionLines("Match", { Name: ni.name })];
|
|
36
|
+
|
|
37
|
+
for (const Address of ni.cidrAddresses) {
|
|
38
|
+
networkSections.push(
|
|
39
|
+
"",
|
|
40
|
+
sectionLines("Address", {
|
|
41
|
+
Address
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
switch (ni.kind) {
|
|
47
|
+
case "ethernet":
|
|
48
|
+
case "wifi":
|
|
49
|
+
const routeSectionExtra = ni.destination
|
|
50
|
+
? { Destination: ni.destination }
|
|
51
|
+
: { Gateway: ni.gatewayAddress };
|
|
52
|
+
|
|
53
|
+
const networkSectionExtra = ni.arpbridge
|
|
54
|
+
? {
|
|
55
|
+
IPForward: "yes",
|
|
56
|
+
IPv4ProxyARP: "yes"
|
|
57
|
+
}
|
|
58
|
+
: {};
|
|
59
|
+
|
|
60
|
+
networkSections.push(
|
|
61
|
+
"",
|
|
62
|
+
sectionLines("Network", {
|
|
63
|
+
...networkSectionExtra,
|
|
64
|
+
DHCP: "no",
|
|
65
|
+
DHCPServer: "no",
|
|
66
|
+
MulticastDNS: "yes",
|
|
67
|
+
LinkLocalAddressing: "ipv6",
|
|
68
|
+
IPv6LinkLocalAddressGenerationMode: "stable-privacy"
|
|
69
|
+
}),
|
|
70
|
+
"",
|
|
71
|
+
sectionLines("Route", {
|
|
72
|
+
...routeSectionExtra,
|
|
73
|
+
Scope: ni.scope,
|
|
74
|
+
Metric: ni.metric,
|
|
75
|
+
InitialCongestionWindow: 20,
|
|
76
|
+
InitialAdvertisedReceiveWindow: 20
|
|
77
|
+
}),
|
|
78
|
+
"",
|
|
79
|
+
sectionLines("IPv6AcceptRA", {
|
|
80
|
+
UseAutonomousPrefix: "true",
|
|
81
|
+
UseOnLinkPrefix: "true",
|
|
82
|
+
DHCPv6Client: "false",
|
|
83
|
+
Token: "eui64"
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (ni.arpbridge) {
|
|
88
|
+
networkSections.push(
|
|
89
|
+
"",
|
|
90
|
+
sectionLines("Link", { Promiscuous: "yes" })
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await writeLines(networkDir, `${ni.name}.network`, networkSections);
|
|
96
|
+
|
|
97
|
+
switch (ni?.kind) {
|
|
98
|
+
case "wireguard":
|
|
99
|
+
{
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
case "wifi": {
|
|
103
|
+
const d = join(dir, "etc/wpa_supplicant");
|
|
104
|
+
await mkdir(d, { recursive: true });
|
|
105
|
+
writeFile(
|
|
106
|
+
join(d, `wpa_supplicant-${ni.name}.conf`),
|
|
107
|
+
`country=${host.location.country}
|
|
108
|
+
ctrl_interface=DIR=/run/wpa_supplicant GROUP=netdev
|
|
109
|
+
update_config=1
|
|
110
|
+
p2p_disabled=1
|
|
111
|
+
network={
|
|
112
|
+
ssid="${ni.ssid}"
|
|
113
|
+
psk=${ni.psk}
|
|
114
|
+
scan_ssid=1
|
|
115
|
+
}`,
|
|
116
|
+
"utf8"
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
host.postinstall.push(
|
|
120
|
+
`systemctl enable wpa_supplicant@${ni.name}.service`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function copySshKeys(host, dir) {
|
|
128
|
+
const sshDir = join(dir, "etc", "ssh");
|
|
129
|
+
|
|
130
|
+
await mkdir(sshDir, { recursive: true });
|
|
131
|
+
|
|
132
|
+
for await (const file of glob("ssh_host_*", { cwd: host.directory })) {
|
|
133
|
+
const destinationFileName = join(sshDir, file);
|
|
134
|
+
await copyFile(join(host.directory, file), destinationFileName);
|
|
135
|
+
await chmod(
|
|
136
|
+
destinationFileName,
|
|
137
|
+
destinationFileName.endsWith(".pub") ? 0o0644 : 0o0600
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function generateKnownHosts(hosts, dir) {
|
|
143
|
+
const keys = [];
|
|
144
|
+
for await (const host of hosts) {
|
|
145
|
+
try {
|
|
146
|
+
const [alg, key, desc] = (await host.publicKey("ed25519")).split(/\s+/);
|
|
147
|
+
|
|
148
|
+
keys.push(`${host.domainName} ${alg} ${key}`);
|
|
149
|
+
|
|
150
|
+
for await (const addr of host.networkAddresses()) {
|
|
151
|
+
keys.push(`${addr.address} ${alg} ${key}`);
|
|
152
|
+
}
|
|
153
|
+
} catch {}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
await writeLines(dir, "known_hosts", keys);
|
|
157
|
+
}
|
package/src/host.mjs
CHANGED
|
@@ -89,9 +89,11 @@ export class Host extends Base {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
if (!this.isTemplate) {
|
|
93
|
+
this.#depends = this.expand(this.depends);
|
|
94
|
+
this.#provides = this.expand(this.provides);
|
|
95
|
+
this.#replaces = this.expand(this.replaces);
|
|
96
|
+
}
|
|
95
97
|
});
|
|
96
98
|
}
|
|
97
99
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export function generateMachineInfo(host: any, dir: any): Promise<void>;
|
|
2
|
+
export function generateNetworkDefs(host: any, dir: any): Promise<void>;
|
|
3
|
+
export function copySshKeys(host: any, dir: any): Promise<void>;
|
|
4
|
+
export function generateKnownHosts(hosts: any, dir: any): Promise<void>;
|