@mittwald/cli 1.0.0-alpha.34 → 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 +105 -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/commands/sftp-user/delete.d.ts +13 -0
- package/dist/esm/commands/sftp-user/delete.js +21 -0
- package/dist/esm/commands/ssh-user/delete.d.ts +13 -0
- package/dist/esm/commands/ssh-user/delete.js +21 -0
- 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
|
|
|
@@ -237,7 +237,9 @@ USAGE
|
|
|
237
237
|
* [`mw project update [PROJECT-ID]`](#mw-project-update-project-id)
|
|
238
238
|
* [`mw server get [SERVER-ID]`](#mw-server-get-server-id)
|
|
239
239
|
* [`mw server list`](#mw-server-list)
|
|
240
|
+
* [`mw sftp-user delete SFTP-USER-ID`](#mw-sftp-user-delete-sftp-user-id)
|
|
240
241
|
* [`mw sftp-user list`](#mw-sftp-user-list)
|
|
242
|
+
* [`mw ssh-user delete SSH-USER-ID`](#mw-ssh-user-delete-ssh-user-id)
|
|
241
243
|
* [`mw ssh-user list`](#mw-ssh-user-list)
|
|
242
244
|
* [`mw update [CHANNEL]`](#mw-update-channel)
|
|
243
245
|
* [`mw user api-token create`](#mw-user-api-token-create)
|
|
@@ -549,17 +551,18 @@ Download the filesystem of an app within a project to your local machine
|
|
|
549
551
|
|
|
550
552
|
```
|
|
551
553
|
USAGE
|
|
552
|
-
$ 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]
|
|
553
555
|
|
|
554
556
|
ARGUMENTS
|
|
555
557
|
INSTALLATION-ID ID or short ID of an app installation; this argument is optional if a default app installation is set
|
|
556
558
|
in the context
|
|
557
559
|
|
|
558
560
|
FLAGS
|
|
559
|
-
-q, --quiet
|
|
560
|
-
--delete
|
|
561
|
-
--dry-run
|
|
562
|
-
--
|
|
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
|
|
563
566
|
|
|
564
567
|
DESCRIPTION
|
|
565
568
|
Download the filesystem of an app within a project to your local machine
|
|
@@ -569,6 +572,13 @@ FLAG DESCRIPTIONS
|
|
|
569
572
|
|
|
570
573
|
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
571
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.
|
|
572
582
|
```
|
|
573
583
|
|
|
574
584
|
## `mw app get [INSTALLATION-ID]`
|
|
@@ -1477,19 +1487,28 @@ Connect to an app via SSH
|
|
|
1477
1487
|
|
|
1478
1488
|
```
|
|
1479
1489
|
USAGE
|
|
1480
|
-
$ mw app ssh [INSTALLATION-ID] [--cd] [--info] [--test]
|
|
1490
|
+
$ mw app ssh [INSTALLATION-ID] [--ssh-user <value>] [--cd] [--info] [--test]
|
|
1481
1491
|
|
|
1482
1492
|
ARGUMENTS
|
|
1483
1493
|
INSTALLATION-ID ID or short ID of an app installation; this argument is optional if a default app installation is set
|
|
1484
1494
|
in the context
|
|
1485
1495
|
|
|
1486
1496
|
FLAGS
|
|
1487
|
-
--[no-]cd
|
|
1488
|
-
--info
|
|
1489
|
-
--
|
|
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
|
|
1490
1501
|
|
|
1491
1502
|
DESCRIPTION
|
|
1492
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.
|
|
1493
1512
|
```
|
|
1494
1513
|
|
|
1495
1514
|
## `mw app uninstall [INSTALLATION-ID]`
|
|
@@ -2267,7 +2286,7 @@ Create a dump of a MySQL database
|
|
|
2267
2286
|
|
|
2268
2287
|
```
|
|
2269
2288
|
USAGE
|
|
2270
|
-
$ 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]
|
|
2271
2290
|
|
|
2272
2291
|
ARGUMENTS
|
|
2273
2292
|
DATABASE-ID The ID of the database (when a project context is set, you can also use the name)
|
|
@@ -2276,6 +2295,8 @@ FLAGS
|
|
|
2276
2295
|
-o, --output=<value> (required) the output file to write the dump to ("-" for stdout)
|
|
2277
2296
|
-p, --mysql-password=<value> the password to use for the MySQL user (env: MYSQL_PWD)
|
|
2278
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
|
|
2279
2300
|
--[no-]temporary-user create a temporary user for the dump
|
|
2280
2301
|
|
|
2281
2302
|
FLAG DESCRIPTIONS
|
|
@@ -2298,6 +2319,18 @@ FLAG DESCRIPTIONS
|
|
|
2298
2319
|
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
2299
2320
|
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
2300
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
|
+
|
|
2301
2334
|
--[no-]temporary-user create a temporary user for the dump
|
|
2302
2335
|
|
|
2303
2336
|
Create a temporary user for the dump. This user will be deleted after the dump has been created. This is useful if
|
|
@@ -2374,20 +2407,28 @@ Forward the TCP port of a MySQL database to a local port
|
|
|
2374
2407
|
|
|
2375
2408
|
```
|
|
2376
2409
|
USAGE
|
|
2377
|
-
$ mw database mysql port-forward DATABASE-ID [-q] [--port <value>]
|
|
2410
|
+
$ mw database mysql port-forward DATABASE-ID [-q] [--ssh-user <value>] [--port <value>]
|
|
2378
2411
|
|
|
2379
2412
|
ARGUMENTS
|
|
2380
2413
|
DATABASE-ID The ID of the database (when a project context is set, you can also use the name)
|
|
2381
2414
|
|
|
2382
2415
|
FLAGS
|
|
2383
|
-
-q, --quiet
|
|
2384
|
-
--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
|
|
2385
2419
|
|
|
2386
2420
|
FLAG DESCRIPTIONS
|
|
2387
2421
|
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
2388
2422
|
|
|
2389
2423
|
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
2390
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.
|
|
2391
2432
|
```
|
|
2392
2433
|
|
|
2393
2434
|
## `mw database mysql shell DATABASE-ID`
|
|
@@ -4184,6 +4225,31 @@ DESCRIPTION
|
|
|
4184
4225
|
List servers for an organization or user.
|
|
4185
4226
|
```
|
|
4186
4227
|
|
|
4228
|
+
## `mw sftp-user delete SFTP-USER-ID`
|
|
4229
|
+
|
|
4230
|
+
Delete an SFTP user
|
|
4231
|
+
|
|
4232
|
+
```
|
|
4233
|
+
USAGE
|
|
4234
|
+
$ mw sftp-user delete SFTP-USER-ID [-q] [-f]
|
|
4235
|
+
|
|
4236
|
+
ARGUMENTS
|
|
4237
|
+
SFTP-USER-ID The ID of the SFTP user to delete
|
|
4238
|
+
|
|
4239
|
+
FLAGS
|
|
4240
|
+
-f, --force Do not ask for confirmation
|
|
4241
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
4242
|
+
|
|
4243
|
+
DESCRIPTION
|
|
4244
|
+
Delete an SFTP user
|
|
4245
|
+
|
|
4246
|
+
FLAG DESCRIPTIONS
|
|
4247
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
4248
|
+
|
|
4249
|
+
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
4250
|
+
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
4251
|
+
```
|
|
4252
|
+
|
|
4187
4253
|
## `mw sftp-user list`
|
|
4188
4254
|
|
|
4189
4255
|
List all SFTP users for a project.
|
|
@@ -4217,6 +4283,31 @@ FLAG DESCRIPTIONS
|
|
|
4217
4283
|
to persistently set a default project for all commands that accept this flag.
|
|
4218
4284
|
```
|
|
4219
4285
|
|
|
4286
|
+
## `mw ssh-user delete SSH-USER-ID`
|
|
4287
|
+
|
|
4288
|
+
Delete an SSH user
|
|
4289
|
+
|
|
4290
|
+
```
|
|
4291
|
+
USAGE
|
|
4292
|
+
$ mw ssh-user delete SSH-USER-ID [-q] [-f]
|
|
4293
|
+
|
|
4294
|
+
ARGUMENTS
|
|
4295
|
+
SSH-USER-ID The ID of the SSH user to delete
|
|
4296
|
+
|
|
4297
|
+
FLAGS
|
|
4298
|
+
-f, --force Do not ask for confirmation
|
|
4299
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
4300
|
+
|
|
4301
|
+
DESCRIPTION
|
|
4302
|
+
Delete an SSH user
|
|
4303
|
+
|
|
4304
|
+
FLAG DESCRIPTIONS
|
|
4305
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
4306
|
+
|
|
4307
|
+
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
4308
|
+
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
4309
|
+
```
|
|
4310
|
+
|
|
4220
4311
|
## `mw ssh-user list`
|
|
4221
4312
|
|
|
4222
4313
|
List all SSH users for a project.
|
|
@@ -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 = [
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DeleteBaseCommand } from "../../DeleteBaseCommand.js";
|
|
2
|
+
export default class Delete extends DeleteBaseCommand<typeof Delete> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static resourceName: string;
|
|
5
|
+
static flags: {
|
|
6
|
+
force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
static args: {
|
|
10
|
+
"sftp-user-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
protected deleteResource(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DeleteBaseCommand } from "../../DeleteBaseCommand.js";
|
|
2
|
+
import assertSuccess from "../../lib/assert_success.js";
|
|
3
|
+
import { Args } from "@oclif/core";
|
|
4
|
+
export default class Delete extends DeleteBaseCommand {
|
|
5
|
+
static description = "Delete an SFTP user";
|
|
6
|
+
static resourceName = "SFTP user";
|
|
7
|
+
static flags = { ...DeleteBaseCommand.baseFlags };
|
|
8
|
+
static args = {
|
|
9
|
+
"sftp-user-id": Args.string({
|
|
10
|
+
description: "The ID of the SFTP user to delete",
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
async deleteResource() {
|
|
15
|
+
const sftpUserId = this.args["sftp-user-id"];
|
|
16
|
+
const response = await this.apiClient.sshsftpUser.sftpUserDeleteSftpUser({
|
|
17
|
+
sftpUserId,
|
|
18
|
+
});
|
|
19
|
+
assertSuccess(response);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DeleteBaseCommand } from "../../DeleteBaseCommand.js";
|
|
2
|
+
export default class Delete extends DeleteBaseCommand<typeof Delete> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static resourceName: string;
|
|
5
|
+
static flags: {
|
|
6
|
+
force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
static args: {
|
|
10
|
+
"ssh-user-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
protected deleteResource(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DeleteBaseCommand } from "../../DeleteBaseCommand.js";
|
|
2
|
+
import assertSuccess from "../../lib/assert_success.js";
|
|
3
|
+
import { Args } from "@oclif/core";
|
|
4
|
+
export default class Delete extends DeleteBaseCommand {
|
|
5
|
+
static description = "Delete an SSH user";
|
|
6
|
+
static resourceName = "SSH user";
|
|
7
|
+
static flags = { ...DeleteBaseCommand.baseFlags };
|
|
8
|
+
static args = {
|
|
9
|
+
"ssh-user-id": Args.string({
|
|
10
|
+
description: "The ID of the SSH user to delete",
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
async deleteResource() {
|
|
15
|
+
const sshUserId = this.args["ssh-user-id"];
|
|
16
|
+
const response = await this.apiClient.sshsftpUser.sshUserDeleteSshUser({
|
|
17
|
+
sshUserId,
|
|
18
|
+
});
|
|
19
|
+
assertSuccess(response);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -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",
|