ramm 0.0.28 → 0.0.30
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 +71 -63
- package/dist/types/base/base.d.ts +33 -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 +2 -2
- 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;
|
|
@@ -111,6 +122,10 @@ var execBySsh = async (command, context) => {
|
|
|
111
122
|
const sshKeyPart = context.sshKey ? ` -i ${context.sshKey}` : "";
|
|
112
123
|
return await execCommand(`ssh${sshKeyPart} ${context.getAddress()} '${command}'`);
|
|
113
124
|
};
|
|
125
|
+
var execCommandOverSsh = async (command, context) => {
|
|
126
|
+
const sshKeyPart = context.sshKey ? ` -i ${context.sshKey}` : "";
|
|
127
|
+
return await execCommand(`ssh${sshKeyPart} ${context.getAddress()} '${command}'`);
|
|
128
|
+
};
|
|
114
129
|
// src/init.ts
|
|
115
130
|
var installBun = async (context) => {
|
|
116
131
|
const bunPath = new URL(import.meta.resolve("./bun.sh")).pathname;
|
|
@@ -148,6 +163,7 @@ var stopSystemdService = async (constext, name) => {
|
|
|
148
163
|
await execCommand(formatUserspace(constext, `systemctl stop ${name}`));
|
|
149
164
|
};
|
|
150
165
|
var restartSystemdService = async (name, constext = defaultContext) => {
|
|
166
|
+
printFunction(`restartSystemdService ${name}`);
|
|
151
167
|
await execCommand(formatUserspace(constext, `systemctl restart ${name}`));
|
|
152
168
|
};
|
|
153
169
|
var checkSystemdService = async (context, serviceName) => {
|
|
@@ -155,6 +171,7 @@ var checkSystemdService = async (context, serviceName) => {
|
|
|
155
171
|
return spawnResult.exitCode === 0;
|
|
156
172
|
};
|
|
157
173
|
var createSystemdService = async (context, serviceName, pathToServiceFile) => {
|
|
174
|
+
printFunction(`createSystemdService ${serviceName}`);
|
|
158
175
|
const pathToSeviceTarget = getSystemdPathToService(context, serviceName);
|
|
159
176
|
await execCommand(`cp -v ${pathToServiceFile} ${pathToSeviceTarget}`);
|
|
160
177
|
await execCommand(formatUserspace(context, "systemctl daemon-reload"));
|
|
@@ -172,10 +189,10 @@ var installPodman = async () => {
|
|
|
172
189
|
var createNetwork = async () => {
|
|
173
190
|
const netwroks = await execCommand("podman network inspect $(podman network ls -q) -f '{{.NetworkInterface}}'");
|
|
174
191
|
const podmanNetworks = await execCommand("podman network ls");
|
|
175
|
-
if (podmanNetworks.
|
|
192
|
+
if (podmanNetworks.stdout.includes("ramm")) {
|
|
176
193
|
return;
|
|
177
194
|
}
|
|
178
|
-
if (netwroks.
|
|
195
|
+
if (netwroks.stdout.includes("podman_ramm")) {
|
|
179
196
|
return;
|
|
180
197
|
}
|
|
181
198
|
await execCommand("podman network create --interface-name=podman_ramm ramm");
|
|
@@ -206,7 +223,7 @@ var runPodmanContainerService = async (name, command, context = defaultContext)
|
|
|
206
223
|
};
|
|
207
224
|
var addNftPodmanRule = async () => {
|
|
208
225
|
const podmanNetworksResult = await execCommand("podman network inspect $(podman network ls -q) -f '{{.NetworkInterface}}'");
|
|
209
|
-
const podmanNetworks = podmanNetworksResult.
|
|
226
|
+
const podmanNetworks = podmanNetworksResult.stdout.trim().split(`
|
|
210
227
|
`);
|
|
211
228
|
await execCommand(`nft add set inet ramm podman_interfaces '{ type ifname; flags dynamic; elements = { ${podmanNetworks.join(", ")} }; }'`);
|
|
212
229
|
await execCommand("nft insert rule inet ramm prerouting iifname @podman_interfaces accept");
|
|
@@ -284,7 +301,6 @@ var normalizeFileContent = (str) => {
|
|
|
284
301
|
};
|
|
285
302
|
var createDir = async (str) => {
|
|
286
303
|
const dirname = str.split("/").slice(0, -1).join("/");
|
|
287
|
-
debugApiCall(`exists(${dirname})`);
|
|
288
304
|
const exist = await exists(dirname);
|
|
289
305
|
if (exist) {
|
|
290
306
|
return;
|
|
@@ -293,11 +309,9 @@ var createDir = async (str) => {
|
|
|
293
309
|
};
|
|
294
310
|
var checkStrInFile = async (filePath, str) => {
|
|
295
311
|
const file2 = Bun.file(filePath);
|
|
296
|
-
debugApiCall(`file(${filePath}).exists())`);
|
|
297
312
|
if (!await file2.exists()) {
|
|
298
313
|
return false;
|
|
299
314
|
}
|
|
300
|
-
debugApiCall(`file(${filePath}).text()`);
|
|
301
315
|
const fileText = await file2.text();
|
|
302
316
|
if (fileText.includes(str)) {
|
|
303
317
|
return true;
|
|
@@ -307,7 +321,6 @@ var checkStrInFile = async (filePath, str) => {
|
|
|
307
321
|
var createFileIfNeed = async (rawFilePath) => {
|
|
308
322
|
const filePath = normalizePath(rawFilePath);
|
|
309
323
|
await createDir(filePath);
|
|
310
|
-
debugApiCall(`file(${filePath}).exists())`);
|
|
311
324
|
if (!await file(filePath).exists()) {
|
|
312
325
|
await execCommand(`touch ${filePath}`);
|
|
313
326
|
}
|
|
@@ -318,24 +331,20 @@ var writeIfNew = async (rawFilePath, str) => {
|
|
|
318
331
|
if (await checkStrInFile(filePath, str)) {
|
|
319
332
|
return;
|
|
320
333
|
}
|
|
321
|
-
debugApiCall(`appendFile(${filePath})`);
|
|
322
334
|
await appendFile(filePath, normalizeFileContent(str));
|
|
323
335
|
};
|
|
324
336
|
var writeFile = async (pathToFile, str) => {
|
|
325
337
|
const normalizedPath = normalizePath(pathToFile);
|
|
326
338
|
await createFileIfNeed(normalizedPath);
|
|
327
|
-
debugApiCall(`write(${normalizedPath})`);
|
|
328
339
|
await write(normalizedPath, str);
|
|
329
340
|
};
|
|
330
341
|
var writeIfNewCompletely = async (pathToFile, str) => {
|
|
331
342
|
const normalizedPath = normalizePath(pathToFile);
|
|
332
343
|
await createFileIfNeed(normalizedPath);
|
|
333
|
-
debugApiCall(`file(${normalizedPath}).text()`);
|
|
334
344
|
const fileText = await file(normalizedPath).text();
|
|
335
345
|
if (fileText === str) {
|
|
336
346
|
return;
|
|
337
347
|
}
|
|
338
|
-
debugApiCall(`write(${normalizedPath})`);
|
|
339
348
|
await write(normalizedPath, str);
|
|
340
349
|
};
|
|
341
350
|
// src/ssh.ts
|
|
@@ -348,29 +357,27 @@ var addKeyToHostConfig = async (pathToHost, address, pathToKey) => {
|
|
|
348
357
|
await writeIfNew(pathToHost, text);
|
|
349
358
|
};
|
|
350
359
|
var getServerFingerprintBySsh = async (context) => {
|
|
351
|
-
const {
|
|
352
|
-
return
|
|
360
|
+
const { stdout } = await execBySsh('ssh-keyscan -t ed25519 localhost | grep -v "^#"', context);
|
|
361
|
+
return stdout.replace("localhost", context.domain);
|
|
353
362
|
};
|
|
354
363
|
async function createSshKey(pathToKey, comment) {
|
|
364
|
+
printFunction(createSshKey.name);
|
|
355
365
|
const name = pathToKey.split("/").at(-1);
|
|
356
366
|
const pathToKeyPub = `${pathToKey}.pub`;
|
|
357
367
|
const pathToDir = pathToKey.split("/").slice(0, -1).join("/");
|
|
358
368
|
const pathToKeyFile = file2(pathToKey);
|
|
359
369
|
const pathToKeyPubFile = file2(pathToKeyPub);
|
|
360
|
-
debugApiCall(`file(${pathToKey}).exist()`);
|
|
361
|
-
debugApiCall(`file(${pathToKeyPub}).exist()`);
|
|
362
370
|
if (await pathToKeyFile.exists() && await pathToKeyPubFile.exists()) {
|
|
363
371
|
return await pathToKeyPubFile.text();
|
|
364
372
|
}
|
|
365
373
|
await execCommand(`mkdir -p ${pathToDir}`);
|
|
366
374
|
await execCommand(`ssh-keygen -t ed25519 -f ${pathToKey} -N "" -C "${comment || name}"`);
|
|
367
375
|
await execCommand(`chmod 600 ${pathToKey}`);
|
|
368
|
-
debugApiCall(`file(${pathToKeyPub}).text()`);
|
|
369
376
|
const pubKey = await Bun.file(pathToKeyPub).text();
|
|
370
377
|
return pubKey;
|
|
371
378
|
}
|
|
372
379
|
var addSshKeyToAuthorized = async (pubKey, context) => {
|
|
373
|
-
const {
|
|
380
|
+
const { stdout: keys } = await execBySsh("cat .ssh/authorized_keys", context);
|
|
374
381
|
if (keys.includes(pubKey)) {
|
|
375
382
|
return;
|
|
376
383
|
}
|
|
@@ -400,7 +407,7 @@ var createCron = async ({
|
|
|
400
407
|
const pathToFileNorm = normalizePath(pathToFile);
|
|
401
408
|
const constructedLine = `${time} ${pathToFileNorm}`;
|
|
402
409
|
const tempFile = `/tmp/ramm_cron}`;
|
|
403
|
-
const {
|
|
410
|
+
const { stdout: cronConfig } = await execCommandMayError("crontab -l");
|
|
404
411
|
let newCronConfig = cronConfig;
|
|
405
412
|
if (cronConfig.includes(constructedLine)) {
|
|
406
413
|
return;
|
|
@@ -438,14 +445,14 @@ var buildAndRunOverSsh = async ({
|
|
|
438
445
|
};
|
|
439
446
|
var pathToJson = "/tmp/ramm_json";
|
|
440
447
|
var passVarsClient = async (data, context) => {
|
|
448
|
+
printFunction("passVarsClient");
|
|
441
449
|
const json = JSON.stringify(data);
|
|
442
|
-
debugApiCall(`writeFile(${pathToJson})`);
|
|
443
450
|
await writeFile(pathToJson, json);
|
|
444
451
|
await copyFilesBySsh(pathToJson, pathToJson, context);
|
|
445
452
|
await execCommand(`rm -rf ${pathToJson}`);
|
|
446
453
|
};
|
|
447
454
|
var passVarsServer = async () => {
|
|
448
|
-
|
|
455
|
+
printFunction("passVarsServer");
|
|
449
456
|
const jsonData = await file3(pathToJson).json();
|
|
450
457
|
await execCommand(`rm -rf ${pathToJson}`);
|
|
451
458
|
return jsonData;
|
|
@@ -459,6 +466,7 @@ export {
|
|
|
459
466
|
runPodmanContainerService,
|
|
460
467
|
runPodmanContainer,
|
|
461
468
|
restartSystemdService,
|
|
469
|
+
printBlock,
|
|
462
470
|
passVarsServer,
|
|
463
471
|
passVarsClient,
|
|
464
472
|
normalizePath,
|
|
@@ -468,9 +476,9 @@ export {
|
|
|
468
476
|
installPodman,
|
|
469
477
|
installBun,
|
|
470
478
|
getServerFingerprintBySsh,
|
|
479
|
+
execCommandOverSsh,
|
|
471
480
|
execCommandMayError as execCommand,
|
|
472
481
|
execBySsh,
|
|
473
|
-
debugBlock,
|
|
474
482
|
createCron,
|
|
475
483
|
createAndAddSshKey,
|
|
476
484
|
copyFilesBySsh,
|
|
@@ -1,18 +1,40 @@
|
|
|
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">;
|
|
34
|
+
}>;
|
|
35
|
+
export declare const execCommandOverSsh: (command: string, context: Context) => Promise<{
|
|
36
|
+
stderr: string;
|
|
37
|
+
stdout: string;
|
|
38
|
+
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
18
39
|
}>;
|
|
40
|
+
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
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { execBySsh, execCommandMayError as execCommand, copyFilesBySsh, } from "./base/base.ts";
|
|
1
|
+
export { execBySsh, execCommandOverSsh, execCommandMayError as execCommand, copyFilesBySsh, } from "./base/base.ts";
|
|
2
2
|
export { Context } from "./context.ts";
|
|
3
3
|
export { installBun } from "./init.ts";
|
|
4
4
|
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