ramm 0.0.28 → 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 +66 -63
- 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");
|
|
@@ -284,7 +297,6 @@ var normalizeFileContent = (str) => {
|
|
|
284
297
|
};
|
|
285
298
|
var createDir = async (str) => {
|
|
286
299
|
const dirname = str.split("/").slice(0, -1).join("/");
|
|
287
|
-
debugApiCall(`exists(${dirname})`);
|
|
288
300
|
const exist = await exists(dirname);
|
|
289
301
|
if (exist) {
|
|
290
302
|
return;
|
|
@@ -293,11 +305,9 @@ var createDir = async (str) => {
|
|
|
293
305
|
};
|
|
294
306
|
var checkStrInFile = async (filePath, str) => {
|
|
295
307
|
const file2 = Bun.file(filePath);
|
|
296
|
-
debugApiCall(`file(${filePath}).exists())`);
|
|
297
308
|
if (!await file2.exists()) {
|
|
298
309
|
return false;
|
|
299
310
|
}
|
|
300
|
-
debugApiCall(`file(${filePath}).text()`);
|
|
301
311
|
const fileText = await file2.text();
|
|
302
312
|
if (fileText.includes(str)) {
|
|
303
313
|
return true;
|
|
@@ -307,7 +317,6 @@ var checkStrInFile = async (filePath, str) => {
|
|
|
307
317
|
var createFileIfNeed = async (rawFilePath) => {
|
|
308
318
|
const filePath = normalizePath(rawFilePath);
|
|
309
319
|
await createDir(filePath);
|
|
310
|
-
debugApiCall(`file(${filePath}).exists())`);
|
|
311
320
|
if (!await file(filePath).exists()) {
|
|
312
321
|
await execCommand(`touch ${filePath}`);
|
|
313
322
|
}
|
|
@@ -318,24 +327,20 @@ var writeIfNew = async (rawFilePath, str) => {
|
|
|
318
327
|
if (await checkStrInFile(filePath, str)) {
|
|
319
328
|
return;
|
|
320
329
|
}
|
|
321
|
-
debugApiCall(`appendFile(${filePath})`);
|
|
322
330
|
await appendFile(filePath, normalizeFileContent(str));
|
|
323
331
|
};
|
|
324
332
|
var writeFile = async (pathToFile, str) => {
|
|
325
333
|
const normalizedPath = normalizePath(pathToFile);
|
|
326
334
|
await createFileIfNeed(normalizedPath);
|
|
327
|
-
debugApiCall(`write(${normalizedPath})`);
|
|
328
335
|
await write(normalizedPath, str);
|
|
329
336
|
};
|
|
330
337
|
var writeIfNewCompletely = async (pathToFile, str) => {
|
|
331
338
|
const normalizedPath = normalizePath(pathToFile);
|
|
332
339
|
await createFileIfNeed(normalizedPath);
|
|
333
|
-
debugApiCall(`file(${normalizedPath}).text()`);
|
|
334
340
|
const fileText = await file(normalizedPath).text();
|
|
335
341
|
if (fileText === str) {
|
|
336
342
|
return;
|
|
337
343
|
}
|
|
338
|
-
debugApiCall(`write(${normalizedPath})`);
|
|
339
344
|
await write(normalizedPath, str);
|
|
340
345
|
};
|
|
341
346
|
// src/ssh.ts
|
|
@@ -348,29 +353,27 @@ var addKeyToHostConfig = async (pathToHost, address, pathToKey) => {
|
|
|
348
353
|
await writeIfNew(pathToHost, text);
|
|
349
354
|
};
|
|
350
355
|
var getServerFingerprintBySsh = async (context) => {
|
|
351
|
-
const {
|
|
352
|
-
return
|
|
356
|
+
const { stdout } = await execBySsh('ssh-keyscan -t ed25519 localhost | grep -v "^#"', context);
|
|
357
|
+
return stdout.replace("localhost", context.domain);
|
|
353
358
|
};
|
|
354
359
|
async function createSshKey(pathToKey, comment) {
|
|
360
|
+
printFunction(createSshKey.name);
|
|
355
361
|
const name = pathToKey.split("/").at(-1);
|
|
356
362
|
const pathToKeyPub = `${pathToKey}.pub`;
|
|
357
363
|
const pathToDir = pathToKey.split("/").slice(0, -1).join("/");
|
|
358
364
|
const pathToKeyFile = file2(pathToKey);
|
|
359
365
|
const pathToKeyPubFile = file2(pathToKeyPub);
|
|
360
|
-
debugApiCall(`file(${pathToKey}).exist()`);
|
|
361
|
-
debugApiCall(`file(${pathToKeyPub}).exist()`);
|
|
362
366
|
if (await pathToKeyFile.exists() && await pathToKeyPubFile.exists()) {
|
|
363
367
|
return await pathToKeyPubFile.text();
|
|
364
368
|
}
|
|
365
369
|
await execCommand(`mkdir -p ${pathToDir}`);
|
|
366
370
|
await execCommand(`ssh-keygen -t ed25519 -f ${pathToKey} -N "" -C "${comment || name}"`);
|
|
367
371
|
await execCommand(`chmod 600 ${pathToKey}`);
|
|
368
|
-
debugApiCall(`file(${pathToKeyPub}).text()`);
|
|
369
372
|
const pubKey = await Bun.file(pathToKeyPub).text();
|
|
370
373
|
return pubKey;
|
|
371
374
|
}
|
|
372
375
|
var addSshKeyToAuthorized = async (pubKey, context) => {
|
|
373
|
-
const {
|
|
376
|
+
const { stdout: keys } = await execBySsh("cat .ssh/authorized_keys", context);
|
|
374
377
|
if (keys.includes(pubKey)) {
|
|
375
378
|
return;
|
|
376
379
|
}
|
|
@@ -400,7 +403,7 @@ var createCron = async ({
|
|
|
400
403
|
const pathToFileNorm = normalizePath(pathToFile);
|
|
401
404
|
const constructedLine = `${time} ${pathToFileNorm}`;
|
|
402
405
|
const tempFile = `/tmp/ramm_cron}`;
|
|
403
|
-
const {
|
|
406
|
+
const { stdout: cronConfig } = await execCommandMayError("crontab -l");
|
|
404
407
|
let newCronConfig = cronConfig;
|
|
405
408
|
if (cronConfig.includes(constructedLine)) {
|
|
406
409
|
return;
|
|
@@ -438,14 +441,14 @@ var buildAndRunOverSsh = async ({
|
|
|
438
441
|
};
|
|
439
442
|
var pathToJson = "/tmp/ramm_json";
|
|
440
443
|
var passVarsClient = async (data, context) => {
|
|
444
|
+
printFunction("passVarsClient");
|
|
441
445
|
const json = JSON.stringify(data);
|
|
442
|
-
debugApiCall(`writeFile(${pathToJson})`);
|
|
443
446
|
await writeFile(pathToJson, json);
|
|
444
447
|
await copyFilesBySsh(pathToJson, pathToJson, context);
|
|
445
448
|
await execCommand(`rm -rf ${pathToJson}`);
|
|
446
449
|
};
|
|
447
450
|
var passVarsServer = async () => {
|
|
448
|
-
|
|
451
|
+
printFunction("passVarsServer");
|
|
449
452
|
const jsonData = await file3(pathToJson).json();
|
|
450
453
|
await execCommand(`rm -rf ${pathToJson}`);
|
|
451
454
|
return jsonData;
|
|
@@ -459,6 +462,7 @@ export {
|
|
|
459
462
|
runPodmanContainerService,
|
|
460
463
|
runPodmanContainer,
|
|
461
464
|
restartSystemdService,
|
|
465
|
+
printBlock,
|
|
462
466
|
passVarsServer,
|
|
463
467
|
passVarsClient,
|
|
464
468
|
normalizePath,
|
|
@@ -470,7 +474,6 @@ export {
|
|
|
470
474
|
getServerFingerprintBySsh,
|
|
471
475
|
execCommandMayError as execCommand,
|
|
472
476
|
execBySsh,
|
|
473
|
-
debugBlock,
|
|
474
477
|
createCron,
|
|
475
478
|
createAndAddSshKey,
|
|
476
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