@govuk-pay/cli 0.0.18 → 0.0.19
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/package.json +2 -1
- package/src/commands/tunnel.js +35 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@govuk-pay/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"description": "GOV.UK Pay Command Line Interface",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pay": "bin/cli.js",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"@aws-sdk/client-ec2": "^3.641.0",
|
|
15
15
|
"@aws-sdk/client-ecs": "^3.637.0",
|
|
16
16
|
"@aws-sdk/client-rds": "^3.637.0",
|
|
17
|
+
"@aws-sdk/client-ssm": "^3.651.1",
|
|
17
18
|
"openurl": "^1.1.1",
|
|
18
19
|
"ts-standard": "^12.0.2"
|
|
19
20
|
},
|
package/src/commands/tunnel.js
CHANGED
|
@@ -8,11 +8,13 @@ const standardContent_js_1 = require("../core/standardContent.js");
|
|
|
8
8
|
const client_ec2_1 = require("@aws-sdk/client-ec2");
|
|
9
9
|
const client_ecs_1 = require("@aws-sdk/client-ecs");
|
|
10
10
|
const client_rds_1 = require("@aws-sdk/client-rds");
|
|
11
|
+
const client_ssm_1 = require("@aws-sdk/client-ssm");
|
|
11
12
|
const readline_1 = __importDefault(require("readline"));
|
|
12
13
|
const child_process_1 = require("child_process");
|
|
13
14
|
const constants_js_1 = require("../core/constants.js");
|
|
14
15
|
let ec2;
|
|
15
16
|
let ecs;
|
|
17
|
+
let ssm;
|
|
16
18
|
const FORMAT = {
|
|
17
19
|
red: '\x1b[31m',
|
|
18
20
|
green: '\x1b[32m',
|
|
@@ -33,16 +35,16 @@ async function tunnelHandler(options) {
|
|
|
33
35
|
console.log(`Opening a database tunnel to ${environment} ${application}`);
|
|
34
36
|
ec2 = new client_ec2_1.EC2Client();
|
|
35
37
|
ecs = new client_ecs_1.ECSClient();
|
|
38
|
+
ssm = new client_ssm_1.SSMClient();
|
|
36
39
|
let bastionTask = null;
|
|
37
|
-
let tunnel = null;
|
|
38
40
|
try {
|
|
39
41
|
printWarningToUser();
|
|
40
42
|
const database = await getDatabaseDetails(environment, application);
|
|
41
43
|
bastionTask = await startBastion(environment);
|
|
42
|
-
|
|
44
|
+
openTunnel(bastionTask, database, environment);
|
|
43
45
|
printHowToTunnelText(application, environment, database.EngineVersion);
|
|
44
46
|
await waitForExit();
|
|
45
|
-
await shutdown(environment,
|
|
47
|
+
await shutdown(environment, bastionTask);
|
|
46
48
|
}
|
|
47
49
|
catch (error) {
|
|
48
50
|
if (typeof error === 'string') {
|
|
@@ -51,7 +53,7 @@ async function tunnelHandler(options) {
|
|
|
51
53
|
else if (error instanceof Error) {
|
|
52
54
|
printError(error.message);
|
|
53
55
|
}
|
|
54
|
-
await shutdown(environment,
|
|
56
|
+
await shutdown(environment, bastionTask);
|
|
55
57
|
process.exit(2);
|
|
56
58
|
}
|
|
57
59
|
}
|
|
@@ -287,7 +289,7 @@ function openTunnel(task, db, environment) {
|
|
|
287
289
|
console.error(`tunnel command error: ${data}`);
|
|
288
290
|
});
|
|
289
291
|
tunnelProc.on('close', (code, _signal) => {
|
|
290
|
-
if (code !== null) {
|
|
292
|
+
if (code !== null && code !== 0) {
|
|
291
293
|
console.error(`\nTunnel unexpectedly closed with exit code: ${code}`);
|
|
292
294
|
console.group();
|
|
293
295
|
console.error('Type `exit` or `Ctrl-C` to shutdown the bastion task then try again.');
|
|
@@ -305,15 +307,10 @@ function openTunnel(task, db, environment) {
|
|
|
305
307
|
});
|
|
306
308
|
return tunnelProc;
|
|
307
309
|
}
|
|
308
|
-
async function shutdown(environment,
|
|
310
|
+
async function shutdown(environment, bastionTask) {
|
|
309
311
|
console.log('Shutting down');
|
|
310
|
-
if (
|
|
311
|
-
|
|
312
|
-
process.kill(-(tunnel.pid));
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
console.log(`Tunnel already closed, exit code: ${tunnel?.exitCode ?? 'no exit code'}`);
|
|
316
|
-
}
|
|
312
|
+
if (bastionTask != null) {
|
|
313
|
+
await terminateSession(bastionTask, environment);
|
|
317
314
|
}
|
|
318
315
|
if (bastionTask !== null) {
|
|
319
316
|
bastionTask = await refreshTask(bastionTask.taskArn, environment);
|
|
@@ -323,6 +320,31 @@ async function shutdown(environment, tunnel, bastionTask) {
|
|
|
323
320
|
}
|
|
324
321
|
printGreen('Shutdown complete.');
|
|
325
322
|
}
|
|
323
|
+
async function terminateSession(task, environment) {
|
|
324
|
+
const cluster = `${environment}-fargate`;
|
|
325
|
+
const ecsTaskId = task.taskArn?.split('/').at(-1);
|
|
326
|
+
const ecsContainerRunTimeId = task.containers?.map(c => c.runtimeId)[0];
|
|
327
|
+
const target = `ecs:${cluster}_${ecsTaskId}_${ecsContainerRunTimeId}`;
|
|
328
|
+
const describeSessionsCommand = new client_ssm_1.DescribeSessionsCommand({
|
|
329
|
+
State: 'Active',
|
|
330
|
+
Filters: [
|
|
331
|
+
{
|
|
332
|
+
key: 'Target',
|
|
333
|
+
value: target
|
|
334
|
+
}
|
|
335
|
+
]
|
|
336
|
+
});
|
|
337
|
+
const describeSessionsOutput = await ssm.send(describeSessionsCommand);
|
|
338
|
+
const sessions = describeSessionsOutput.Sessions;
|
|
339
|
+
if (sessions != null) {
|
|
340
|
+
for (const session of sessions) {
|
|
341
|
+
const terminateSessionCommand = new client_ssm_1.TerminateSessionCommand({
|
|
342
|
+
SessionId: session.SessionId
|
|
343
|
+
});
|
|
344
|
+
await ssm.send(terminateSessionCommand);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
326
348
|
function printHowToTunnelText(application, environment, dbEngineVersion) {
|
|
327
349
|
const dbUser = getDbUser(application);
|
|
328
350
|
const payLowPassDbSecretName = getPayLowPassDbSecretname(environment, dbUser);
|