pmcf 1.52.2 → 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.
@@ -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.2",
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.7.3"
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
+ }
@@ -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>;