@brunwig/mup-aws-beanstalk 0.8.1

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.
Files changed (57) hide show
  1. package/.babelrc +6 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc.yml +10 -0
  4. package/.github/FUNDING.yml +12 -0
  5. package/changelog.md +56 -0
  6. package/docs/getting-started.md +83 -0
  7. package/docs/index.md +333 -0
  8. package/index.js +1 -0
  9. package/lib/assets/env.sh +30 -0
  10. package/lib/assets/env.yaml +19 -0
  11. package/lib/assets/graceful_shutdown.sh +14 -0
  12. package/lib/assets/graceful_shutdown.yaml +7 -0
  13. package/lib/assets/health-check.js +54 -0
  14. package/lib/assets/health-check.js.map +1 -0
  15. package/lib/assets/nginx-server.conf +59 -0
  16. package/lib/assets/nginx.conf +85 -0
  17. package/lib/assets/nginx.yaml +13 -0
  18. package/lib/assets/node.sh +25 -0
  19. package/lib/assets/node.yaml +8 -0
  20. package/lib/assets/npmrc +1 -0
  21. package/lib/assets/package.json +7 -0
  22. package/lib/assets/packages.yaml +5 -0
  23. package/lib/assets/start.sh +21 -0
  24. package/lib/aws.js +98 -0
  25. package/lib/aws.js.map +1 -0
  26. package/lib/certificates.js +64 -0
  27. package/lib/certificates.js.map +1 -0
  28. package/lib/command-handlers.js +774 -0
  29. package/lib/command-handlers.js.map +1 -0
  30. package/lib/commands.js +145 -0
  31. package/lib/commands.js.map +1 -0
  32. package/lib/download.js +27 -0
  33. package/lib/download.js.map +1 -0
  34. package/lib/eb-config.js +269 -0
  35. package/lib/eb-config.js.map +1 -0
  36. package/lib/env-ready.js +121 -0
  37. package/lib/env-ready.js.map +1 -0
  38. package/lib/env-settings.js +22 -0
  39. package/lib/env-settings.js.map +1 -0
  40. package/lib/index.js +111 -0
  41. package/lib/index.js.map +1 -0
  42. package/lib/policies.js +144 -0
  43. package/lib/policies.js.map +1 -0
  44. package/lib/prepare-bundle.js +245 -0
  45. package/lib/prepare-bundle.js.map +1 -0
  46. package/lib/recheck.js +27 -0
  47. package/lib/recheck.js.map +1 -0
  48. package/lib/upload.js +75 -0
  49. package/lib/upload.js.map +1 -0
  50. package/lib/utils.js +678 -0
  51. package/lib/utils.js.map +1 -0
  52. package/lib/validate.js +67 -0
  53. package/lib/validate.js.map +1 -0
  54. package/lib/versions.js +116 -0
  55. package/lib/versions.js.map +1 -0
  56. package/package.json +65 -0
  57. package/readme.md +18 -0
package/lib/utils.js ADDED
@@ -0,0 +1,678 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.logStep = logStep;
7
+ exports.shouldRebuild = shouldRebuild;
8
+ exports.tmpBuildPath = tmpBuildPath;
9
+ exports.names = names;
10
+ exports.createUniqueName = createUniqueName;
11
+ exports.getLogs = getLogs;
12
+ exports.getNodeVersion = getNodeVersion;
13
+ exports.selectPlatformArn = selectPlatformArn;
14
+ exports.attachPolicies = attachPolicies;
15
+ exports.getAccountId = getAccountId;
16
+ exports.ensureRoleExists = ensureRoleExists;
17
+ exports.ensureInstanceProfileExists = ensureInstanceProfileExists;
18
+ exports.ensureRoleAdded = ensureRoleAdded;
19
+ exports.ensurePoliciesAttached = ensurePoliciesAttached;
20
+ exports.ensureInlinePolicyAttached = ensureInlinePolicyAttached;
21
+ exports.ensureBucketExists = ensureBucketExists;
22
+ exports.findBucketWithPrefix = findBucketWithPrefix;
23
+ exports.ensureBucketPolicyAttached = ensureBucketPolicyAttached;
24
+ exports.ensureCloudWatchRule = ensureCloudWatchRule;
25
+ exports.ensureRuleTargetExists = ensureRuleTargetExists;
26
+ exports.coloredStatusText = coloredStatusText;
27
+ exports.createVersionDescription = createVersionDescription;
28
+ exports.ensureSsmDocument = ensureSsmDocument;
29
+ exports.pickInstance = pickInstance;
30
+ exports.connectToInstance = connectToInstance;
31
+ exports.executeSSHCommand = executeSSHCommand;
32
+
33
+ var _axios = _interopRequireDefault(require("axios"));
34
+
35
+ var _chalk = _interopRequireDefault(require("chalk"));
36
+
37
+ var _fs = _interopRequireDefault(require("fs"));
38
+
39
+ var _lodash = require("lodash");
40
+
41
+ var _os = _interopRequireDefault(require("os"));
42
+
43
+ var _randomSeed = _interopRequireDefault(require("random-seed"));
44
+
45
+ var _uuid = _interopRequireDefault(require("uuid"));
46
+
47
+ var _child_process = require("child_process");
48
+
49
+ var _aws = require("./aws");
50
+
51
+ var _recheck = require("./recheck");
52
+
53
+ var _envReady = require("./env-ready");
54
+
55
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
56
+
57
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
58
+
59
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
60
+
61
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
62
+
63
+ function logStep(message) {
64
+ console.log(_chalk.default.blue(message));
65
+ }
66
+
67
+ function shouldRebuild(bundlePath, useCachedBuild) {
68
+ if (_fs.default.existsSync(bundlePath) && useCachedBuild) {
69
+ return false;
70
+ }
71
+
72
+ return true;
73
+ }
74
+
75
+ function tmpBuildPath(appPath, api) {
76
+ const rand = _randomSeed.default.create(appPath);
77
+
78
+ const uuidNumbers = [];
79
+
80
+ for (let i = 0; i < 16; i++) {
81
+ uuidNumbers.push(rand(255));
82
+ }
83
+
84
+ return api.resolvePath(_os.default.tmpdir(), `mup-meteor-${_uuid.default.v4({
85
+ random: uuidNumbers
86
+ })}`);
87
+ }
88
+
89
+ function names(config) {
90
+ const name = config.app.name.toLowerCase();
91
+ return {
92
+ bucket: `mup-${name}`,
93
+ environment: config.app.envName || `mup-env-${name}`,
94
+ app: `mup-${name}`,
95
+ bundlePrefix: `mup/bundles/${name}/`,
96
+ instanceProfile: 'aws-elasticbeanstalk-ec2-role',
97
+ serviceRole: 'aws-elasticbeanstalk-service-role',
98
+ trailBucketPrefix: 'mup-graceful-shutdown-trail',
99
+ trailName: 'mup-graceful-shutdown-trail',
100
+ deregisterRuleName: 'mup-target-deregister',
101
+ eventTargetRole: `mup-envoke-run-command-${name}`,
102
+ eventTargetPolicyName: 'Invoke_Run_Command',
103
+ eventTargetPassRoleName: 'Pass_Role',
104
+ automationDocument: 'mup-graceful-shutdown'
105
+ };
106
+ }
107
+
108
+ function createUniqueName(prefix = '') {
109
+ const randomNumbers = Math.floor(Math.random() * 10000);
110
+ return `${prefix}-${Date.now()}-${randomNumbers}`;
111
+ }
112
+
113
+ async function retrieveEnvironmentInfo(api, count) {
114
+ const config = api.getConfig();
115
+ const {
116
+ environment
117
+ } = names(config);
118
+ const {
119
+ EnvironmentInfo
120
+ } = await _aws.beanstalk.retrieveEnvironmentInfo({
121
+ EnvironmentName: environment,
122
+ InfoType: 'tail'
123
+ }).promise();
124
+
125
+ if (EnvironmentInfo.length > 0) {
126
+ return EnvironmentInfo;
127
+ } else if (count > 5) {
128
+ throw new Error('No logs');
129
+ }
130
+
131
+ return new Promise((resolve, reject) => {
132
+ setTimeout(() => {
133
+ // The logs aren't always available, so retry until they are
134
+ // Another option is to look for the event that says it is ready
135
+ retrieveEnvironmentInfo(api, count + 1).then(resolve).catch(reject);
136
+ }, (0, _recheck.getRecheckInterval)());
137
+ });
138
+ }
139
+
140
+ async function getLogs(api, logNames) {
141
+ const config = api.getConfig();
142
+ const {
143
+ environment
144
+ } = names(config);
145
+ await (0, _envReady.waitForEnvReady)(config, false);
146
+ logStep('=> Requesting Logs');
147
+ await _aws.beanstalk.requestEnvironmentInfo({
148
+ EnvironmentName: environment,
149
+ InfoType: 'tail'
150
+ }).promise();
151
+ const EnvironmentInfo = await retrieveEnvironmentInfo(api, 0);
152
+ logStep('=> Downloading Logs');
153
+ const logsForServer = EnvironmentInfo.reduce((result, info) => {
154
+ result[info.Ec2InstanceId] = info.Message;
155
+ return result;
156
+ }, {});
157
+ return Promise.all(Object.keys(logsForServer).map(key => new Promise((resolve, reject) => {
158
+ _axios.default.get(logsForServer[key]).then(({
159
+ data
160
+ }) => {
161
+ // The separator changed with Amazon Linux 2
162
+ let parts = data.split('----------------------------------------\n/var/log/');
163
+
164
+ if (parts.length === 1) {
165
+ parts = data.split('-------------------------------------\n/var/log/');
166
+ }
167
+
168
+ data = logNames.map(name => parts.find(part => part.trim().startsWith(name)));
169
+ resolve({
170
+ data,
171
+ instance: key
172
+ });
173
+ }).catch(reject);
174
+ })));
175
+ }
176
+
177
+ function getNodeVersion(api, bundlePath) {
178
+ let star = _fs.default.readFileSync(api.resolvePath(bundlePath, 'bundle/star.json')).toString();
179
+
180
+ const nodeVersionTxt = _fs.default.readFileSync(api.resolvePath(bundlePath, 'bundle/.node_version.txt')).toString();
181
+
182
+ star = JSON.parse(star);
183
+
184
+ if (star.npmVersion) {
185
+ return {
186
+ nodeVersion: star.nodeVersion,
187
+ npmVersion: star.npmVersion
188
+ };
189
+ }
190
+
191
+ const nodeVersion = nodeVersionTxt.substr(1);
192
+
193
+ if (nodeVersion.startsWith('4')) {
194
+ return {
195
+ nodeVersion,
196
+ npmVersion: '4.6.1'
197
+ };
198
+ }
199
+
200
+ return {
201
+ nodeVersion,
202
+ npmVersion: '3.10.5'
203
+ };
204
+ }
205
+
206
+ async function selectPlatformArn() {
207
+ const {
208
+ PlatformBranchSummaryList
209
+ } = await _aws.beanstalk.listPlatformBranches({
210
+ Filters: [{
211
+ Attribute: 'LifecycleState',
212
+ Operator: '=',
213
+ Values: ['supported']
214
+ }, {
215
+ Attribute: 'PlatformName',
216
+ Operator: '=',
217
+ Values: ['Node.js']
218
+ }, {
219
+ Attribute: 'TierType',
220
+ Operator: '=',
221
+ Values: ['WebServer/Standard']
222
+ }]
223
+ }).promise();
224
+
225
+ if (PlatformBranchSummaryList.length === 0) {
226
+ throw new Error('Unable to find supported Node.js platform');
227
+ }
228
+
229
+ const branchName = PlatformBranchSummaryList[0].BranchName;
230
+ const {
231
+ PlatformSummaryList
232
+ } = await _aws.beanstalk.listPlatformVersions({
233
+ Filters: [{
234
+ Type: 'PlatformBranchName',
235
+ Operator: '=',
236
+ Values: [branchName]
237
+ }, {
238
+ Type: 'PlatformStatus',
239
+ Operator: '=',
240
+ Values: ['Ready']
241
+ }]
242
+ }).promise();
243
+ const arn = PlatformSummaryList[0].PlatformArn;
244
+ return arn;
245
+ }
246
+
247
+ async function attachPolicies(config, roleName, policies) {
248
+ const promises = [];
249
+ policies.forEach(policy => {
250
+ const promise = _aws.iam.attachRolePolicy({
251
+ RoleName: roleName,
252
+ PolicyArn: policy
253
+ }).promise();
254
+
255
+ promises.push(promise);
256
+ });
257
+ await Promise.all(promises);
258
+ }
259
+
260
+ function getAccountId() {
261
+ return _aws.sts.getCallerIdentity().promise().then(({
262
+ Account
263
+ }) => Account);
264
+ }
265
+
266
+ async function ensureRoleExists(name, assumeRolePolicyDocument, ensureAssumeRolePolicy) {
267
+ let exists = true;
268
+ let updateAssumeRolePolicy = false;
269
+
270
+ try {
271
+ const {
272
+ Role
273
+ } = await _aws.iam.getRole({
274
+ RoleName: name
275
+ }).promise();
276
+ const currentAssumeRolePolicy = decodeURIComponent(Role.AssumeRolePolicyDocument); // Make the whitespace consistent with the current document
277
+
278
+ assumeRolePolicyDocument = JSON.stringify(JSON.parse(assumeRolePolicyDocument));
279
+
280
+ if (currentAssumeRolePolicy !== assumeRolePolicyDocument && ensureAssumeRolePolicy) {
281
+ updateAssumeRolePolicy = true;
282
+ }
283
+ } catch (e) {
284
+ exists = false;
285
+ }
286
+
287
+ if (!exists) {
288
+ await _aws.iam.createRole({
289
+ RoleName: name,
290
+ AssumeRolePolicyDocument: assumeRolePolicyDocument
291
+ }).promise();
292
+ } else if (updateAssumeRolePolicy) {
293
+ await _aws.iam.updateAssumeRolePolicy({
294
+ RoleName: name,
295
+ PolicyDocument: assumeRolePolicyDocument
296
+ }).promise();
297
+ }
298
+ }
299
+
300
+ async function ensureInstanceProfileExists(config, name) {
301
+ let exists = true;
302
+
303
+ try {
304
+ await _aws.iam.getInstanceProfile({
305
+ InstanceProfileName: name
306
+ }).promise();
307
+ } catch (e) {
308
+ exists = false;
309
+ }
310
+
311
+ if (!exists) {
312
+ await _aws.iam.createInstanceProfile({
313
+ InstanceProfileName: name
314
+ }).promise();
315
+ }
316
+ }
317
+
318
+ async function ensureRoleAdded(config, instanceProfile, role) {
319
+ let added = true;
320
+ const {
321
+ InstanceProfile
322
+ } = await _aws.iam.getInstanceProfile({
323
+ InstanceProfileName: instanceProfile
324
+ }).promise();
325
+
326
+ if (InstanceProfile.Roles.length === 0 || InstanceProfile.Roles[0].RoleName !== role) {
327
+ added = false;
328
+ }
329
+
330
+ if (!added) {
331
+ await _aws.iam.addRoleToInstanceProfile({
332
+ InstanceProfileName: instanceProfile,
333
+ RoleName: role
334
+ }).promise();
335
+ }
336
+ }
337
+
338
+ async function ensurePoliciesAttached(config, role, policies) {
339
+ let {
340
+ AttachedPolicies
341
+ } = await _aws.iam.listAttachedRolePolicies({
342
+ RoleName: role
343
+ }).promise();
344
+ AttachedPolicies = AttachedPolicies.map(policy => policy.PolicyArn);
345
+ const unattachedPolicies = policies.reduce((result, policy) => {
346
+ if (AttachedPolicies.indexOf(policy) === -1) {
347
+ result.push(policy);
348
+ }
349
+
350
+ return result;
351
+ }, []);
352
+
353
+ if (unattachedPolicies.length > 0) {
354
+ await attachPolicies(config, role, unattachedPolicies);
355
+ }
356
+ }
357
+
358
+ async function ensureInlinePolicyAttached(role, policyName, policyDocument) {
359
+ let exists = true;
360
+ let needsUpdating = false;
361
+
362
+ try {
363
+ const result = await _aws.iam.getRolePolicy({
364
+ RoleName: role,
365
+ PolicyName: policyName
366
+ }).promise();
367
+ const currentPolicyDocument = decodeURIComponent(result.PolicyDocument);
368
+
369
+ if (currentPolicyDocument !== policyDocument) {
370
+ needsUpdating = true;
371
+ }
372
+ } catch (e) {
373
+ exists = false;
374
+ }
375
+
376
+ if (!exists || needsUpdating) {
377
+ await _aws.iam.putRolePolicy({
378
+ RoleName: role,
379
+ PolicyName: policyName,
380
+ PolicyDocument: policyDocument
381
+ }).promise();
382
+ }
383
+ }
384
+
385
+ async function ensureBucketExists(buckets, bucketName, region) {
386
+ if (!buckets.find(bucket => bucket.Name === bucketName)) {
387
+ await _aws.s3.createBucket(_objectSpread({
388
+ Bucket: bucketName
389
+ }, region ? {
390
+ CreateBucketConfiguration: {
391
+ LocationConstraint: region
392
+ }
393
+ } : {})).promise();
394
+ return true;
395
+ }
396
+ }
397
+
398
+ function findBucketWithPrefix(buckets, prefix) {
399
+ return buckets.find(bucket => bucket.Name.indexOf(prefix) === 0);
400
+ }
401
+
402
+ async function ensureBucketPolicyAttached(bucketName, policy) {
403
+ let error = false;
404
+ let currentPolicy;
405
+
406
+ try {
407
+ const {
408
+ Policy
409
+ } = await _aws.s3.getBucketPolicy({
410
+ Bucket: bucketName
411
+ }).promise();
412
+ currentPolicy = Policy;
413
+ } catch (e) {
414
+ error = true;
415
+ }
416
+
417
+ if (error || currentPolicy !== policy) {
418
+ const params = {
419
+ Bucket: bucketName,
420
+ Policy: policy
421
+ };
422
+ await _aws.s3.putBucketPolicy(params).promise();
423
+ }
424
+ }
425
+
426
+ async function ensureCloudWatchRule(name, description, eventPattern) {
427
+ let error = false;
428
+
429
+ try {
430
+ await _aws.cloudWatchEvents.describeRule({
431
+ Name: name
432
+ }).promise();
433
+ } catch (e) {
434
+ error = true;
435
+ }
436
+
437
+ if (error) {
438
+ await _aws.cloudWatchEvents.putRule({
439
+ Name: name,
440
+ Description: description,
441
+ EventPattern: eventPattern
442
+ }).promise();
443
+ return true;
444
+ }
445
+
446
+ return false;
447
+ }
448
+
449
+ async function ensureRuleTargetExists(ruleName, target) {
450
+ const {
451
+ Targets
452
+ } = await _aws.cloudWatchEvents.listTargetsByRule({
453
+ Rule: ruleName
454
+ }).promise();
455
+
456
+ if (!Targets.find(_target => (0, _lodash.isEqual)(_target, target))) {
457
+ const params = {
458
+ Rule: ruleName,
459
+ Targets: [target]
460
+ };
461
+ await _aws.cloudWatchEvents.putTargets(params).promise();
462
+ return true;
463
+ }
464
+ }
465
+
466
+ function coloredStatusText(envColor, text) {
467
+ if (envColor === 'Green') {
468
+ return _chalk.default.green(text);
469
+ } else if (envColor === 'Yellow') {
470
+ return _chalk.default.yellow(text);
471
+ } else if (envColor === 'Red') {
472
+ return _chalk.default.red(text);
473
+ }
474
+
475
+ return text;
476
+ }
477
+
478
+ function createVersionDescription(api, appConfig) {
479
+ const appPath = api.resolvePath(api.getBasePath(), appConfig.path);
480
+ let description = '';
481
+
482
+ try {
483
+ description = (0, _child_process.execSync)('git log -1 --pretty=%B', {
484
+ cwd: appPath,
485
+ stdio: 'pipe'
486
+ }).toString();
487
+ } catch (e) {
488
+ description = `Deployed by Mup on ${new Date().toUTCString()}`;
489
+ }
490
+
491
+ return description.split('\n')[0].slice(0, 195);
492
+ }
493
+
494
+ async function ensureSsmDocument(name, content) {
495
+ let exists = true;
496
+ let needsUpdating = false;
497
+
498
+ try {
499
+ const result = await _aws.ssm.getDocument({
500
+ Name: name,
501
+ DocumentVersion: '$DEFAULT'
502
+ }).promise(); // If the document was created or edited on the AWS console, there is extra new
503
+ // line characters and whitespace
504
+
505
+ const currentContent = JSON.stringify(JSON.parse(result.Content.replace(/\r?\n|\r/g, '')));
506
+
507
+ if (currentContent !== content) {
508
+ needsUpdating = true;
509
+ }
510
+ } catch (e) {
511
+ exists = false;
512
+ }
513
+
514
+ if (!exists) {
515
+ await _aws.ssm.createDocument({
516
+ Content: content,
517
+ Name: name,
518
+ DocumentType: 'Automation'
519
+ }).promise();
520
+ return true;
521
+ } else if (needsUpdating) {
522
+ try {
523
+ await _aws.ssm.updateDocument({
524
+ Content: content,
525
+ Name: name,
526
+ DocumentVersion: '$LATEST'
527
+ }).promise();
528
+ } catch (e) {
529
+ // If the latest document version has the correct content
530
+ // then it must not be the default version. Ignore the error
531
+ // so we can fix the default version
532
+ if (e.code !== 'DuplicateDocumentContent') {
533
+ throw e;
534
+ }
535
+ }
536
+
537
+ const result = await _aws.ssm.getDocument({
538
+ Name: name,
539
+ DocumentVersion: '$LATEST'
540
+ }).promise();
541
+ await _aws.ssm.updateDocumentDefaultVersion({
542
+ DocumentVersion: result.DocumentVersion,
543
+ Name: name
544
+ }).promise();
545
+ }
546
+ }
547
+
548
+ async function pickInstance(config, instance) {
549
+ const {
550
+ environment
551
+ } = names(config);
552
+ const {
553
+ EnvironmentResources
554
+ } = await _aws.beanstalk.describeEnvironmentResources({
555
+ EnvironmentName: environment
556
+ }).promise();
557
+ const instanceIds = EnvironmentResources.Instances.map(({
558
+ Id
559
+ }) => Id);
560
+ const description = ['Available instances', ...instanceIds.map(id => ` - ${id}`)].join('\n');
561
+ return {
562
+ selected: instanceIds.includes(instance) ? instance : null,
563
+ description
564
+ };
565
+ }
566
+
567
+ async function connectToInstance(api, instanceId, commandLabel) {
568
+ const {
569
+ sshKey
570
+ } = api.getConfig().app;
571
+
572
+ if (!sshKey) {
573
+ const error = new Error('missing sshKey config');
574
+ error.solution = 'Learn how to configure sshKey at https://github.com/zodern/mup-aws-beanstalk/blob/master/docs/index.md#meteor-shell-and-debug';
575
+ throw error;
576
+ }
577
+
578
+ const {
579
+ Reservations
580
+ } = await _aws.ec2.describeInstances({
581
+ InstanceIds: [instanceId]
582
+ }).promise();
583
+ const instance = Reservations[0].Instances[0];
584
+ const availabilityZone = instance.Placement.AvailabilityZone;
585
+ const securityGroups = instance.SecurityGroups.map(g => g.GroupId);
586
+ let {
587
+ data: ipAddress
588
+ } = await _axios.default.get('https://ipv4.icanhazip.com');
589
+ ipAddress = ipAddress.trim();
590
+
591
+ if (securityGroups.length > 1) {
592
+ console.warn('Instance has more than one security group. Please open a GitHub issue for mup-aws-beanstalk');
593
+ }
594
+
595
+ let ruleIds = [];
596
+
597
+ try {
598
+ const {
599
+ SecurityGroupRules
600
+ } = await _aws.ec2.authorizeSecurityGroupIngress({
601
+ GroupId: securityGroups[0],
602
+ IpPermissions: [{
603
+ FromPort: 22,
604
+ IpProtocol: 'tcp',
605
+ IpRanges: [{
606
+ CidrIp: `${ipAddress}/32`,
607
+ Description: `Temporary SSH access for ${commandLabel}`
608
+ }],
609
+ ToPort: 22
610
+ }]
611
+ }).promise();
612
+ ruleIds = SecurityGroupRules.map(rule => rule.SecurityGroupRuleId);
613
+ } catch (e) {
614
+ if (e.code === 'InvalidPermission.Duplicate') {// This rule already exists
615
+ // TODO: should we find the rule id so we can remove it, or leave it in
616
+ // case the user had manually added this rule?
617
+ } else {
618
+ throw e;
619
+ }
620
+ }
621
+
622
+ await _aws.ec2InstanceConnect.sendSSHPublicKey({
623
+ InstanceId: instanceId,
624
+ AvailabilityZone: availabilityZone,
625
+ InstanceOSUser: 'ec2-user',
626
+ SSHPublicKey: _fs.default.readFileSync(api.resolvePath(sshKey.publicKey), 'utf-8')
627
+ }).promise();
628
+ const sshOptions = {
629
+ host: instance.PublicDnsName,
630
+ port: 22,
631
+ username: 'ec2-user',
632
+ privateKey: _fs.default.readFileSync(api.resolvePath(sshKey.privateKey), 'utf-8')
633
+ };
634
+ return {
635
+ sshOptions,
636
+
637
+ removeSSHAccess() {
638
+ if (ruleIds.length === 0) {
639
+ return;
640
+ }
641
+
642
+ console.log('Removing temporary security group rule for SSH');
643
+ return _aws.ec2.revokeSecurityGroupIngress({
644
+ GroupId: securityGroups[0],
645
+ SecurityGroupRuleIds: ruleIds
646
+ }).promise();
647
+ }
648
+
649
+ };
650
+ }
651
+
652
+ async function executeSSHCommand(conn, command) {
653
+ return new Promise((resolve, reject) => {
654
+ conn.exec(command, (err, outputStream) => {
655
+ if (err) {
656
+ conn.end();
657
+ reject(err);
658
+ return;
659
+ }
660
+
661
+ let output = '';
662
+ outputStream.on('data', data => {
663
+ output += data;
664
+ });
665
+ outputStream.stderr.on('data', data => {
666
+ output += data;
667
+ });
668
+ outputStream.once('close', code => {
669
+ conn.end();
670
+ resolve({
671
+ code,
672
+ output
673
+ });
674
+ });
675
+ });
676
+ });
677
+ }
678
+ //# sourceMappingURL=utils.js.map