ramm 0.0.59 → 0.0.63
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/README.md +298 -68
- package/dist/ramm.js +104 -107
- package/package.json +6 -2
- package/dist/types/base/base.d.ts +0 -35
- package/dist/types/base/tee.d.ts +0 -2
- package/dist/types/build.d.ts +0 -7
- package/dist/types/context.d.ts +0 -16
- package/dist/types/cron.d.ts +0 -4
- package/dist/types/files.d.ts +0 -4
- package/dist/types/init.d.ts +0 -2
- package/dist/types/nft.d.ts +0 -6
- package/dist/types/packages.d.ts +0 -13
- package/dist/types/path.d.ts +0 -1
- package/dist/types/podman.d.ts +0 -25
- package/dist/types/print.d.ts +0 -3
- package/dist/types/ramm.d.ts +0 -13
- package/dist/types/ssh.d.ts +0 -11
- package/dist/types/systemd.d.ts +0 -10
package/README.md
CHANGED
|
@@ -1,151 +1,381 @@
|
|
|
1
|
-
|
|
1
|
+
# RAMM
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Bun library for server management and deployment automation in TypeScript. Write your infrastructure logic in real code — no YAML, no DSL, no templating language to fight with.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Why not Ansible?
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
Ansible is great, but it comes with a cost: you write infrastructure in YAML with Jinja2 templates. The moment your logic gets non-trivial — conditionals, loops, dynamic values — you're fighting the format instead of solving the problem.
|
|
8
|
+
|
|
9
|
+
RAMM takes a different approach: **your deployment scripts are just TypeScript**. Full language, real abstractions, IDE support, type checking, any npm package you need. If you know JS, you already know how to write RAMM scripts.
|
|
10
|
+
|
|
11
|
+
The trade-off is explicit: Ansible gives you a huge module ecosystem and declarative guarantees. RAMM gives you simplicity and the full power of a real programming language. For developers who want to own their deployment code without learning a separate tool, RAMM is the better fit.
|
|
12
|
+
|
|
13
|
+
## How it works
|
|
14
|
+
|
|
15
|
+
The core pattern is `buildAndRunOverSsh`: write a script that configures your server (`server.ts`), then run it from your local machine (`client.ts`). RAMM compiles the server script with `bun build` and executes it on the remote host — all commands inside run on the server.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
client.ts → [bun build] → server.ts runs on remote
|
|
19
|
+
(local machine) (all execCommand calls are local to the server)
|
|
20
|
+
```
|
|
11
21
|
|
|
12
22
|
## Installation
|
|
13
23
|
|
|
14
24
|
```bash
|
|
15
25
|
bun add ramm
|
|
16
|
-
# or
|
|
17
|
-
npm install ramm
|
|
18
26
|
```
|
|
19
27
|
|
|
20
|
-
## Quick Start
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
**`client.ts`** — runs on your local machine:
|
|
21
31
|
|
|
22
32
|
```ts
|
|
23
|
-
import {
|
|
24
|
-
import { Context, exec, copyFiles, debug, installBun } from "ramm";
|
|
33
|
+
import { buildAndRunOverSsh, Context } from "ramm";
|
|
25
34
|
|
|
26
|
-
const
|
|
35
|
+
const ctx = new Context({ user: "root", address: "1.2.3.4" });
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
await buildAndRunOverSsh({
|
|
38
|
+
entrypoint: "./server.ts",
|
|
39
|
+
context: ctx,
|
|
40
|
+
});
|
|
41
|
+
```
|
|
30
42
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
**`server.ts`** — compiled and executed on the remote server:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import {
|
|
47
|
+
installPodman,
|
|
48
|
+
createPodmanCommand,
|
|
49
|
+
runPodmanContainerService,
|
|
50
|
+
setupNftable,
|
|
51
|
+
printBlock,
|
|
52
|
+
} from "ramm";
|
|
53
|
+
|
|
54
|
+
printBlock("Firewall");
|
|
55
|
+
await setupNftable({
|
|
56
|
+
allowedIpV4: ["1.2.3.4"],
|
|
57
|
+
allowedPorts: [443],
|
|
36
58
|
});
|
|
37
59
|
|
|
38
|
-
|
|
39
|
-
await
|
|
60
|
+
printBlock("Container");
|
|
61
|
+
await installPodman();
|
|
62
|
+
|
|
63
|
+
const cmd = createPodmanCommand({
|
|
64
|
+
name: "app",
|
|
65
|
+
command: "myregistry.io/app:latest",
|
|
66
|
+
envs: [{ name: "PORT", value: "3000" }],
|
|
67
|
+
});
|
|
40
68
|
|
|
41
|
-
|
|
42
|
-
await exec(context, "bun run ./dist/server.js");
|
|
69
|
+
await runPodmanContainerService("app", cmd);
|
|
43
70
|
```
|
|
44
71
|
|
|
45
|
-
|
|
72
|
+
---
|
|
46
73
|
|
|
47
|
-
|
|
74
|
+
## API
|
|
48
75
|
|
|
49
|
-
|
|
76
|
+
### Context
|
|
77
|
+
|
|
78
|
+
Describes the server connection.
|
|
50
79
|
|
|
51
80
|
```ts
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
81
|
+
const ctx = new Context({
|
|
82
|
+
user: "root",
|
|
83
|
+
address: "1.2.3.4",
|
|
84
|
+
sshKey: "~/.ssh/id_ed25519", // optional
|
|
85
|
+
sudo: false, // prefix commands with sudo (default: false)
|
|
86
|
+
userspace: false, // use systemd --user scope (default: false)
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
ctx.getAddress(); // "root@1.2.3.4"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Commands
|
|
95
|
+
|
|
96
|
+
#### `execCommand(command, props?, context?)`
|
|
97
|
+
|
|
98
|
+
Runs a command locally. Throws on non-zero exit code.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
await execCommand("systemctl restart app");
|
|
102
|
+
await execCommand("mkdir -p /opt/app", {}, ctx); // with sudo if ctx.sudo = true
|
|
56
103
|
```
|
|
57
104
|
|
|
58
|
-
|
|
59
|
-
- address: Server IP/hostname
|
|
60
|
-
- getAddress(): Returns "user@host" format
|
|
105
|
+
#### `execCommandMayError(command, props?, context?)`
|
|
61
106
|
|
|
62
|
-
|
|
107
|
+
Same as `execCommand` but does not throw — returns the result with exit code.
|
|
63
108
|
|
|
64
109
|
```ts
|
|
65
|
-
|
|
110
|
+
const result = await execCommandMayError("command -v podman", {}, ctx);
|
|
111
|
+
if (result.spawnResult.exitCode !== 0) {
|
|
112
|
+
// podman is not installed
|
|
113
|
+
}
|
|
66
114
|
```
|
|
67
115
|
|
|
68
|
-
|
|
116
|
+
#### `execCommandOverSsh(command, context)`
|
|
69
117
|
|
|
70
|
-
|
|
118
|
+
Runs a command on a remote server over SSH.
|
|
71
119
|
|
|
72
120
|
```ts
|
|
73
|
-
await
|
|
121
|
+
await execCommandOverSsh("systemctl restart app", ctx);
|
|
74
122
|
```
|
|
75
123
|
|
|
76
|
-
|
|
124
|
+
#### `copyFilesOverSsh(from, to, context)`
|
|
125
|
+
|
|
126
|
+
Copies files to the remote server using rsync.
|
|
77
127
|
|
|
78
128
|
```ts
|
|
79
|
-
|
|
129
|
+
await copyFilesOverSsh("./dist/", "/opt/app/dist", ctx);
|
|
80
130
|
```
|
|
81
131
|
|
|
82
|
-
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### Build & Deploy
|
|
83
135
|
|
|
84
|
-
|
|
136
|
+
#### `buildAndRunOverSsh({ entrypoint, context })`
|
|
137
|
+
|
|
138
|
+
Compiles a TypeScript script with `bun build` and runs it on the remote server. This is the primary usage pattern.
|
|
85
139
|
|
|
86
140
|
```ts
|
|
87
|
-
await
|
|
141
|
+
await buildAndRunOverSsh({
|
|
142
|
+
entrypoint: "./server.ts",
|
|
143
|
+
context: ctx,
|
|
144
|
+
});
|
|
88
145
|
```
|
|
89
146
|
|
|
90
|
-
|
|
147
|
+
#### `passVarsClient(data, context)` / `passVarsServer(context?)`
|
|
148
|
+
|
|
149
|
+
Passes variables from the local environment into the server script. Call `passVarsClient` before `buildAndRunOverSsh`, then `passVarsServer` inside the server script.
|
|
91
150
|
|
|
92
151
|
```ts
|
|
93
|
-
|
|
152
|
+
// client.ts
|
|
153
|
+
await passVarsClient({ DB_URL: process.env.DB_URL }, ctx);
|
|
154
|
+
await buildAndRunOverSsh({ entrypoint: "./server.ts", context: ctx });
|
|
155
|
+
|
|
156
|
+
// server.ts
|
|
157
|
+
const vars = await passVarsServer();
|
|
158
|
+
console.log(vars.DB_URL);
|
|
94
159
|
```
|
|
95
160
|
|
|
96
|
-
|
|
161
|
+
---
|
|
97
162
|
|
|
98
|
-
|
|
163
|
+
### Packages
|
|
164
|
+
|
|
165
|
+
#### `installSystemPackage(package, context?)`
|
|
166
|
+
|
|
167
|
+
Installs a system package. Auto-detects the OS and uses `apt` or `dnf`. Skips if already installed.
|
|
99
168
|
|
|
100
169
|
```ts
|
|
101
|
-
await installSystemPackage("
|
|
170
|
+
await installSystemPackage("nftables");
|
|
171
|
+
|
|
172
|
+
// with explicit config for a custom package
|
|
173
|
+
await installSystemPackage({
|
|
174
|
+
name: "nginx",
|
|
175
|
+
command: "nginx",
|
|
176
|
+
});
|
|
102
177
|
```
|
|
103
178
|
|
|
104
|
-
|
|
179
|
+
#### `installBunOverSsh(context)`
|
|
180
|
+
|
|
181
|
+
Installs Bun on a remote server.
|
|
105
182
|
|
|
106
183
|
```ts
|
|
107
|
-
|
|
184
|
+
await installBunOverSsh(ctx);
|
|
108
185
|
```
|
|
109
186
|
|
|
110
|
-
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Podman
|
|
111
190
|
|
|
112
|
-
|
|
191
|
+
#### `installPodman(context?)`
|
|
192
|
+
|
|
193
|
+
Installs Podman and creates the `ramm` network. Skips if already installed.
|
|
113
194
|
|
|
114
195
|
```ts
|
|
115
196
|
await installPodman();
|
|
116
197
|
```
|
|
117
198
|
|
|
118
|
-
|
|
199
|
+
#### `createPodmanCommand(options)`
|
|
200
|
+
|
|
201
|
+
Builds a `podman run` command string from structured options.
|
|
119
202
|
|
|
120
203
|
```ts
|
|
121
|
-
|
|
204
|
+
const cmd = createPodmanCommand({
|
|
205
|
+
name: "app",
|
|
206
|
+
command: "myregistry.io/app:latest",
|
|
207
|
+
networks: ["ramm"], // default: ["ramm"]
|
|
208
|
+
replace: true, // default: true
|
|
209
|
+
background: true, // default: true
|
|
210
|
+
envs: [{ name: "PORT", value: "3000" }],
|
|
211
|
+
volumes: [{ from: "/data", to: "/data" }],
|
|
212
|
+
});
|
|
213
|
+
// "podman run --name app --replace -d --network ramm -e PORT=3000 -v /data:/data myregistry.io/app:latest"
|
|
122
214
|
```
|
|
123
215
|
|
|
124
|
-
|
|
216
|
+
#### `runPodmanContainer(name, command, context?)`
|
|
125
217
|
|
|
126
|
-
|
|
127
|
-
- Recreates if configuration changed
|
|
128
|
-
- Skips if already running
|
|
218
|
+
Runs a container. Skips if already running with the same command. Recreates if the command changed.
|
|
129
219
|
|
|
130
|
-
|
|
220
|
+
```ts
|
|
221
|
+
await runPodmanContainer("app", cmd);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
#### `runPodmanContainerService(name, command, context?)`
|
|
225
|
+
|
|
226
|
+
Runs a container and registers it as a systemd service for autostart on reboot.
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
await runPodmanContainerService("app", cmd);
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### `loginPodman(address, login, password, context?)`
|
|
233
|
+
|
|
234
|
+
Authenticates with a container registry.
|
|
131
235
|
|
|
132
236
|
```ts
|
|
133
|
-
await
|
|
237
|
+
await loginPodman("registry.example.com", "user", "password");
|
|
134
238
|
```
|
|
135
239
|
|
|
136
|
-
|
|
240
|
+
#### `addNftPodmanRule(context?)`
|
|
241
|
+
|
|
242
|
+
Adds an nftables rule to allow Podman network traffic through the firewall.
|
|
137
243
|
|
|
138
244
|
```ts
|
|
139
|
-
|
|
245
|
+
await addNftPodmanRule();
|
|
140
246
|
```
|
|
141
247
|
|
|
142
|
-
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
### Systemd
|
|
251
|
+
|
|
252
|
+
#### `createSystemdService(name, content, context?)`
|
|
253
|
+
|
|
254
|
+
Writes a unit file, enables and starts the service.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
await createSystemdService(
|
|
258
|
+
"app.service",
|
|
259
|
+
`[Unit]
|
|
260
|
+
Description=My App
|
|
261
|
+
|
|
262
|
+
[Service]
|
|
263
|
+
ExecStart=bun run /opt/app/server.js
|
|
264
|
+
Restart=always
|
|
265
|
+
|
|
266
|
+
[Install]
|
|
267
|
+
WantedBy=multi-user.target`
|
|
268
|
+
);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### `createSystemdUnit(name, content, context?)`
|
|
272
|
+
|
|
273
|
+
Writes a unit file and reloads systemd. Does not start the service.
|
|
274
|
+
|
|
275
|
+
#### `startSystemdUnit(name, context?)` / `restartSystemdUnit(name, context?)` / `enableSystemdUnit(name, context?)` / `reloadSystemd(context?)`
|
|
276
|
+
|
|
277
|
+
Systemd unit management.
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
await reloadSystemd();
|
|
281
|
+
await enableSystemdUnit("app.service");
|
|
282
|
+
await startSystemdUnit("app.service");
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### `getSystemdPathToUnit(name, context?)`
|
|
286
|
+
|
|
287
|
+
Returns the path to the unit file — `/etc/systemd/system/` or `~/.config/systemd/user/` for userspace context.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
### Firewall (nftables)
|
|
292
|
+
|
|
293
|
+
#### `setupNftable({ allowedIpV4, allowedPorts, context? })`
|
|
294
|
+
|
|
295
|
+
Creates an `inet ramm` nftables table. Closes all ports except the ones listed, rate-limits SSH, saves the config, and enables autostart.
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
await setupNftable({
|
|
299
|
+
allowedIpV4: ["1.2.3.4"], // IPs with unrestricted SSH access
|
|
300
|
+
allowedPorts: [80, 443],
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
### SSH Keys
|
|
307
|
+
|
|
308
|
+
#### `createAndAddSshKey(filePath, comment, context)`
|
|
309
|
+
|
|
310
|
+
Creates an ed25519 key (if it doesn't exist) and adds the public key to `authorized_keys` on the server.
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
await createAndAddSshKey("~/.ssh/deploy_key", "deploy", ctx);
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### `addSshKeyToUse({ key, fingerprint, filePath, server, context? })`
|
|
317
|
+
|
|
318
|
+
Saves a private key locally, adds the fingerprint to `known_hosts`, and configures `~/.ssh/config`.
|
|
319
|
+
|
|
320
|
+
#### `saveSshFingerptint(filePath, context)`
|
|
321
|
+
|
|
322
|
+
Fetches the server's fingerprint and saves it to a file.
|
|
323
|
+
|
|
324
|
+
#### `addKeyToHostConfig(pathToHost, address, pathToKey, context?)`
|
|
325
|
+
|
|
326
|
+
Adds a `Host` block to the SSH config.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
### Files
|
|
331
|
+
|
|
332
|
+
#### `writeFile(path, content, context?)`
|
|
333
|
+
|
|
334
|
+
Writes a file. Skips if the content is already the same.
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
await writeFile("/etc/app/config.json", JSON.stringify(config));
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
#### `writeFileStrUniq(path, str, context?)`
|
|
341
|
+
|
|
342
|
+
Appends a string to a file only if it is not already present.
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
await writeFileStrUniq("~/.bashrc", 'export PATH="$PATH:/opt/bin"');
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
### Cron
|
|
351
|
+
|
|
352
|
+
#### `createCron({ time, pathToFile, context? })`
|
|
353
|
+
|
|
354
|
+
Adds a crontab entry. Skips if the entry already exists. Updates the schedule if the file is already in crontab with a different time.
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
await createCron({
|
|
358
|
+
time: "0 3 * * *",
|
|
359
|
+
pathToFile: "/opt/scripts/backup.sh",
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
### Utilities
|
|
366
|
+
|
|
367
|
+
#### `printBlock(name)`
|
|
368
|
+
|
|
369
|
+
Prints a named block to the console — useful for structuring deployment output.
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
printBlock("Database"); // → Block: Database
|
|
373
|
+
```
|
|
143
374
|
|
|
144
|
-
|
|
145
|
-
- Executes bun.sh on remote host
|
|
375
|
+
#### `normalizePath(path)`
|
|
146
376
|
|
|
147
|
-
|
|
377
|
+
Expands `~/` to an absolute path.
|
|
148
378
|
|
|
149
379
|
```ts
|
|
150
|
-
|
|
380
|
+
normalizePath("~/.ssh/config"); // "/home/user/.ssh/config"
|
|
151
381
|
```
|
package/dist/ramm.js
CHANGED
|
@@ -20,8 +20,8 @@ var printBlock = (name) => {
|
|
|
20
20
|
class Context {
|
|
21
21
|
user;
|
|
22
22
|
domain;
|
|
23
|
-
userspace;
|
|
24
|
-
sudo;
|
|
23
|
+
userspace = false;
|
|
24
|
+
sudo = false;
|
|
25
25
|
sshKey;
|
|
26
26
|
params = {};
|
|
27
27
|
constructor({
|
|
@@ -108,32 +108,33 @@ var execCommandMayError = async (command, props, context) => {
|
|
|
108
108
|
return execCommandRaw(command, props, context);
|
|
109
109
|
};
|
|
110
110
|
var execCommand = async (command, props, context) => {
|
|
111
|
+
const callSiteError = new Error(command);
|
|
111
112
|
const result = await execCommandMayError(command, props, context);
|
|
112
113
|
if (result.spawnResult.exitCode !== 0) {
|
|
113
|
-
console.error(
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
console.error(`<${command}> exitCode: ${result.spawnResult.exitCode}`);
|
|
115
|
+
callSiteError.stack = callSiteError.stack?.split(`
|
|
116
|
+
`).slice(1).join(`
|
|
117
|
+
`);
|
|
118
|
+
throw callSiteError;
|
|
116
119
|
}
|
|
117
120
|
return result;
|
|
118
121
|
};
|
|
119
|
-
var
|
|
120
|
-
|
|
122
|
+
var copyFilesOverSsh = async (from, to, context) => {
|
|
123
|
+
const sshKeyPart = context.sshKey ? ` -e "ssh -i ${context.sshKey}"` : "";
|
|
124
|
+
await execCommand(`rsync -avz${sshKeyPart} ${from} ${context.getAddress()}:${to}`);
|
|
121
125
|
};
|
|
122
126
|
var execCommandOverSsh = async (command, context) => {
|
|
123
127
|
const sshKeyPart = context.sshKey ? ` -i ${context.sshKey}` : "";
|
|
124
|
-
|
|
128
|
+
const escapedCommand = command.replace(/'/g, "'\\''");
|
|
129
|
+
return await execCommand(`ssh${sshKeyPart} ${context.getAddress()} '${escapedCommand}'`);
|
|
125
130
|
};
|
|
126
131
|
// src/init.ts
|
|
127
132
|
var installBunOverSsh = async (context) => {
|
|
128
133
|
const bunPath = new URL(import.meta.resolve("./bun.sh")).pathname;
|
|
129
|
-
await
|
|
134
|
+
await copyFilesOverSsh(bunPath, "./bun.sh", context);
|
|
130
135
|
await execCommandOverSsh("./bun.sh", context);
|
|
131
136
|
};
|
|
132
|
-
// src/podman.ts
|
|
133
|
-
var {$: $2 } = globalThis.Bun;
|
|
134
|
-
|
|
135
137
|
// src/packages.ts
|
|
136
|
-
var {$ } = globalThis.Bun;
|
|
137
138
|
var dnfOs = ["rocky", "fedora", "alma"];
|
|
138
139
|
var aptOs = ["ubuntu"];
|
|
139
140
|
var getManagerByOs = (osName) => {
|
|
@@ -180,7 +181,8 @@ var installSystemPackage = async (packageEnt, context) => {
|
|
|
180
181
|
const errorMessage = `No package ent for: ${packageEnt}`;
|
|
181
182
|
throw new Error(errorMessage);
|
|
182
183
|
}
|
|
183
|
-
const
|
|
184
|
+
const { stdout: osRaw } = await execCommand("cat /etc/os-release | grep ^ID= | cut -d'=' -f2", {}, context);
|
|
185
|
+
const osName = osRaw.trim().replace(/"/g, "");
|
|
184
186
|
const manager = getManagerByOs(osName);
|
|
185
187
|
const managerConfig = getManagerConfig(manager, finalPackageEnt);
|
|
186
188
|
const checkResult = await execCommandMayError(`command -v ${managerConfig.command}`, {}, context);
|
|
@@ -189,13 +191,6 @@ var installSystemPackage = async (packageEnt, context) => {
|
|
|
189
191
|
}
|
|
190
192
|
const installCommand = getInstallCommand(manager, managerConfig);
|
|
191
193
|
await execCommand(installCommand, {}, context);
|
|
192
|
-
if (osName === "ubuntu") {
|
|
193
|
-
await execCommand(`apt-get install -y ${managerConfig.name}`, {}, context);
|
|
194
|
-
} else if (dnfOs.includes(osName)) {
|
|
195
|
-
await execCommand(`dnf install -y ${managerConfig.name}`, {}, context);
|
|
196
|
-
} else {
|
|
197
|
-
throw new Error(`Unsupported OS: ${osName}`);
|
|
198
|
-
}
|
|
199
194
|
};
|
|
200
195
|
|
|
201
196
|
// src/files.ts
|
|
@@ -225,13 +220,13 @@ var normalizeFileContent = (str) => {
|
|
|
225
220
|
}
|
|
226
221
|
return str;
|
|
227
222
|
};
|
|
228
|
-
var createDir = async (str) => {
|
|
223
|
+
var createDir = async (str, context = defaultContext) => {
|
|
229
224
|
const dirname = str.split("/").slice(0, -1).join("/");
|
|
230
225
|
const exist = await exists(dirname);
|
|
231
226
|
if (exist) {
|
|
232
227
|
return;
|
|
233
228
|
}
|
|
234
|
-
await execCommand(`mkdir -p ${dirname}
|
|
229
|
+
await execCommand(`mkdir -p ${dirname}`, {}, context);
|
|
235
230
|
};
|
|
236
231
|
var checkStrInFile = async (filePath, str) => {
|
|
237
232
|
const file2 = Bun.file(filePath);
|
|
@@ -244,29 +239,24 @@ var checkStrInFile = async (filePath, str) => {
|
|
|
244
239
|
}
|
|
245
240
|
return false;
|
|
246
241
|
};
|
|
247
|
-
var createFileIfNeed = async (rawFilePath) => {
|
|
242
|
+
var createFileIfNeed = async (rawFilePath, context = defaultContext) => {
|
|
248
243
|
const filePath = normalizePath(rawFilePath);
|
|
249
|
-
await createDir(filePath);
|
|
244
|
+
await createDir(filePath, context);
|
|
250
245
|
if (!await file(filePath).exists()) {
|
|
251
|
-
await execCommand(`touch ${filePath}
|
|
246
|
+
await execCommand(`touch ${filePath}`, {}, context);
|
|
252
247
|
}
|
|
253
248
|
};
|
|
254
|
-
var
|
|
249
|
+
var writeFileStrUniq = async (rawFilePath, str, context = defaultContext) => {
|
|
255
250
|
const filePath = normalizePath(rawFilePath);
|
|
256
|
-
await createFileIfNeed(filePath);
|
|
251
|
+
await createFileIfNeed(filePath, context);
|
|
257
252
|
if (await checkStrInFile(filePath, str)) {
|
|
258
253
|
return;
|
|
259
254
|
}
|
|
260
255
|
await appendFile(filePath, normalizeFileContent(str));
|
|
261
256
|
};
|
|
262
|
-
var writeFile = async (pathToFile, str) => {
|
|
257
|
+
var writeFile = async (pathToFile, str, context = defaultContext) => {
|
|
263
258
|
const normalizedPath = normalizePath(pathToFile);
|
|
264
|
-
await createFileIfNeed(normalizedPath);
|
|
265
|
-
await write(normalizedPath, str);
|
|
266
|
-
};
|
|
267
|
-
var writeFileFull = async (pathToFile, str) => {
|
|
268
|
-
const normalizedPath = normalizePath(pathToFile);
|
|
269
|
-
await createFileIfNeed(normalizedPath);
|
|
259
|
+
await createFileIfNeed(normalizedPath, context);
|
|
270
260
|
const fileText = await file(normalizedPath).text();
|
|
271
261
|
if (fileText === str) {
|
|
272
262
|
return;
|
|
@@ -286,7 +276,7 @@ var reloadSystemd = async (context = defaultContext) => {
|
|
|
286
276
|
var startSystemdUnit = async (unitName, context = defaultContext) => {
|
|
287
277
|
await execCommand(formatUserspace(`systemctl start ${unitName}`, context));
|
|
288
278
|
};
|
|
289
|
-
var
|
|
279
|
+
var enableSystemdUnit = async (unitName, context = defaultContext) => {
|
|
290
280
|
await execCommand(formatUserspace(`systemctl enable ${unitName}`, context));
|
|
291
281
|
};
|
|
292
282
|
var restartSystemdUnit = async (name, context = defaultContext) => {
|
|
@@ -301,7 +291,7 @@ var checkSystemdUnit = async (serviceName, context = defaultContext) => {
|
|
|
301
291
|
};
|
|
302
292
|
var createSystemdUnit = async (unitName, content, context = defaultContext) => {
|
|
303
293
|
const pathToSeviceTarget = getSystemdPathToUnit(unitName, context);
|
|
304
|
-
await
|
|
294
|
+
await writeFile(pathToSeviceTarget, content);
|
|
305
295
|
await reloadSystemd(context);
|
|
306
296
|
};
|
|
307
297
|
var getSystemdPathToUnit = (serviceName, context = defaultContext) => {
|
|
@@ -312,7 +302,7 @@ var getSystemdPathToUnit = (serviceName, context = defaultContext) => {
|
|
|
312
302
|
};
|
|
313
303
|
var createSystemdService = async (serviceName, content, context = defaultContext) => {
|
|
314
304
|
await createSystemdUnit(serviceName, content, context);
|
|
315
|
-
await
|
|
305
|
+
await enableSystemdUnit(serviceName, context);
|
|
316
306
|
await startSystemdUnit(serviceName, context);
|
|
317
307
|
};
|
|
318
308
|
|
|
@@ -356,48 +346,54 @@ var createNftTable = ({
|
|
|
356
346
|
};
|
|
357
347
|
var setupNftable = async ({
|
|
358
348
|
allowedIpV4,
|
|
359
|
-
allowedPorts
|
|
349
|
+
allowedPorts,
|
|
350
|
+
context = defaultContext
|
|
360
351
|
}) => {
|
|
361
|
-
await installSystemPackage("nftables");
|
|
362
|
-
const listTable = await execCommandMayError("nft list table inet ramm");
|
|
352
|
+
await installSystemPackage("nftables", context);
|
|
353
|
+
const listTable = await execCommandMayError("nft list table inet ramm", {}, context);
|
|
363
354
|
if (listTable.spawnResult.exitCode === 0) {
|
|
364
|
-
await execCommand("nft delete table inet ramm");
|
|
355
|
+
await execCommand("nft delete table inet ramm", {}, context);
|
|
365
356
|
}
|
|
366
357
|
const nftTable = createNftTable({ allowedIpV4, allowedPorts });
|
|
367
358
|
await execCommand(`nft -f - <<EOF
|
|
368
359
|
${nftTable}
|
|
369
|
-
EOF
|
|
370
|
-
await safeNftTable();
|
|
360
|
+
EOF`, {}, context);
|
|
361
|
+
await safeNftTable(context);
|
|
371
362
|
};
|
|
372
|
-
var safeNftTable = async () => {
|
|
373
|
-
await execCommand("nft list ruleset > /etc/nftables.conf");
|
|
374
|
-
await execCommand("systemctl enable nftables");
|
|
363
|
+
var safeNftTable = async (context = defaultContext) => {
|
|
364
|
+
await execCommand("nft list ruleset > /etc/nftables.conf", {}, context);
|
|
365
|
+
await execCommand("systemctl enable nftables", {}, context);
|
|
375
366
|
};
|
|
376
367
|
|
|
377
368
|
// src/podman.ts
|
|
378
|
-
var installPodman = async () => {
|
|
379
|
-
|
|
380
|
-
|
|
369
|
+
var installPodman = async (context = defaultContext) => {
|
|
370
|
+
const check = await execCommandMayError("command -v podman", {}, context);
|
|
371
|
+
if (check.spawnResult.exitCode !== 0) {
|
|
372
|
+
await installSystemPackage("podman", context);
|
|
381
373
|
}
|
|
382
|
-
await createNetwork();
|
|
374
|
+
await createNetwork(context);
|
|
383
375
|
};
|
|
384
|
-
var createNetwork = async () => {
|
|
385
|
-
const netwroks = await execCommand("podman network inspect $(podman network ls -q) -f '{{.NetworkInterface}}'");
|
|
386
|
-
const podmanNetworks = await execCommand("podman network ls");
|
|
376
|
+
var createNetwork = async (context = defaultContext) => {
|
|
377
|
+
const netwroks = await execCommand("podman network inspect $(podman network ls -q) -f '{{.NetworkInterface}}'", {}, context);
|
|
378
|
+
const podmanNetworks = await execCommand("podman network ls", {}, context);
|
|
387
379
|
if (podmanNetworks.stdout.includes("ramm")) {
|
|
388
380
|
return;
|
|
389
381
|
}
|
|
390
382
|
if (netwroks.stdout.includes("podman_ramm")) {
|
|
391
383
|
return;
|
|
392
384
|
}
|
|
393
|
-
await execCommand("podman network create --interface-name=podman_ramm ramm");
|
|
385
|
+
await execCommand("podman network create --interface-name=podman_ramm ramm", {}, context);
|
|
394
386
|
};
|
|
395
|
-
var getCreateCommand = async (name) => {
|
|
396
|
-
const
|
|
397
|
-
|
|
387
|
+
var getCreateCommand = async (name, context = defaultContext) => {
|
|
388
|
+
const result = await execCommandMayError(`podman inspect --format '{{.Config.CreateCommand}}' ${name}`, {}, context);
|
|
389
|
+
const text = result.stdout.trim();
|
|
390
|
+
if (text.startsWith("[") && text.endsWith("]")) {
|
|
391
|
+
return text.slice(1, -1);
|
|
392
|
+
}
|
|
393
|
+
return text;
|
|
398
394
|
};
|
|
399
|
-
var loginPodman = async (address, login, password) => {
|
|
400
|
-
return await execCommand(`echo "${password}" | podman login --username "${login}" --password-stdin ${address}
|
|
395
|
+
var loginPodman = async (address, login, password, context = defaultContext) => {
|
|
396
|
+
return await execCommand(`echo "${password}" | podman login --username "${login}" --password-stdin ${address}`, {}, context);
|
|
401
397
|
};
|
|
402
398
|
var createPodmanCommand = ({
|
|
403
399
|
name,
|
|
@@ -432,10 +428,10 @@ var createPodmanCommand = ({
|
|
|
432
428
|
const str = values.join(" ");
|
|
433
429
|
return str;
|
|
434
430
|
};
|
|
435
|
-
var runPodmanContainer = async (name, command) => {
|
|
436
|
-
if (await getCreateCommand(name) !== command) {
|
|
437
|
-
await
|
|
438
|
-
await execCommand(command);
|
|
431
|
+
var runPodmanContainer = async (name, command, context = defaultContext) => {
|
|
432
|
+
if (await getCreateCommand(name, context) !== command) {
|
|
433
|
+
await execCommand(`podman rm -f ${name}`, {}, context);
|
|
434
|
+
await execCommand(command, {}, context);
|
|
439
435
|
return;
|
|
440
436
|
}
|
|
441
437
|
console.info("Podman container is already running");
|
|
@@ -446,27 +442,27 @@ var runPodmanContainerService = async (name, command, context = defaultContext)
|
|
|
446
442
|
if (await checkSystemdUnit(serviceName, context)) {
|
|
447
443
|
await stopSystemdUnit(serviceName, context);
|
|
448
444
|
}
|
|
449
|
-
await runPodmanContainer(name, command);
|
|
450
|
-
await execCommand(`podman generate systemd --name --new ${name} > ${filepath}
|
|
445
|
+
await runPodmanContainer(name, command, context);
|
|
446
|
+
await execCommand(`podman generate systemd --name --new ${name} > ${filepath}`, {}, context);
|
|
451
447
|
await reloadSystemd(context);
|
|
452
448
|
await startSystemdUnit(serviceName, context);
|
|
453
|
-
await
|
|
449
|
+
await enableSystemdUnit(serviceName, context);
|
|
454
450
|
};
|
|
455
|
-
var addNftPodmanRule = async () => {
|
|
456
|
-
const podmanNetworksResult = await execCommand("podman network inspect $(podman network ls -q) -f '{{.NetworkInterface}}'");
|
|
451
|
+
var addNftPodmanRule = async (context = defaultContext) => {
|
|
452
|
+
const podmanNetworksResult = await execCommand("podman network inspect $(podman network ls -q) -f '{{.NetworkInterface}}'", {}, context);
|
|
457
453
|
const podmanNetworks = podmanNetworksResult.stdout.trim().split(`
|
|
458
454
|
`);
|
|
459
|
-
await execCommand(`nft add set inet ramm podman_interfaces '{ type ifname; flags dynamic; elements = { ${podmanNetworks.join(", ")} }; }'
|
|
460
|
-
await execCommand("nft insert rule inet ramm prerouting iifname @podman_interfaces accept");
|
|
461
|
-
await safeNftTable();
|
|
455
|
+
await execCommand(`nft add set inet ramm podman_interfaces '{ type ifname; flags dynamic; elements = { ${podmanNetworks.join(", ")} }; }'`, {}, context);
|
|
456
|
+
await execCommand("nft insert rule inet ramm prerouting iifname @podman_interfaces accept", {}, context);
|
|
457
|
+
await safeNftTable(context);
|
|
462
458
|
};
|
|
463
459
|
// src/ssh.ts
|
|
464
460
|
var {file: file2 } = globalThis.Bun;
|
|
465
|
-
var addKeyToHostConfig = async (pathToHost, address, pathToKey) => {
|
|
461
|
+
var addKeyToHostConfig = async (pathToHost, address, pathToKey, context = defaultContext) => {
|
|
466
462
|
const text = `Host ${address}
|
|
467
463
|
IdentityFile ${pathToKey}
|
|
468
464
|
`;
|
|
469
|
-
await
|
|
465
|
+
await writeFileStrUniq(pathToHost, text, context);
|
|
470
466
|
};
|
|
471
467
|
var getServerFingerprint = async (context) => {
|
|
472
468
|
const { stdout } = await execCommandOverSsh('ssh-keyscan -t ed25519 localhost | grep -v "^#"', context);
|
|
@@ -475,9 +471,9 @@ var getServerFingerprint = async (context) => {
|
|
|
475
471
|
var saveSshFingerptint = async (filePath, context) => {
|
|
476
472
|
const normalizedPath = normalizePath(filePath);
|
|
477
473
|
const fingerprint = await getServerFingerprint(context);
|
|
478
|
-
await
|
|
474
|
+
await writeFile(normalizedPath, fingerprint, context);
|
|
479
475
|
};
|
|
480
|
-
async function createSshKey(filePath, comment) {
|
|
476
|
+
async function createSshKey(filePath, comment, context = defaultContext) {
|
|
481
477
|
printFunction(`${createSshKey.name} ${filePath}`);
|
|
482
478
|
const normalizedPathToKey = normalizePath(filePath);
|
|
483
479
|
const name = normalizedPathToKey.split("/").at(-1);
|
|
@@ -488,9 +484,9 @@ async function createSshKey(filePath, comment) {
|
|
|
488
484
|
if (await pathToKeyFile.exists() && await pathToKeyPubFile.exists()) {
|
|
489
485
|
return await pathToKeyPubFile.text();
|
|
490
486
|
}
|
|
491
|
-
await execCommand(`mkdir -p ${pathToDir}
|
|
492
|
-
await execCommand(`ssh-keygen -t ed25519 -f ${normalizedPathToKey} -N "" -C "${comment || name}"
|
|
493
|
-
await execCommand(`chmod 600 ${normalizedPathToKey}
|
|
487
|
+
await execCommand(`mkdir -p ${pathToDir}`, {}, context);
|
|
488
|
+
await execCommand(`ssh-keygen -t ed25519 -f ${normalizedPathToKey} -N "" -C "${comment || name}"`, {}, context);
|
|
489
|
+
await execCommand(`chmod 600 ${normalizedPathToKey}`, {}, context);
|
|
494
490
|
const pubKey = await Bun.file(pathToKeyPub).text();
|
|
495
491
|
return pubKey;
|
|
496
492
|
}
|
|
@@ -504,7 +500,7 @@ var addSshKeyToAuthorizedOverSsh = async (pubKey, context) => {
|
|
|
504
500
|
};
|
|
505
501
|
var createAndAddSshKey = async (filePath, comment, context) => {
|
|
506
502
|
const normalizedPath = normalizePath(filePath);
|
|
507
|
-
const pubKey = await createSshKey(normalizedPath, comment);
|
|
503
|
+
const pubKey = await createSshKey(normalizedPath, comment, context);
|
|
508
504
|
console.log(`Key is: ${pubKey}`);
|
|
509
505
|
await addSshKeyToAuthorizedOverSsh(pubKey, context);
|
|
510
506
|
};
|
|
@@ -512,38 +508,40 @@ var addSshKeyToUse = async ({
|
|
|
512
508
|
key,
|
|
513
509
|
fingerprint,
|
|
514
510
|
filePath,
|
|
515
|
-
server
|
|
511
|
+
server,
|
|
512
|
+
context = defaultContext
|
|
516
513
|
}) => {
|
|
517
514
|
printFunction(`${addSshKeyToUse.name} ${filePath}`);
|
|
518
515
|
const normalizedFilePath = normalizePath(filePath);
|
|
519
|
-
await
|
|
520
|
-
await execCommand(`chmod 0600 ${normalizedFilePath}
|
|
521
|
-
await
|
|
522
|
-
await addKeyToHostConfig("~/.ssh/config", server, normalizedFilePath);
|
|
516
|
+
await writeFile(normalizedFilePath, key, context);
|
|
517
|
+
await execCommand(`chmod 0600 ${normalizedFilePath}`, {}, context);
|
|
518
|
+
await writeFileStrUniq("~/.ssh/known_hosts", fingerprint, context);
|
|
519
|
+
await addKeyToHostConfig("~/.ssh/config", server, normalizedFilePath, context);
|
|
523
520
|
};
|
|
524
521
|
// src/cron.ts
|
|
525
522
|
var createCron = async ({
|
|
526
523
|
time,
|
|
527
|
-
pathToFile
|
|
524
|
+
pathToFile,
|
|
525
|
+
context = defaultContext
|
|
528
526
|
}) => {
|
|
529
527
|
const pathToFileNorm = normalizePath(pathToFile);
|
|
530
528
|
const constructedLine = `${time} ${pathToFileNorm}`;
|
|
531
|
-
const tempFile = `/tmp/ramm_cron
|
|
532
|
-
const { stdout: cronConfig } = await execCommandMayError("crontab -l");
|
|
533
|
-
let newCronConfig = cronConfig;
|
|
529
|
+
const tempFile = `/tmp/ramm_cron`;
|
|
530
|
+
const { stdout: cronConfig } = await execCommandMayError("crontab -l", {}, context);
|
|
534
531
|
if (cronConfig.includes(constructedLine)) {
|
|
535
532
|
return;
|
|
536
533
|
}
|
|
534
|
+
let baseCronConfig = cronConfig;
|
|
537
535
|
if (cronConfig.includes(pathToFileNorm)) {
|
|
538
|
-
|
|
536
|
+
baseCronConfig = cronConfig.split(`
|
|
539
537
|
`).filter((str) => !str.includes(pathToFileNorm)).join(`
|
|
540
538
|
`);
|
|
541
539
|
}
|
|
542
|
-
newCronConfig = normalizeFileContent(normalizeFileContent(
|
|
543
|
-
await writeFile(tempFile, newCronConfig);
|
|
544
|
-
await execCommandMayError(`cat ${tempFile}
|
|
545
|
-
await execCommandMayError(`crontab ${tempFile}
|
|
546
|
-
await execCommandMayError(`rm ${tempFile}
|
|
540
|
+
const newCronConfig = normalizeFileContent(normalizeFileContent(baseCronConfig) + constructedLine);
|
|
541
|
+
await writeFile(tempFile, newCronConfig, context);
|
|
542
|
+
await execCommandMayError(`cat ${tempFile}`, {}, context);
|
|
543
|
+
await execCommandMayError(`crontab ${tempFile}`, {}, context);
|
|
544
|
+
await execCommandMayError(`rm ${tempFile}`, {}, context);
|
|
547
545
|
};
|
|
548
546
|
// src/build.ts
|
|
549
547
|
var {build, file: file3 } = globalThis.Bun;
|
|
@@ -561,27 +559,26 @@ var buildAndRunOverSsh = async ({
|
|
|
561
559
|
});
|
|
562
560
|
const pathToDistFile = outputs.outputs[0]?.path;
|
|
563
561
|
const relativePathToFile = pathToDistFile.slice(distDir.length + 1);
|
|
564
|
-
await
|
|
562
|
+
await copyFilesOverSsh(`${distDir}/`, distDir, context);
|
|
565
563
|
await execCommandOverSsh(`bun run ${distDir}/${relativePathToFile}`, context);
|
|
566
|
-
await execCommand(`rm -rf ${distDir}
|
|
564
|
+
await execCommand(`rm -rf ${distDir}`, {}, context);
|
|
567
565
|
};
|
|
568
566
|
var pathToJson = "/tmp/ramm_json";
|
|
569
567
|
var passVarsClient = async (data, context) => {
|
|
570
568
|
printFunction("passVarsClient");
|
|
571
569
|
const json = JSON.stringify(data);
|
|
572
|
-
await writeFile(pathToJson, json);
|
|
573
|
-
await
|
|
574
|
-
await execCommand(`rm -rf ${pathToJson}
|
|
570
|
+
await writeFile(pathToJson, json, context);
|
|
571
|
+
await copyFilesOverSsh(pathToJson, pathToJson, context);
|
|
572
|
+
await execCommand(`rm -rf ${pathToJson}`, {}, context);
|
|
575
573
|
};
|
|
576
|
-
var passVarsServer = async () => {
|
|
574
|
+
var passVarsServer = async (context = defaultContext) => {
|
|
577
575
|
printFunction("passVarsServer");
|
|
578
576
|
const jsonData = await file3(pathToJson).json();
|
|
579
|
-
await execCommand(`rm -rf ${pathToJson}
|
|
577
|
+
await execCommand(`rm -rf ${pathToJson}`, {}, context);
|
|
580
578
|
return jsonData;
|
|
581
579
|
};
|
|
582
580
|
export {
|
|
583
|
-
|
|
584
|
-
writeFileFull,
|
|
581
|
+
writeFileStrUniq,
|
|
585
582
|
writeFile,
|
|
586
583
|
startSystemdUnit,
|
|
587
584
|
setupNftable,
|
|
@@ -599,19 +596,19 @@ export {
|
|
|
599
596
|
installSystemPackage,
|
|
600
597
|
installPodman,
|
|
601
598
|
installBunOverSsh,
|
|
602
|
-
getSystemdPathToUnit
|
|
599
|
+
getSystemdPathToUnit,
|
|
603
600
|
getServerFingerprint,
|
|
604
601
|
execCommandRaw,
|
|
605
602
|
execCommandOverSsh,
|
|
606
603
|
execCommandMayError,
|
|
607
604
|
execCommand,
|
|
608
|
-
|
|
605
|
+
enableSystemdUnit,
|
|
609
606
|
createSystemdUnit,
|
|
610
607
|
createSystemdService,
|
|
611
608
|
createPodmanCommand,
|
|
612
609
|
createCron,
|
|
613
610
|
createAndAddSshKey,
|
|
614
|
-
|
|
611
|
+
copyFilesOverSsh,
|
|
615
612
|
buildAndRunOverSsh,
|
|
616
613
|
addSshKeyToUse,
|
|
617
614
|
addNftPodmanRule,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ramm",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.63",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "bun build ./src/ramm.ts --target bun --outdir ./dist && cp ./src/bun.sh ./dist/bun.sh",
|
|
7
7
|
"types": "tsc --project tsconfig.types.json"
|
|
@@ -14,9 +14,13 @@
|
|
|
14
14
|
"engines": {
|
|
15
15
|
"bun": ">=1.0.0"
|
|
16
16
|
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/utftu/ramm.git"
|
|
20
|
+
},
|
|
17
21
|
"devDependencies": {
|
|
18
22
|
"@types/bun": "latest",
|
|
19
23
|
"typescript": "^5.8.2",
|
|
20
24
|
"dapes": "^0.0.26"
|
|
21
25
|
}
|
|
22
|
-
}
|
|
26
|
+
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { type Subprocess } from "bun";
|
|
2
|
-
import { Context } from "../context.ts";
|
|
3
|
-
export declare const defaultContext: Context;
|
|
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, ctx?: Context) => Promise<{
|
|
15
|
-
stderr: string;
|
|
16
|
-
stdout: string;
|
|
17
|
-
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
18
|
-
}>;
|
|
19
|
-
export declare const execCommandMayError: (command: string, props: ExecProps, context?: Context) => Promise<{
|
|
20
|
-
stderr: string;
|
|
21
|
-
stdout: string;
|
|
22
|
-
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
23
|
-
}>;
|
|
24
|
-
export declare const execCommand: (command: string, props: ExecProps, context?: Context) => Promise<{
|
|
25
|
-
stderr: string;
|
|
26
|
-
stdout: string;
|
|
27
|
-
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
28
|
-
}>;
|
|
29
|
-
export declare const copyFilesBySsh: (from: string, to: string, context: Context) => Promise<void>;
|
|
30
|
-
export declare const execCommandOverSsh: (command: string, context: Context) => Promise<{
|
|
31
|
-
stderr: string;
|
|
32
|
-
stdout: string;
|
|
33
|
-
spawnResult: Subprocess<"inherit", "pipe", "pipe">;
|
|
34
|
-
}>;
|
|
35
|
-
export {};
|
package/dist/types/base/tee.d.ts
DELETED
package/dist/types/build.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Context } from "./context.ts";
|
|
2
|
-
export declare const buildAndRunOverSsh: ({ entrypoint, context, }: {
|
|
3
|
-
entrypoint: string;
|
|
4
|
-
context: Context;
|
|
5
|
-
}) => Promise<void>;
|
|
6
|
-
export declare const passVarsClient: (data: Record<string, any>, context: Context) => Promise<void>;
|
|
7
|
-
export declare const passVarsServer: () => Promise<any>;
|
package/dist/types/context.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export declare class Context {
|
|
2
|
-
user: string;
|
|
3
|
-
domain: string;
|
|
4
|
-
userspace: boolean;
|
|
5
|
-
sudo: boolean;
|
|
6
|
-
sshKey?: string;
|
|
7
|
-
params: Record<string, string>;
|
|
8
|
-
constructor({ user, address, userspace, sudo, sshKey, }: {
|
|
9
|
-
user: string;
|
|
10
|
-
address: string;
|
|
11
|
-
userspace?: boolean;
|
|
12
|
-
sudo?: boolean;
|
|
13
|
-
sshKey?: string;
|
|
14
|
-
});
|
|
15
|
-
getAddress(): string;
|
|
16
|
-
}
|
package/dist/types/cron.d.ts
DELETED
package/dist/types/files.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export declare const normalizeFileContent: (str: string) => string;
|
|
2
|
-
export declare const writeIfNewStr: (rawFilePath: string, str: string) => Promise<void>;
|
|
3
|
-
export declare const writeFile: (pathToFile: string, str: string) => Promise<void>;
|
|
4
|
-
export declare const writeFileFull: (pathToFile: string, str: string) => Promise<void>;
|
package/dist/types/init.d.ts
DELETED
package/dist/types/nft.d.ts
DELETED
package/dist/types/packages.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Context } from "./context.ts";
|
|
2
|
-
type Manager = "dnf" | "apt";
|
|
3
|
-
type PackageConfig = {
|
|
4
|
-
name: string;
|
|
5
|
-
command: string;
|
|
6
|
-
managers?: Record<Manager, ManagerConfig>;
|
|
7
|
-
};
|
|
8
|
-
type ManagerConfig = {
|
|
9
|
-
name: string;
|
|
10
|
-
command: string;
|
|
11
|
-
};
|
|
12
|
-
export declare const installSystemPackage: (packageEnt: string | PackageConfig, context?: Context) => Promise<void>;
|
|
13
|
-
export {};
|
package/dist/types/path.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function normalizePath(rawFilePath: string): string;
|
package/dist/types/podman.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { Context } from "./context.ts";
|
|
2
|
-
export declare const installPodman: () => Promise<void>;
|
|
3
|
-
export declare const loginPodman: (address: string, login: string, password: string) => Promise<{
|
|
4
|
-
stderr: string;
|
|
5
|
-
stdout: string;
|
|
6
|
-
spawnResult: import("bun").Subprocess<"inherit", "pipe", "pipe">;
|
|
7
|
-
}>;
|
|
8
|
-
export declare const createPodmanCommand: ({ name, replace, background, networks, envs, volumes, command, }: {
|
|
9
|
-
name?: string;
|
|
10
|
-
replace?: boolean;
|
|
11
|
-
background?: boolean;
|
|
12
|
-
networks?: string[];
|
|
13
|
-
envs?: {
|
|
14
|
-
name: string;
|
|
15
|
-
value: string;
|
|
16
|
-
}[];
|
|
17
|
-
volumes?: {
|
|
18
|
-
from: string;
|
|
19
|
-
to: string;
|
|
20
|
-
}[];
|
|
21
|
-
command: string;
|
|
22
|
-
}) => string;
|
|
23
|
-
export declare const runPodmanContainer: (name: string, command: string) => Promise<void>;
|
|
24
|
-
export declare const runPodmanContainerService: (name: string, command: string, context?: Context) => Promise<void>;
|
|
25
|
-
export declare const addNftPodmanRule: () => Promise<void>;
|
package/dist/types/print.d.ts
DELETED
package/dist/types/ramm.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export { execCommandOverSsh, execCommand, execCommandMayError, copyFilesBySsh, execCommandRaw, } from "./base/base.ts";
|
|
2
|
-
export { Context } from "./context.ts";
|
|
3
|
-
export { installBunOverSsh } from "./init.ts";
|
|
4
|
-
export { installPodman, runPodmanContainer, loginPodman, runPodmanContainerService, addNftPodmanRule, createPodmanCommand, } from "./podman.ts";
|
|
5
|
-
export { startSystemdUnit, enabledSystemdUnit, restartSystemdUnit, createSystemdService, getSystemdPathToUnit as getSystemdPathToService, createSystemdUnit, reloadSystemd, } from "./systemd.ts";
|
|
6
|
-
export { installSystemPackage } from "./packages.ts";
|
|
7
|
-
export { printBlock } from "./print.ts";
|
|
8
|
-
export { setupNftable } from "./nft.ts";
|
|
9
|
-
export { writeIfNewStr, writeFile, writeFileFull, normalizeFileContent, } from "./files.ts";
|
|
10
|
-
export { createAndAddSshKey, getServerFingerprint, addKeyToHostConfig, addSshKeyToUse, saveSshFingerptint, } from "./ssh.ts";
|
|
11
|
-
export { normalizePath } from "./path.ts";
|
|
12
|
-
export { createCron } from "./cron.ts";
|
|
13
|
-
export { buildAndRunOverSsh, passVarsClient, passVarsServer } from "./build.ts";
|
package/dist/types/ssh.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Context } from "./context.ts";
|
|
2
|
-
export declare const addKeyToHostConfig: (pathToHost: string, address: string, pathToKey: string) => Promise<void>;
|
|
3
|
-
export declare const getServerFingerprint: (context: Context) => Promise<string>;
|
|
4
|
-
export declare const saveSshFingerptint: (filePath: string, context: Context) => Promise<void>;
|
|
5
|
-
export declare const createAndAddSshKey: (filePath: string, comment: string, context: Context) => Promise<void>;
|
|
6
|
-
export declare const addSshKeyToUse: ({ key, fingerprint, filePath, server, }: {
|
|
7
|
-
key: string;
|
|
8
|
-
fingerprint: string;
|
|
9
|
-
filePath: string;
|
|
10
|
-
server: string;
|
|
11
|
-
}) => Promise<void>;
|
package/dist/types/systemd.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Context } from "./context.ts";
|
|
2
|
-
export declare const reloadSystemd: (context?: Context) => Promise<void>;
|
|
3
|
-
export declare const startSystemdUnit: (unitName: string, context?: Context) => Promise<void>;
|
|
4
|
-
export declare const enabledSystemdUnit: (unitName: string, context?: Context) => Promise<void>;
|
|
5
|
-
export declare const restartSystemdUnit: (name: string, context?: Context) => Promise<void>;
|
|
6
|
-
export declare const stopSystemdUnit: (name: string, context?: Context) => Promise<void>;
|
|
7
|
-
export declare const checkSystemdUnit: (serviceName: string, context?: Context) => Promise<boolean>;
|
|
8
|
-
export declare const createSystemdUnit: (unitName: string, content: string, context?: Context) => Promise<void>;
|
|
9
|
-
export declare const getSystemdPathToUnit: (serviceName: string, context?: Context) => string;
|
|
10
|
-
export declare const createSystemdService: (serviceName: string, content: string, context?: Context) => Promise<void>;
|