@mittwald/cli 1.0.0-alpha.35 → 1.0.0-alpha.36
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 +53 -14
- package/dist/esm/commands/app/download.d.ts +1 -0
- package/dist/esm/commands/app/download.js +4 -2
- package/dist/esm/commands/app/ssh.d.ts +1 -0
- package/dist/esm/commands/app/ssh.js +3 -1
- package/dist/esm/commands/database/mysql/dump.d.ts +2 -0
- package/dist/esm/commands/database/mysql/dump.js +18 -1
- package/dist/esm/commands/database/mysql/port-forward.d.ts +1 -0
- package/dist/esm/commands/database/mysql/port-forward.js +3 -1
- package/dist/esm/lib/database/mysql/connect.d.ts +2 -1
- package/dist/esm/lib/database/mysql/connect.js +8 -6
- package/dist/esm/lib/ssh/appinstall.d.ts +1 -1
- package/dist/esm/lib/ssh/appinstall.js +7 -4
- package/dist/esm/lib/ssh/exec.d.ts +7 -1
- package/dist/esm/lib/ssh/exec.js +9 -6
- package/dist/esm/lib/ssh/flags.d.ts +3 -0
- package/dist/esm/lib/ssh/flags.js +13 -0
- package/dist/esm/lib/ssh/project.d.ts +1 -1
- package/dist/esm/lib/ssh/project.js +7 -4
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ either the CMD prompt or PowerShell.
|
|
|
42
42
|
#### Any OS, using Node.js+NPM
|
|
43
43
|
|
|
44
44
|
Installing the CLI via NPM will work on any OS; however we cannot guarantee
|
|
45
|
-
stability, because functionality of the CLI may depend
|
|
45
|
+
stability, because functionality of the CLI may depend on the Node.js runtime
|
|
46
46
|
already installed on your system. Also, the automatic upgrade will not work when
|
|
47
47
|
using NPM; remember to run `npm upgrade -g @mittwald/cli` occasionally.
|
|
48
48
|
|
|
@@ -551,17 +551,18 @@ Download the filesystem of an app within a project to your local machine
|
|
|
551
551
|
|
|
552
552
|
```
|
|
553
553
|
USAGE
|
|
554
|
-
$ mw app download [INSTALLATION-ID] --target <value> [-q] [--dry-run] [--delete]
|
|
554
|
+
$ mw app download [INSTALLATION-ID] --target <value> [-q] [--ssh-user <value>] [--dry-run] [--delete]
|
|
555
555
|
|
|
556
556
|
ARGUMENTS
|
|
557
557
|
INSTALLATION-ID ID or short ID of an app installation; this argument is optional if a default app installation is set
|
|
558
558
|
in the context
|
|
559
559
|
|
|
560
560
|
FLAGS
|
|
561
|
-
-q, --quiet
|
|
562
|
-
--delete
|
|
563
|
-
--dry-run
|
|
564
|
-
--
|
|
561
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
562
|
+
--delete delete local files that are not present on the server
|
|
563
|
+
--dry-run do not actually download the app installation
|
|
564
|
+
--ssh-user=<value> override the SSH user to connect with; if omitted, your own user will be used
|
|
565
|
+
--target=<value> (required) target directory to download the app installation to
|
|
565
566
|
|
|
566
567
|
DESCRIPTION
|
|
567
568
|
Download the filesystem of an app within a project to your local machine
|
|
@@ -571,6 +572,13 @@ FLAG DESCRIPTIONS
|
|
|
571
572
|
|
|
572
573
|
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
573
574
|
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
575
|
+
|
|
576
|
+
--ssh-user=<value> override the SSH user to connect with; if omitted, your own user will be used
|
|
577
|
+
|
|
578
|
+
This flag can be used to override the SSH user that is used for a connection; be default, your own personal user
|
|
579
|
+
will be used for this.
|
|
580
|
+
|
|
581
|
+
You can also set this value by setting the MITTWALD_SSH_USER environment variable.
|
|
574
582
|
```
|
|
575
583
|
|
|
576
584
|
## `mw app get [INSTALLATION-ID]`
|
|
@@ -1479,19 +1487,28 @@ Connect to an app via SSH
|
|
|
1479
1487
|
|
|
1480
1488
|
```
|
|
1481
1489
|
USAGE
|
|
1482
|
-
$ mw app ssh [INSTALLATION-ID] [--cd] [--info] [--test]
|
|
1490
|
+
$ mw app ssh [INSTALLATION-ID] [--ssh-user <value>] [--cd] [--info] [--test]
|
|
1483
1491
|
|
|
1484
1492
|
ARGUMENTS
|
|
1485
1493
|
INSTALLATION-ID ID or short ID of an app installation; this argument is optional if a default app installation is set
|
|
1486
1494
|
in the context
|
|
1487
1495
|
|
|
1488
1496
|
FLAGS
|
|
1489
|
-
--[no-]cd
|
|
1490
|
-
--info
|
|
1491
|
-
--
|
|
1497
|
+
--[no-]cd change to installation path after connecting
|
|
1498
|
+
--info only print connection information, without actually connecting
|
|
1499
|
+
--ssh-user=<value> override the SSH user to connect with; if omitted, your own user will be used
|
|
1500
|
+
--test test connection and exit
|
|
1492
1501
|
|
|
1493
1502
|
DESCRIPTION
|
|
1494
1503
|
Connect to an app via SSH
|
|
1504
|
+
|
|
1505
|
+
FLAG DESCRIPTIONS
|
|
1506
|
+
--ssh-user=<value> override the SSH user to connect with; if omitted, your own user will be used
|
|
1507
|
+
|
|
1508
|
+
This flag can be used to override the SSH user that is used for a connection; be default, your own personal user
|
|
1509
|
+
will be used for this.
|
|
1510
|
+
|
|
1511
|
+
You can also set this value by setting the MITTWALD_SSH_USER environment variable.
|
|
1495
1512
|
```
|
|
1496
1513
|
|
|
1497
1514
|
## `mw app uninstall [INSTALLATION-ID]`
|
|
@@ -2269,7 +2286,7 @@ Create a dump of a MySQL database
|
|
|
2269
2286
|
|
|
2270
2287
|
```
|
|
2271
2288
|
USAGE
|
|
2272
|
-
$ mw database mysql dump DATABASE-ID -o <value> [-q] [-p <value>] [--temporary-user]
|
|
2289
|
+
$ mw database mysql dump DATABASE-ID -o <value> [-q] [-p <value>] [--ssh-user <value>] [--temporary-user] [--gzip]
|
|
2273
2290
|
|
|
2274
2291
|
ARGUMENTS
|
|
2275
2292
|
DATABASE-ID The ID of the database (when a project context is set, you can also use the name)
|
|
@@ -2278,6 +2295,8 @@ FLAGS
|
|
|
2278
2295
|
-o, --output=<value> (required) the output file to write the dump to ("-" for stdout)
|
|
2279
2296
|
-p, --mysql-password=<value> the password to use for the MySQL user (env: MYSQL_PWD)
|
|
2280
2297
|
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
2298
|
+
--gzip compress the dump with gzip
|
|
2299
|
+
--ssh-user=<value> override the SSH user to connect with; if omitted, your own user will be used
|
|
2281
2300
|
--[no-]temporary-user create a temporary user for the dump
|
|
2282
2301
|
|
|
2283
2302
|
FLAG DESCRIPTIONS
|
|
@@ -2300,6 +2319,18 @@ FLAG DESCRIPTIONS
|
|
|
2300
2319
|
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
2301
2320
|
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
2302
2321
|
|
|
2322
|
+
--gzip compress the dump with gzip
|
|
2323
|
+
|
|
2324
|
+
Compress the dump with gzip. This is useful for large databases, as it can significantly reduce the size of the
|
|
2325
|
+
dump.
|
|
2326
|
+
|
|
2327
|
+
--ssh-user=<value> override the SSH user to connect with; if omitted, your own user will be used
|
|
2328
|
+
|
|
2329
|
+
This flag can be used to override the SSH user that is used for a connection; be default, your own personal user
|
|
2330
|
+
will be used for this.
|
|
2331
|
+
|
|
2332
|
+
You can also set this value by setting the MITTWALD_SSH_USER environment variable.
|
|
2333
|
+
|
|
2303
2334
|
--[no-]temporary-user create a temporary user for the dump
|
|
2304
2335
|
|
|
2305
2336
|
Create a temporary user for the dump. This user will be deleted after the dump has been created. This is useful if
|
|
@@ -2376,20 +2407,28 @@ Forward the TCP port of a MySQL database to a local port
|
|
|
2376
2407
|
|
|
2377
2408
|
```
|
|
2378
2409
|
USAGE
|
|
2379
|
-
$ mw database mysql port-forward DATABASE-ID [-q] [--port <value>]
|
|
2410
|
+
$ mw database mysql port-forward DATABASE-ID [-q] [--ssh-user <value>] [--port <value>]
|
|
2380
2411
|
|
|
2381
2412
|
ARGUMENTS
|
|
2382
2413
|
DATABASE-ID The ID of the database (when a project context is set, you can also use the name)
|
|
2383
2414
|
|
|
2384
2415
|
FLAGS
|
|
2385
|
-
-q, --quiet
|
|
2386
|
-
--port=<value>
|
|
2416
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
2417
|
+
--port=<value> [default: 3306] The local TCP port to forward to
|
|
2418
|
+
--ssh-user=<value> override the SSH user to connect with; if omitted, your own user will be used
|
|
2387
2419
|
|
|
2388
2420
|
FLAG DESCRIPTIONS
|
|
2389
2421
|
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
2390
2422
|
|
|
2391
2423
|
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
2392
2424
|
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
2425
|
+
|
|
2426
|
+
--ssh-user=<value> override the SSH user to connect with; if omitted, your own user will be used
|
|
2427
|
+
|
|
2428
|
+
This flag can be used to override the SSH user that is used for a connection; be default, your own personal user
|
|
2429
|
+
will be used for this.
|
|
2430
|
+
|
|
2431
|
+
You can also set this value by setting the MITTWALD_SSH_USER environment variable.
|
|
2393
2432
|
```
|
|
2394
2433
|
|
|
2395
2434
|
## `mw database mysql shell DATABASE-ID`
|
|
@@ -9,6 +9,7 @@ export declare class Download extends ExecRenderBaseCommand<typeof Download, voi
|
|
|
9
9
|
"dry-run": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
10
|
delete: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
11
|
target: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
|
+
"ssh-user": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
13
|
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
13
14
|
};
|
|
14
15
|
protected exec(): Promise<void>;
|
|
@@ -7,6 +7,7 @@ import { Success } from "../../rendering/react/components/Success.js";
|
|
|
7
7
|
import { spawn } from "child_process";
|
|
8
8
|
import { hasBinary } from "../../lib/hasbin.js";
|
|
9
9
|
import { getSSHConnectionForAppInstallation } from "../../lib/ssh/appinstall.js";
|
|
10
|
+
import { sshConnectionFlags } from "../../lib/ssh/flags.js";
|
|
10
11
|
export class Download extends ExecRenderBaseCommand {
|
|
11
12
|
static description = "Download the filesystem of an app within a project to your local machine";
|
|
12
13
|
static args = {
|
|
@@ -14,6 +15,7 @@ export class Download extends ExecRenderBaseCommand {
|
|
|
14
15
|
};
|
|
15
16
|
static flags = {
|
|
16
17
|
...processFlags,
|
|
18
|
+
...sshConnectionFlags,
|
|
17
19
|
"dry-run": Flags.boolean({
|
|
18
20
|
description: "do not actually download the app installation",
|
|
19
21
|
default: false,
|
|
@@ -30,10 +32,10 @@ export class Download extends ExecRenderBaseCommand {
|
|
|
30
32
|
};
|
|
31
33
|
async exec() {
|
|
32
34
|
const appInstallationId = await this.withAppInstallationId(Download);
|
|
33
|
-
const { "dry-run": dryRun, target, delete: deleteLocal } = this.flags;
|
|
35
|
+
const { "dry-run": dryRun, target, delete: deleteLocal, "ssh-user": sshUser, } = this.flags;
|
|
34
36
|
const p = makeProcessRenderer(this.flags, "Downloading app installation");
|
|
35
37
|
const { host, user, directory } = await p.runStep("getting connection data", async () => {
|
|
36
|
-
return getSSHConnectionForAppInstallation(this.apiClient, appInstallationId);
|
|
38
|
+
return getSSHConnectionForAppInstallation(this.apiClient, appInstallationId, sshUser);
|
|
37
39
|
});
|
|
38
40
|
await p.runStep("check if rsync is installed", async () => {
|
|
39
41
|
if (!(await hasBinary("rsync"))) {
|
|
@@ -8,6 +8,7 @@ export default class Ssh extends ExtendedBaseCommand<typeof Ssh> {
|
|
|
8
8
|
cd: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
9
|
info: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
10
|
test: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
|
+
"ssh-user": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
12
|
};
|
|
12
13
|
run(): Promise<void>;
|
|
13
14
|
}
|
|
@@ -3,10 +3,12 @@ import { appInstallationArgs } from "../../lib/app/flags.js";
|
|
|
3
3
|
import { Flags } from "@oclif/core";
|
|
4
4
|
import { ExtendedBaseCommand } from "../../ExtendedBaseCommand.js";
|
|
5
5
|
import { getSSHConnectionForAppInstallation } from "../../lib/ssh/appinstall.js";
|
|
6
|
+
import { sshConnectionFlags } from "../../lib/ssh/flags.js";
|
|
6
7
|
export default class Ssh extends ExtendedBaseCommand {
|
|
7
8
|
static description = "Connect to an app via SSH";
|
|
8
9
|
static args = { ...appInstallationArgs };
|
|
9
10
|
static flags = {
|
|
11
|
+
...sshConnectionFlags,
|
|
10
12
|
cd: Flags.boolean({
|
|
11
13
|
summary: "change to installation path after connecting",
|
|
12
14
|
default: true,
|
|
@@ -22,7 +24,7 @@ export default class Ssh extends ExtendedBaseCommand {
|
|
|
22
24
|
async run() {
|
|
23
25
|
const { flags } = await this.parse(Ssh);
|
|
24
26
|
const appInstallationId = await this.withAppInstallationId(Ssh);
|
|
25
|
-
const { host, user, directory } = await getSSHConnectionForAppInstallation(this.apiClient, appInstallationId);
|
|
27
|
+
const { host, user, directory } = await getSSHConnectionForAppInstallation(this.apiClient, appInstallationId, flags["ssh-user"]);
|
|
26
28
|
if (flags.info) {
|
|
27
29
|
this.log("hostname: %o", host);
|
|
28
30
|
this.log("username: %o", user);
|
|
@@ -5,6 +5,8 @@ export declare class Dump extends ExecRenderBaseCommand<typeof Dump, Record<stri
|
|
|
5
5
|
static flags: {
|
|
6
6
|
"temporary-user": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
7
|
output: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
+
gzip: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
|
+
"ssh-user": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
10
|
"mysql-password": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
11
|
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
12
|
};
|
|
@@ -12,11 +12,14 @@ import { assertStatus } from "@mittwald/api-client";
|
|
|
12
12
|
import { randomBytes } from "crypto";
|
|
13
13
|
import { executeViaSSH } from "../../../lib/ssh/exec.js";
|
|
14
14
|
import assertSuccess from "../../../lib/assert_success.js";
|
|
15
|
+
import shellEscape from "shell-escape";
|
|
16
|
+
import { sshConnectionFlags } from "../../../lib/ssh/flags.js";
|
|
15
17
|
export class Dump extends ExecRenderBaseCommand {
|
|
16
18
|
static summary = "Create a dump of a MySQL database";
|
|
17
19
|
static flags = {
|
|
18
20
|
...processFlags,
|
|
19
21
|
...mysqlConnectionFlags,
|
|
22
|
+
...sshConnectionFlags,
|
|
20
23
|
"temporary-user": Flags.boolean({
|
|
21
24
|
summary: "create a temporary user for the dump",
|
|
22
25
|
description: "Create a temporary user for the dump. This user will be deleted after the dump has been created. This is useful if you want to dump a database that is not accessible from the outside.\n\nIf this flag is disabled, you will need to specify the password of the default user; either via the --mysql-password flag or via the MYSQL_PWD environment variable.",
|
|
@@ -30,6 +33,13 @@ export class Dump extends ExecRenderBaseCommand {
|
|
|
30
33
|
description: 'The output file to write the dump to. You can specify "-" or "/dev/stdout" to write the dump directly to STDOUT; in this case, you might want to use the --quiet/-q flag to supress all other output, so that you can pipe the mysqldump for further processing.',
|
|
31
34
|
required: true,
|
|
32
35
|
}),
|
|
36
|
+
gzip: Flags.boolean({
|
|
37
|
+
summary: "compress the dump with gzip",
|
|
38
|
+
aliases: ["gz"],
|
|
39
|
+
description: "Compress the dump with gzip. This is useful for large databases, as it can significantly reduce the size of the dump.",
|
|
40
|
+
default: false,
|
|
41
|
+
required: false,
|
|
42
|
+
}),
|
|
33
43
|
};
|
|
34
44
|
static args = { ...mysqlArgs };
|
|
35
45
|
async exec() {
|
|
@@ -49,7 +59,14 @@ export class Dump extends ExecRenderBaseCommand {
|
|
|
49
59
|
}
|
|
50
60
|
const { project } = connectionDetails;
|
|
51
61
|
const mysqldumpArgs = buildMySqlDumpArgs(connectionDetails);
|
|
52
|
-
|
|
62
|
+
let cmd = { command: "mysqldump", args: mysqldumpArgs };
|
|
63
|
+
if (this.flags.gzip) {
|
|
64
|
+
const escapedArgs = shellEscape(mysqldumpArgs);
|
|
65
|
+
cmd = {
|
|
66
|
+
shell: `set -e -o pipefail > /dev/null ; mysqldump ${escapedArgs} | gzip`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
await p.runStep(_jsxs(Text, { children: ["starting mysqldump via SSH on project ", _jsx(Value, { children: project.shortId })] }), () => executeViaSSH(this.apiClient, this.flags["ssh-user"], { projectId: connectionDetails.project.id }, cmd, this.getOutputStream()));
|
|
53
70
|
await p.complete(_jsx(DumpSuccess, { database: connectionDetails.database, output: this.flags.output }));
|
|
54
71
|
return {};
|
|
55
72
|
}
|
|
@@ -4,6 +4,7 @@ export declare class PortForward extends ExecRenderBaseCommand<typeof PortForwar
|
|
|
4
4
|
static summary: string;
|
|
5
5
|
static flags: {
|
|
6
6
|
port: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
7
|
+
"ssh-user": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
7
8
|
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
9
|
};
|
|
9
10
|
static args: {
|
|
@@ -7,10 +7,12 @@ import { mysqlArgs, withMySQLId } from "../../../lib/database/mysql/flags.js";
|
|
|
7
7
|
import { getConnectionDetails } from "../../../lib/database/mysql/connect.js";
|
|
8
8
|
import { Value } from "../../../rendering/react/components/Value.js";
|
|
9
9
|
import { Flags } from "@oclif/core";
|
|
10
|
+
import { sshConnectionFlags } from "../../../lib/ssh/flags.js";
|
|
10
11
|
export class PortForward extends ExecRenderBaseCommand {
|
|
11
12
|
static summary = "Forward the TCP port of a MySQL database to a local port";
|
|
12
13
|
static flags = {
|
|
13
14
|
...processFlags,
|
|
15
|
+
...sshConnectionFlags,
|
|
14
16
|
port: Flags.integer({
|
|
15
17
|
summary: "The local TCP port to forward to",
|
|
16
18
|
default: 3306,
|
|
@@ -20,7 +22,7 @@ export class PortForward extends ExecRenderBaseCommand {
|
|
|
20
22
|
async exec() {
|
|
21
23
|
const databaseId = await withMySQLId(this.apiClient, this.flags, this.args, this.config);
|
|
22
24
|
const p = makeProcessRenderer(this.flags, "Port-forwarding a MySQL database");
|
|
23
|
-
const { sshUser, sshHost, hostname, database } = await getConnectionDetails(this.apiClient, databaseId, p);
|
|
25
|
+
const { sshUser, sshHost, hostname, database } = await getConnectionDetails(this.apiClient, databaseId, this.flags["ssh-user"], p);
|
|
24
26
|
const { port } = this.flags;
|
|
25
27
|
p.complete(_jsxs(Text, { children: ["Forwarding MySQL database ", _jsx(Value, { children: database }), " to local port", " ", _jsx(Value, { children: port }), ". Use CTRL+C to cancel."] }));
|
|
26
28
|
const sshArgs = [
|
|
@@ -3,6 +3,7 @@ import { MittwaldAPIV2, MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
|
3
3
|
export declare function getConnectionDetailsWithPassword(apiClient: MittwaldAPIV2Client, databaseId: string, p: ProcessRenderer, flags: {
|
|
4
4
|
"mysql-password": string | undefined;
|
|
5
5
|
"temporary-user"?: boolean;
|
|
6
|
+
"ssh-user"?: string;
|
|
6
7
|
}): Promise<{
|
|
7
8
|
password: string;
|
|
8
9
|
hostname: string;
|
|
@@ -12,7 +13,7 @@ export declare function getConnectionDetailsWithPassword(apiClient: MittwaldAPIV
|
|
|
12
13
|
sshUser: string;
|
|
13
14
|
project: MittwaldAPIV2.Components.Schemas.ProjectProject;
|
|
14
15
|
}>;
|
|
15
|
-
export declare function getConnectionDetails(apiClient: MittwaldAPIV2Client, databaseId: string, p: ProcessRenderer): Promise<{
|
|
16
|
+
export declare function getConnectionDetails(apiClient: MittwaldAPIV2Client, databaseId: string, sshUser: string | undefined, p: ProcessRenderer): Promise<{
|
|
16
17
|
hostname: string;
|
|
17
18
|
database: string;
|
|
18
19
|
user: string;
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import { assertStatus } from "@mittwald/api-client-commons";
|
|
2
|
-
import { getProject
|
|
2
|
+
import { getProject } from "../common.js";
|
|
3
|
+
import { getSSHConnectionForProject } from "../../ssh/project.js";
|
|
3
4
|
export async function getConnectionDetailsWithPassword(apiClient, databaseId, p, flags) {
|
|
4
5
|
const password = flags["temporary-user"] ? "" : await getPassword(p, flags);
|
|
6
|
+
const sshUser = flags["ssh-user"];
|
|
5
7
|
return {
|
|
6
|
-
...(await getConnectionDetails(apiClient, databaseId, p)),
|
|
8
|
+
...(await getConnectionDetails(apiClient, databaseId, sshUser, p)),
|
|
7
9
|
password,
|
|
8
10
|
};
|
|
9
11
|
}
|
|
10
|
-
export async function getConnectionDetails(apiClient, databaseId, p) {
|
|
12
|
+
export async function getConnectionDetails(apiClient, databaseId, sshUser, p) {
|
|
11
13
|
const database = await getDatabase(apiClient, p, databaseId);
|
|
12
14
|
const databaseUser = await getDatabaseUser(apiClient, p, databaseId);
|
|
13
15
|
const project = await getProject(apiClient, p, database);
|
|
14
|
-
const
|
|
16
|
+
const sshConnectionData = await getSSHConnectionForProject(apiClient, database.projectId, sshUser);
|
|
15
17
|
return {
|
|
16
18
|
hostname: database.hostname,
|
|
17
19
|
database: database.name,
|
|
18
20
|
user: databaseUser.name,
|
|
19
|
-
sshHost:
|
|
20
|
-
sshUser:
|
|
21
|
+
sshHost: sshConnectionData.host,
|
|
22
|
+
sshUser: sshConnectionData.user,
|
|
21
23
|
project,
|
|
22
24
|
};
|
|
23
25
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
2
2
|
import { SSHConnectionData } from "./types.js";
|
|
3
|
-
export declare function getSSHConnectionForAppInstallation(client: MittwaldAPIV2Client, appInstallationId: string): Promise<SSHConnectionData>;
|
|
3
|
+
export declare function getSSHConnectionForAppInstallation(client: MittwaldAPIV2Client, appInstallationId: string, sshUser: string | undefined): Promise<SSHConnectionData>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assertStatus } from "@mittwald/api-client";
|
|
2
2
|
import path from "path";
|
|
3
|
-
export async function getSSHConnectionForAppInstallation(client, appInstallationId) {
|
|
3
|
+
export async function getSSHConnectionForAppInstallation(client, appInstallationId, sshUser) {
|
|
4
4
|
const appInstallationResponse = await client.app.getAppinstallation({
|
|
5
5
|
appInstallationId,
|
|
6
6
|
});
|
|
@@ -12,10 +12,13 @@ export async function getSSHConnectionForAppInstallation(client, appInstallation
|
|
|
12
12
|
projectId: appInstallationResponse.data.projectId,
|
|
13
13
|
});
|
|
14
14
|
assertStatus(projectResponse, 200);
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
if (sshUser === undefined) {
|
|
16
|
+
const userResponse = await client.user.getOwnAccount();
|
|
17
|
+
assertStatus(userResponse, 200);
|
|
18
|
+
sshUser = userResponse.data.email;
|
|
19
|
+
}
|
|
17
20
|
const host = `ssh.${projectResponse.data.clusterID}.${projectResponse.data.clusterDomain}`;
|
|
18
|
-
const user = `${
|
|
21
|
+
const user = `${sshUser}@${appInstallationResponse.data.shortId}`;
|
|
19
22
|
const directory = path.join(projectResponse.data.directories["Web"], appInstallationResponse.data.installationPath);
|
|
20
23
|
return {
|
|
21
24
|
host,
|
|
@@ -5,4 +5,10 @@ export type RunTarget = {
|
|
|
5
5
|
} | {
|
|
6
6
|
projectId: string;
|
|
7
7
|
};
|
|
8
|
-
export
|
|
8
|
+
export type RunCommand = {
|
|
9
|
+
command: string;
|
|
10
|
+
args: string[];
|
|
11
|
+
} | {
|
|
12
|
+
shell: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function executeViaSSH(client: MittwaldAPIV2Client, sshUser: string | undefined, target: RunTarget, command: RunCommand, output: NodeJS.WritableStream): Promise<void>;
|
package/dist/esm/lib/ssh/exec.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import cp from "child_process";
|
|
2
2
|
import { getSSHConnectionForAppInstallation } from "./appinstall.js";
|
|
3
3
|
import { getSSHConnectionForProject } from "./project.js";
|
|
4
|
-
export async function executeViaSSH(client, target, command,
|
|
5
|
-
const { user, host } = await connectionDataForTarget(client, target);
|
|
6
|
-
const
|
|
4
|
+
export async function executeViaSSH(client, sshUser, target, command, output) {
|
|
5
|
+
const { user, host } = await connectionDataForTarget(client, target, sshUser);
|
|
6
|
+
const sshCommandArgs = "shell" in command
|
|
7
|
+
? ["bash", "-c", command.shell]
|
|
8
|
+
: [command.command, ...command.args];
|
|
9
|
+
const sshArgs = ["-l", user, "-T", host, ...sshCommandArgs];
|
|
7
10
|
const ssh = cp.spawn("ssh", sshArgs, {
|
|
8
11
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9
12
|
});
|
|
@@ -31,11 +34,11 @@ export async function executeViaSSH(client, target, command, args, output) {
|
|
|
31
34
|
});
|
|
32
35
|
});
|
|
33
36
|
}
|
|
34
|
-
async function connectionDataForTarget(client, target) {
|
|
37
|
+
async function connectionDataForTarget(client, target, sshUser) {
|
|
35
38
|
if ("appInstallationId" in target) {
|
|
36
|
-
return getSSHConnectionForAppInstallation(client, target.appInstallationId);
|
|
39
|
+
return getSSHConnectionForAppInstallation(client, target.appInstallationId, sshUser);
|
|
37
40
|
}
|
|
38
41
|
else {
|
|
39
|
-
return getSSHConnectionForProject(client, target.projectId);
|
|
42
|
+
return getSSHConnectionForProject(client, target.projectId, sshUser);
|
|
40
43
|
}
|
|
41
44
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Flags } from "@oclif/core";
|
|
2
|
+
export const sshConnectionFlags = {
|
|
3
|
+
"ssh-user": Flags.string({
|
|
4
|
+
summary: "override the SSH user to connect with; if omitted, your own user will be used",
|
|
5
|
+
description: "This flag can be used to override the SSH user that is used for a " +
|
|
6
|
+
"connection; be default, your own personal user will be used for this." +
|
|
7
|
+
"\n\n" +
|
|
8
|
+
"You can also set this value by setting the MITTWALD_SSH_USER environment variable.",
|
|
9
|
+
required: false,
|
|
10
|
+
default: undefined,
|
|
11
|
+
env: "MITTWALD_SSH_USER",
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
2
2
|
import { SSHConnectionData } from "./types.js";
|
|
3
|
-
export declare function getSSHConnectionForProject(client: MittwaldAPIV2Client, projectId: string): Promise<SSHConnectionData>;
|
|
3
|
+
export declare function getSSHConnectionForProject(client: MittwaldAPIV2Client, projectId: string, sshUser: string | undefined): Promise<SSHConnectionData>;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { assertStatus } from "@mittwald/api-client";
|
|
2
|
-
export async function getSSHConnectionForProject(client, projectId) {
|
|
2
|
+
export async function getSSHConnectionForProject(client, projectId, sshUser) {
|
|
3
3
|
const projectResponse = await client.project.getProject({ projectId });
|
|
4
4
|
assertStatus(projectResponse, 200);
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
if (sshUser === undefined) {
|
|
6
|
+
const userResponse = await client.user.getOwnAccount();
|
|
7
|
+
assertStatus(userResponse, 200);
|
|
8
|
+
sshUser = userResponse.data.email;
|
|
9
|
+
}
|
|
7
10
|
const host = `ssh.${projectResponse.data.clusterID}.${projectResponse.data.clusterDomain}`;
|
|
8
|
-
const user = `${
|
|
11
|
+
const user = `${sshUser}@${projectResponse.data.shortId}`;
|
|
9
12
|
const directory = projectResponse.data.directories["Web"];
|
|
10
13
|
return {
|
|
11
14
|
host,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mittwald/cli",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.36",
|
|
4
4
|
"description": "Hand-crafted CLI for the mittwald API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"pretty-bytes": "^6.1.0",
|
|
72
72
|
"react": "^18.2.0",
|
|
73
73
|
"semver": "^7.5.4",
|
|
74
|
+
"shell-escape": "^0.2.0",
|
|
74
75
|
"tempfile": "^5.0.0"
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
@@ -84,6 +85,7 @@
|
|
|
84
85
|
"@types/pretty-bytes": "^5.2.0",
|
|
85
86
|
"@types/react": "^18",
|
|
86
87
|
"@types/semver": "^7.5.0",
|
|
88
|
+
"@types/shell-escape": "^0.2.3",
|
|
87
89
|
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
|
88
90
|
"@typescript-eslint/parser": "^6.10.0",
|
|
89
91
|
"@yarnpkg/pnpify": "^4.0.0-rc.48",
|