ramm 0.0.27 → 0.0.29
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/dist/ramm.js +67 -67
- package/dist/types/base/base.d.ts +28 -11
- package/dist/types/base/tee.d.ts +2 -3
- package/dist/types/podman.d.ts +2 -2
- package/dist/types/print.d.ts +3 -0
- package/dist/types/ramm.d.ts +1 -1
- package/package.json +1 -1
package/dist/ramm.js
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
// src/base/base.ts
|
|
3
3
|
var {spawn } = globalThis.Bun;
|
|
4
4
|
|
|
5
|
-
// src/
|
|
6
|
-
var
|
|
7
|
-
console.info(
|
|
5
|
+
// src/print.ts
|
|
6
|
+
var printInternal = (left, right) => {
|
|
7
|
+
console.info(`\x1B[32m${left}:\x1B[0m \x1B[38;5;85m${right}\x1B[0m`);
|
|
8
8
|
};
|
|
9
|
-
var
|
|
10
|
-
|
|
9
|
+
var printCommand = (command) => {
|
|
10
|
+
printInternal("Command", command);
|
|
11
11
|
};
|
|
12
|
-
var
|
|
13
|
-
|
|
12
|
+
var printFunction = (func) => {
|
|
13
|
+
printInternal("Function", func);
|
|
14
14
|
};
|
|
15
|
-
var
|
|
16
|
-
|
|
15
|
+
var printBlock = (name) => {
|
|
16
|
+
console.info(`\x1B[34mBlock:\x1B[0m \x1B[38;5;81m${name}\x1B[0m`);
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
// src/context.ts
|
|
@@ -43,32 +43,36 @@ class Context {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// src/base/tee.ts
|
|
46
|
-
var tee = async (read) => {
|
|
46
|
+
var tee = async (read, write, prefix) => {
|
|
47
47
|
const reader = read.getReader();
|
|
48
|
+
let leftover = "";
|
|
48
49
|
let output = "";
|
|
50
|
+
const decoder = new TextDecoder("utf-8");
|
|
49
51
|
while (true) {
|
|
50
|
-
const { value, done
|
|
51
|
-
if (
|
|
52
|
+
const { value, done } = await reader.read();
|
|
53
|
+
if (done) {
|
|
54
|
+
if (leftover)
|
|
55
|
+
write(prefix + leftover + `
|
|
56
|
+
`);
|
|
52
57
|
return output;
|
|
53
58
|
}
|
|
54
|
-
const
|
|
55
|
-
output +=
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
while (true) {
|
|
63
|
-
const { value, done: doneReading } = await reader.read();
|
|
64
|
-
if (doneReading) {
|
|
65
|
-
return output;
|
|
59
|
+
const decodedOutput = decoder.decode(value, { stream: true });
|
|
60
|
+
output += decodedOutput;
|
|
61
|
+
const lines = (leftover + decodedOutput).split(`
|
|
62
|
+
`);
|
|
63
|
+
leftover = lines.pop() ?? "";
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
write(prefix + line + `
|
|
66
|
+
`);
|
|
66
67
|
}
|
|
67
|
-
const decoder = new TextDecoder("utf-8");
|
|
68
|
-
output += decoder.decode(value);
|
|
69
|
-
process.stderr.write(value);
|
|
70
68
|
}
|
|
71
69
|
};
|
|
70
|
+
var teeStdout = (read, prefix) => {
|
|
71
|
+
return tee(read, (text) => process.stdout.write(text), prefix);
|
|
72
|
+
};
|
|
73
|
+
var teeStderr = (read, prefix) => {
|
|
74
|
+
return tee(read, (text) => process.stderr.write(text), prefix);
|
|
75
|
+
};
|
|
72
76
|
|
|
73
77
|
// src/base/base.ts
|
|
74
78
|
var defaultContext = new Context({
|
|
@@ -77,29 +81,36 @@ var defaultContext = new Context({
|
|
|
77
81
|
userspace: false,
|
|
78
82
|
sudo: false
|
|
79
83
|
});
|
|
80
|
-
var
|
|
81
|
-
|
|
82
|
-
const result = spawn(["bash", "-c", command], {
|
|
84
|
+
var execCommandRaw = async (command, { store = {}, signal, env, cwd, prefix = "" } = {}) => {
|
|
85
|
+
const spawnResult = spawn(["bash", "-c", command], {
|
|
83
86
|
stdin: "inherit",
|
|
84
87
|
stdout: "pipe",
|
|
85
|
-
stderr: "pipe"
|
|
88
|
+
stderr: "pipe",
|
|
89
|
+
signal,
|
|
90
|
+
cwd,
|
|
91
|
+
env
|
|
86
92
|
});
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
store.spawnResult = spawnResult;
|
|
94
|
+
const [stdout, stderr] = await Promise.all([
|
|
95
|
+
teeStdout(spawnResult.stdout, prefix),
|
|
96
|
+
teeStderr(spawnResult.stderr, prefix)
|
|
90
97
|
]);
|
|
91
|
-
await
|
|
98
|
+
await spawnResult.exited;
|
|
92
99
|
return {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
spawnResult
|
|
100
|
+
stderr,
|
|
101
|
+
stdout,
|
|
102
|
+
spawnResult
|
|
96
103
|
};
|
|
97
104
|
};
|
|
98
|
-
var
|
|
99
|
-
|
|
105
|
+
var execCommandMayError = async (command, props) => {
|
|
106
|
+
printCommand(command);
|
|
107
|
+
return execCommandRaw(command, props);
|
|
108
|
+
};
|
|
109
|
+
var execCommand = async (command, props) => {
|
|
110
|
+
const result = await execCommandMayError(command, props);
|
|
100
111
|
if (result.spawnResult.exitCode !== 0) {
|
|
101
|
-
console.error(
|
|
102
|
-
console.error(
|
|
112
|
+
console.error(`Error exit code:" ${result.spawnResult.exitCode}`);
|
|
113
|
+
console.error(`Command: ${command}`);
|
|
103
114
|
throw new Error(command);
|
|
104
115
|
}
|
|
105
116
|
return result;
|
|
@@ -148,6 +159,7 @@ var stopSystemdService = async (constext, name) => {
|
|
|
148
159
|
await execCommand(formatUserspace(constext, `systemctl stop ${name}`));
|
|
149
160
|
};
|
|
150
161
|
var restartSystemdService = async (name, constext = defaultContext) => {
|
|
162
|
+
printFunction(`restartSystemdService ${name}`);
|
|
151
163
|
await execCommand(formatUserspace(constext, `systemctl restart ${name}`));
|
|
152
164
|
};
|
|
153
165
|
var checkSystemdService = async (context, serviceName) => {
|
|
@@ -155,6 +167,7 @@ var checkSystemdService = async (context, serviceName) => {
|
|
|
155
167
|
return spawnResult.exitCode === 0;
|
|
156
168
|
};
|
|
157
169
|
var createSystemdService = async (context, serviceName, pathToServiceFile) => {
|
|
170
|
+
printFunction(`createSystemdService ${serviceName}`);
|
|
158
171
|
const pathToSeviceTarget = getSystemdPathToService(context, serviceName);
|
|
159
172
|
await execCommand(`cp -v ${pathToServiceFile} ${pathToSeviceTarget}`);
|
|
160
173
|
await execCommand(formatUserspace(context, "systemctl daemon-reload"));
|
|
@@ -172,10 +185,10 @@ var installPodman = async () => {
|
|
|
172
185
|
var createNetwork = async () => {
|
|
173
186
|
const netwroks = await execCommand("podman network inspect $(podman network ls -q) -f '{{.NetworkInterface}}'");
|
|
174
187
|
const podmanNetworks = await execCommand("podman network ls");
|
|
175
|
-
if (podmanNetworks.
|
|
188
|
+
if (podmanNetworks.stdout.includes("ramm")) {
|
|
176
189
|
return;
|
|
177
190
|
}
|
|
178
|
-
if (netwroks.
|
|
191
|
+
if (netwroks.stdout.includes("podman_ramm")) {
|
|
179
192
|
return;
|
|
180
193
|
}
|
|
181
194
|
await execCommand("podman network create --interface-name=podman_ramm ramm");
|
|
@@ -206,7 +219,7 @@ var runPodmanContainerService = async (name, command, context = defaultContext)
|
|
|
206
219
|
};
|
|
207
220
|
var addNftPodmanRule = async () => {
|
|
208
221
|
const podmanNetworksResult = await execCommand("podman network inspect $(podman network ls -q) -f '{{.NetworkInterface}}'");
|
|
209
|
-
const podmanNetworks = podmanNetworksResult.
|
|
222
|
+
const podmanNetworks = podmanNetworksResult.stdout.trim().split(`
|
|
210
223
|
`);
|
|
211
224
|
await execCommand(`nft add set inet ramm podman_interfaces '{ type ifname; flags dynamic; elements = { ${podmanNetworks.join(", ")} }; }'`);
|
|
212
225
|
await execCommand("nft insert rule inet ramm prerouting iifname @podman_interfaces accept");
|
|
@@ -247,10 +260,7 @@ var createNftTable = ({ allowedIpV4 }) => {
|
|
|
247
260
|
var setupNftable = async ({
|
|
248
261
|
allowedIpV4
|
|
249
262
|
}) => {
|
|
250
|
-
|
|
251
|
-
if (listTable.spawnResult.exitCode === 0) {
|
|
252
|
-
await execCommand("nft delete table inet ramm");
|
|
253
|
-
}
|
|
263
|
+
await execCommand("nft flush ruleset");
|
|
254
264
|
const nftTable = createNftTable({ allowedIpV4 });
|
|
255
265
|
await execCommand(`nft -f - <<EOF
|
|
256
266
|
${nftTable}
|
|
@@ -287,7 +297,6 @@ var normalizeFileContent = (str) => {
|
|
|
287
297
|
};
|
|
288
298
|
var createDir = async (str) => {
|
|
289
299
|
const dirname = str.split("/").slice(0, -1).join("/");
|
|
290
|
-
debugApiCall(`exists(${dirname})`);
|
|
291
300
|
const exist = await exists(dirname);
|
|
292
301
|
if (exist) {
|
|
293
302
|
return;
|
|
@@ -296,11 +305,9 @@ var createDir = async (str) => {
|
|
|
296
305
|
};
|
|
297
306
|
var checkStrInFile = async (filePath, str) => {
|
|
298
307
|
const file2 = Bun.file(filePath);
|
|
299
|
-
debugApiCall(`file(${filePath}).exists())`);
|
|
300
308
|
if (!await file2.exists()) {
|
|
301
309
|
return false;
|
|
302
310
|
}
|
|
303
|
-
debugApiCall(`file(${filePath}).text()`);
|
|
304
311
|
const fileText = await file2.text();
|
|
305
312
|
if (fileText.includes(str)) {
|
|
306
313
|
return true;
|
|
@@ -310,7 +317,6 @@ var checkStrInFile = async (filePath, str) => {
|
|
|
310
317
|
var createFileIfNeed = async (rawFilePath) => {
|
|
311
318
|
const filePath = normalizePath(rawFilePath);
|
|
312
319
|
await createDir(filePath);
|
|
313
|
-
debugApiCall(`file(${filePath}).exists())`);
|
|
314
320
|
if (!await file(filePath).exists()) {
|
|
315
321
|
await execCommand(`touch ${filePath}`);
|
|
316
322
|
}
|
|
@@ -321,24 +327,20 @@ var writeIfNew = async (rawFilePath, str) => {
|
|
|
321
327
|
if (await checkStrInFile(filePath, str)) {
|
|
322
328
|
return;
|
|
323
329
|
}
|
|
324
|
-
debugApiCall(`appendFile(${filePath})`);
|
|
325
330
|
await appendFile(filePath, normalizeFileContent(str));
|
|
326
331
|
};
|
|
327
332
|
var writeFile = async (pathToFile, str) => {
|
|
328
333
|
const normalizedPath = normalizePath(pathToFile);
|
|
329
334
|
await createFileIfNeed(normalizedPath);
|
|
330
|
-
debugApiCall(`write(${normalizedPath})`);
|
|
331
335
|
await write(normalizedPath, str);
|
|
332
336
|
};
|
|
333
337
|
var writeIfNewCompletely = async (pathToFile, str) => {
|
|
334
338
|
const normalizedPath = normalizePath(pathToFile);
|
|
335
339
|
await createFileIfNeed(normalizedPath);
|
|
336
|
-
debugApiCall(`file(${normalizedPath}).text()`);
|
|
337
340
|
const fileText = await file(normalizedPath).text();
|
|
338
341
|
if (fileText === str) {
|
|
339
342
|
return;
|
|
340
343
|
}
|
|
341
|
-
debugApiCall(`write(${normalizedPath})`);
|
|
342
344
|
await write(normalizedPath, str);
|
|
343
345
|
};
|
|
344
346
|
// src/ssh.ts
|
|
@@ -351,29 +353,27 @@ var addKeyToHostConfig = async (pathToHost, address, pathToKey) => {
|
|
|
351
353
|
await writeIfNew(pathToHost, text);
|
|
352
354
|
};
|
|
353
355
|
var getServerFingerprintBySsh = async (context) => {
|
|
354
|
-
const {
|
|
355
|
-
return
|
|
356
|
+
const { stdout } = await execBySsh('ssh-keyscan -t ed25519 localhost | grep -v "^#"', context);
|
|
357
|
+
return stdout.replace("localhost", context.domain);
|
|
356
358
|
};
|
|
357
359
|
async function createSshKey(pathToKey, comment) {
|
|
360
|
+
printFunction(createSshKey.name);
|
|
358
361
|
const name = pathToKey.split("/").at(-1);
|
|
359
362
|
const pathToKeyPub = `${pathToKey}.pub`;
|
|
360
363
|
const pathToDir = pathToKey.split("/").slice(0, -1).join("/");
|
|
361
364
|
const pathToKeyFile = file2(pathToKey);
|
|
362
365
|
const pathToKeyPubFile = file2(pathToKeyPub);
|
|
363
|
-
debugApiCall(`file(${pathToKey}).exist()`);
|
|
364
|
-
debugApiCall(`file(${pathToKeyPub}).exist()`);
|
|
365
366
|
if (await pathToKeyFile.exists() && await pathToKeyPubFile.exists()) {
|
|
366
367
|
return await pathToKeyPubFile.text();
|
|
367
368
|
}
|
|
368
369
|
await execCommand(`mkdir -p ${pathToDir}`);
|
|
369
370
|
await execCommand(`ssh-keygen -t ed25519 -f ${pathToKey} -N "" -C "${comment || name}"`);
|
|
370
371
|
await execCommand(`chmod 600 ${pathToKey}`);
|
|
371
|
-
debugApiCall(`file(${pathToKeyPub}).text()`);
|
|
372
372
|
const pubKey = await Bun.file(pathToKeyPub).text();
|
|
373
373
|
return pubKey;
|
|
374
374
|
}
|
|
375
375
|
var addSshKeyToAuthorized = async (pubKey, context) => {
|
|
376
|
-
const {
|
|
376
|
+
const { stdout: keys } = await execBySsh("cat .ssh/authorized_keys", context);
|
|
377
377
|
if (keys.includes(pubKey)) {
|
|
378
378
|
return;
|
|
379
379
|
}
|
|
@@ -403,7 +403,7 @@ var createCron = async ({
|
|
|
403
403
|
const pathToFileNorm = normalizePath(pathToFile);
|
|
404
404
|
const constructedLine = `${time} ${pathToFileNorm}`;
|
|
405
405
|
const tempFile = `/tmp/ramm_cron}`;
|
|
406
|
-
const {
|
|
406
|
+
const { stdout: cronConfig } = await execCommandMayError("crontab -l");
|
|
407
407
|
let newCronConfig = cronConfig;
|
|
408
408
|
if (cronConfig.includes(constructedLine)) {
|
|
409
409
|
return;
|
|
@@ -441,14 +441,14 @@ var buildAndRunOverSsh = async ({
|
|
|
441
441
|
};
|
|
442
442
|
var pathToJson = "/tmp/ramm_json";
|
|
443
443
|
var passVarsClient = async (data, context) => {
|
|
444
|
+
printFunction("passVarsClient");
|
|
444
445
|
const json = JSON.stringify(data);
|
|
445
|
-
debugApiCall(`writeFile(${pathToJson})`);
|
|
446
446
|
await writeFile(pathToJson, json);
|
|
447
447
|
await copyFilesBySsh(pathToJson, pathToJson, context);
|
|
448
448
|
await execCommand(`rm -rf ${pathToJson}`);
|
|
449
449
|
};
|
|
450
450
|
var passVarsServer = async () => {
|
|
451
|
-
|
|
451
|
+
printFunction("passVarsServer");
|
|
452
452
|
const jsonData = await file3(pathToJson).json();
|
|
453
453
|
await execCommand(`rm -rf ${pathToJson}`);
|
|
454
454
|
return jsonData;
|
|
@@ -462,6 +462,7 @@ export {
|
|
|
462
462
|
runPodmanContainerService,
|
|
463
463
|
runPodmanContainer,
|
|
464
464
|
restartSystemdService,
|
|
465
|
+
printBlock,
|
|
465
466
|
passVarsServer,
|
|
466
467
|
passVarsClient,
|
|
467
468
|
normalizePath,
|
|
@@ -473,7 +474,6 @@ export {
|
|
|
473
474
|
getServerFingerprintBySsh,
|
|
474
475
|
execCommandMayError as execCommand,
|
|
475
476
|
execBySsh,
|
|
476
|
-
debugBlock,
|
|
477
477
|
createCron,
|
|
478
478
|
createAndAddSshKey,
|
|
479
479
|
copyFilesBySsh,
|
|
@@ -1,18 +1,35 @@
|
|
|
1
|
+
import { type Subprocess } from "bun";
|
|
1
2
|
import { Context } from "../context.ts";
|
|
2
3
|
export declare const defaultContext: Context;
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export type ExecCommandStore = {
|
|
5
|
+
spawnResult?: Subprocess<"inherit", "pipe", "pipe">;
|
|
6
|
+
};
|
|
7
|
+
type ExecProps = {
|
|
8
|
+
store?: ExecCommandStore;
|
|
9
|
+
env?: Record<string, string>;
|
|
10
|
+
cwd?: string;
|
|
11
|
+
prefix?: string;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
} | void;
|
|
14
|
+
export declare const execCommandRaw: (command: string, { store, signal, env, cwd, prefix }?: ExecProps) => Promise<{
|
|
15
|
+
stderr: string;
|
|
16
|
+
stdout: string;
|
|
17
|
+
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
7
18
|
}>;
|
|
8
|
-
export declare const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
spawnResult:
|
|
19
|
+
export declare const execCommandMayError: (command: string, props: ExecProps) => Promise<{
|
|
20
|
+
stderr: string;
|
|
21
|
+
stdout: string;
|
|
22
|
+
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const execCommand: (command: string, props: ExecProps) => Promise<{
|
|
25
|
+
stderr: string;
|
|
26
|
+
stdout: string;
|
|
27
|
+
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
12
28
|
}>;
|
|
13
29
|
export declare const copyFilesBySsh: (from: string, to: string, context: Context) => Promise<void>;
|
|
14
30
|
export declare const execBySsh: (command: string, context: Context) => Promise<{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
spawnResult:
|
|
31
|
+
stderr: string;
|
|
32
|
+
stdout: string;
|
|
33
|
+
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
18
34
|
}>;
|
|
35
|
+
export {};
|
package/dist/types/base/tee.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const readStreamToStr: (read: ReadableStream) => Promise<string>;
|
|
1
|
+
export declare const teeStdout: (read: ReadableStream, prefix: string) => Promise<string>;
|
|
2
|
+
export declare const teeStderr: (read: ReadableStream, prefix: string) => Promise<string>;
|
package/dist/types/podman.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { Context } from "./context.ts";
|
|
|
2
2
|
export declare const installPodman: () => Promise<void>;
|
|
3
3
|
export declare const getCreateCommand: (name: string) => Promise<string>;
|
|
4
4
|
export declare const loginPodman: (address: string, login: string, password: string) => Promise<{
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
stderr: string;
|
|
6
|
+
stdout: string;
|
|
7
7
|
spawnResult: import("bun").Subprocess<"inherit", "pipe", "pipe">;
|
|
8
8
|
}>;
|
|
9
9
|
export declare const runPodmanContainer: (name: string, command: string) => Promise<void>;
|
package/dist/types/ramm.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { installPodman, runPodmanContainer, loginPodman } from "./podman.ts";
|
|
|
5
5
|
export { runPodmanContainerService, addNftPodmanRule } from "./podman.ts";
|
|
6
6
|
export { restartSystemdService } from "./systemd.ts";
|
|
7
7
|
export { installSystemPackage } from "./packages.ts";
|
|
8
|
-
export {
|
|
8
|
+
export { printBlock } from "./print.ts";
|
|
9
9
|
export { setupNftable } from "./nft.ts";
|
|
10
10
|
export { writeIfNew, writeFile, writeIfNewCompletely as writeFileIfNotMatch, normalizeFileContent, } from "./files.ts";
|
|
11
11
|
export { createAndAddSshKey, getServerFingerprintBySsh, addKeyToHostConfig, setupSshKey, } from "./ssh.ts";
|
package/package.json
CHANGED