@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@govuk-pay/cli",
3
- "version": "0.0.18",
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
  },
@@ -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
- tunnel = openTunnel(bastionTask, database, environment);
44
+ openTunnel(bastionTask, database, environment);
43
45
  printHowToTunnelText(application, environment, database.EngineVersion);
44
46
  await waitForExit();
45
- await shutdown(environment, tunnel, bastionTask);
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, tunnel, bastionTask);
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, tunnel, bastionTask) {
310
+ async function shutdown(environment, bastionTask) {
309
311
  console.log('Shutting down');
310
- if (tunnel !== undefined && tunnel !== null) {
311
- if (tunnel.exitCode === null && tunnel.pid !== undefined) {
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);