@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
@@ -0,0 +1,774 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.setup = setup;
7
+ exports.deploy = deploy;
8
+ exports.logs = logs;
9
+ exports.logsNginx = logsNginx;
10
+ exports.logsEb = logsEb;
11
+ exports.start = start;
12
+ exports.stop = stop;
13
+ exports.restart = restart;
14
+ exports.clean = clean;
15
+ exports.reconfig = reconfig;
16
+ exports.events = events;
17
+ exports.status = status;
18
+ exports.ssl = ssl;
19
+ exports.shell = shell;
20
+ exports.debug = debug;
21
+
22
+ var _chalk = _interopRequireDefault(require("chalk"));
23
+
24
+ var _ssh = require("ssh2");
25
+
26
+ var _aws = require("./aws");
27
+
28
+ var _certificates = _interopRequireDefault(require("./certificates"));
29
+
30
+ var _policies = require("./policies");
31
+
32
+ var _upload = _interopRequireWildcard(require("./upload"));
33
+
34
+ var _prepareBundle = require("./prepare-bundle");
35
+
36
+ var _utils = require("./utils");
37
+
38
+ var _versions = require("./versions");
39
+
40
+ var _envSettings = require("./env-settings");
41
+
42
+ var _ebConfig = require("./eb-config");
43
+
44
+ var _envReady = require("./env-ready");
45
+
46
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
47
+
48
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
49
+
50
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
51
+
52
+ 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; }
53
+
54
+ 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; }
55
+
56
+ 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; }
57
+
58
+ async function setup(api) {
59
+ const config = api.getConfig();
60
+ const appConfig = config.app;
61
+ const {
62
+ bucket: bucketName,
63
+ app: appName,
64
+ instanceProfile,
65
+ serviceRole: serviceRoleName,
66
+ trailBucketPrefix,
67
+ trailName,
68
+ deregisterRuleName,
69
+ environment: environmentName,
70
+ eventTargetRole: eventTargetRoleName,
71
+ eventTargetPolicyName,
72
+ eventTargetPassRoleName,
73
+ automationDocument
74
+ } = (0, _utils.names)(config);
75
+ (0, _utils.logStep)('=> Setting up'); // Create bucket if needed
76
+
77
+ const {
78
+ Buckets
79
+ } = await _aws.s3.listBuckets().promise();
80
+ const beanstalkBucketCreated = await (0, _utils.ensureBucketExists)(Buckets, bucketName, appConfig.region);
81
+
82
+ if (beanstalkBucketCreated) {
83
+ console.log(' Created Bucket');
84
+ }
85
+
86
+ (0, _utils.logStep)('=> Ensuring IAM Roles and Instance Profiles are setup'); // Create role and instance profile
87
+
88
+ await (0, _utils.ensureRoleExists)(instanceProfile, _policies.rolePolicy);
89
+ await (0, _utils.ensureInstanceProfileExists)(config, instanceProfile);
90
+ await (0, _utils.ensurePoliciesAttached)(config, instanceProfile, ['arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier', 'arn:aws:iam::aws:policy/AWSElasticBeanstalkMulticontainerDocker', 'arn:aws:iam::aws:policy/AWSElasticBeanstalkWorkerTier', ...(appConfig.gracefulShutdown ? ['arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM'] : [])]);
91
+ await (0, _utils.ensureRoleAdded)(config, instanceProfile, instanceProfile); // Create role used by enhanced health
92
+
93
+ await (0, _utils.ensureRoleExists)(serviceRoleName, _policies.serviceRole);
94
+ await (0, _utils.ensurePoliciesAttached)(config, serviceRoleName, ['arn:aws:iam::aws:policy/service-role/AWSElasticBeanstalkEnhancedHealth', 'arn:aws:iam::aws:policy/service-role/AWSElasticBeanstalkService']);
95
+
96
+ if (appConfig.gracefulShutdown) {
97
+ const accountId = await (0, _utils.getAccountId)();
98
+ const policy = (0, _policies.eventTargetRolePolicy)(accountId, environmentName, appConfig.region || 'us-east-1');
99
+ const passPolicy = (0, _policies.passRolePolicy)(accountId, eventTargetRoleName);
100
+ await (0, _utils.ensureRoleExists)(eventTargetRoleName, _policies.eventTargetRole, true);
101
+ await (0, _utils.ensureInlinePolicyAttached)(eventTargetRoleName, eventTargetPolicyName, policy);
102
+ await (0, _utils.ensureInlinePolicyAttached)(eventTargetRoleName, eventTargetPassRoleName, passPolicy);
103
+ } // Create beanstalk application if needed
104
+
105
+
106
+ const {
107
+ Applications
108
+ } = await _aws.beanstalk.describeApplications().promise();
109
+
110
+ if (!Applications.find(app => app.ApplicationName === appName)) {
111
+ const params = {
112
+ ApplicationName: appName,
113
+ Description: `App "${appConfig.name}" managed by Meteor Up`
114
+ };
115
+ await _aws.beanstalk.createApplication(params).promise();
116
+ console.log(' Created Beanstalk application');
117
+ }
118
+
119
+ if (appConfig.gracefulShutdown) {
120
+ (0, _utils.logStep)('=> Ensuring Graceful Shutdown is setup');
121
+ const existingBucket = (0, _utils.findBucketWithPrefix)(Buckets, trailBucketPrefix);
122
+ const trailBucketName = existingBucket ? existingBucket.Name : (0, _utils.createUniqueName)(trailBucketPrefix);
123
+ const region = appConfig.region || 'us-east-1';
124
+ const accountId = await (0, _utils.getAccountId)();
125
+ const policy = (0, _policies.trailBucketPolicy)(accountId, trailBucketName);
126
+ const trailBucketCreated = await (0, _utils.ensureBucketExists)(Buckets, trailBucketName, appConfig.region);
127
+ await (0, _utils.ensureBucketPolicyAttached)(trailBucketName, policy);
128
+
129
+ if (trailBucketCreated) {
130
+ console.log(' Created bucket for Cloud Trail');
131
+ }
132
+
133
+ const params = {
134
+ trailNameList: [trailName]
135
+ };
136
+ const {
137
+ trailList
138
+ } = await _aws.cloudTrail.describeTrails(params).promise();
139
+
140
+ if (trailList.length === 0) {
141
+ const createParams = {
142
+ Name: trailName,
143
+ S3BucketName: trailBucketName
144
+ };
145
+ await _aws.cloudTrail.createTrail(createParams).promise();
146
+ console.log(' Created CloudTrail trail');
147
+ }
148
+
149
+ const createdDocument = await (0, _utils.ensureSsmDocument)(automationDocument, (0, _policies.gracefulShutdownAutomationDocument)());
150
+
151
+ if (createdDocument) {
152
+ console.log(' Created SSM Automation Document');
153
+ }
154
+
155
+ const createdRule = await (0, _utils.ensureCloudWatchRule)(deregisterRuleName, 'Used by Meteor Up for graceful shutdown', _policies.DeregisterEvent);
156
+
157
+ if (createdRule) {
158
+ console.log(' Created Cloud Watch rule');
159
+ }
160
+
161
+ const target = (0, _policies.deregisterEventTarget)(environmentName, eventTargetRoleName, accountId, region);
162
+ const createdTarget = await (0, _utils.ensureRuleTargetExists)(deregisterRuleName, target, accountId);
163
+
164
+ if (createdTarget) {
165
+ console.log(' Created target for Cloud Watch rule');
166
+ }
167
+ }
168
+ }
169
+
170
+ async function deploy(api) {
171
+ await api.runCommand('beanstalk.setup');
172
+ const config = api.getConfig();
173
+ const {
174
+ app,
175
+ bucket,
176
+ bundlePrefix,
177
+ environment
178
+ } = (0, _utils.names)(config);
179
+ const version = await (0, _versions.largestVersion)(api);
180
+ const nextVersion = version + 1; // Mutates the config, so the meteor.build command will have the correct build location
181
+
182
+ config.app.buildOptions.buildLocation = config.app.buildOptions.buildLocation || (0, _utils.tmpBuildPath)(config.app.path, api);
183
+ const bundlePath = api.resolvePath(config.app.buildOptions.buildLocation, 'bundle.zip');
184
+ const willBuild = (0, _utils.shouldRebuild)(bundlePath, api.getOptions()['cached-build']);
185
+
186
+ if (willBuild) {
187
+ await api.runCommand('meteor.build');
188
+ (0, _prepareBundle.injectFiles)(api, app, nextVersion, config.app);
189
+ await (0, _prepareBundle.archiveApp)(config.app.buildOptions.buildLocation, api);
190
+ }
191
+
192
+ (0, _utils.logStep)('=> Uploading bundle');
193
+ const key = `${bundlePrefix}${nextVersion}`;
194
+ await (0, _upload.default)(config.app, bucket, `${bundlePrefix}${nextVersion}`, bundlePath);
195
+ (0, _utils.logStep)('=> Creating version');
196
+ await _aws.beanstalk.createApplicationVersion({
197
+ ApplicationName: app,
198
+ VersionLabel: nextVersion.toString(),
199
+ Description: (0, _utils.createVersionDescription)(api, config.app),
200
+ SourceBundle: {
201
+ S3Bucket: bucket,
202
+ S3Key: key
203
+ }
204
+ }).promise();
205
+ await api.runCommand('beanstalk.reconfig');
206
+ await (0, _envReady.waitForEnvReady)(config, true);
207
+ (0, _utils.logStep)('=> Deploying new version');
208
+ const {
209
+ toRemove,
210
+ toUpdate
211
+ } = await (0, _ebConfig.prepareUpdateEnvironment)(api);
212
+
213
+ if (api.verbose) {
214
+ console.log('EB Config changes:');
215
+ console.dir({
216
+ toRemove,
217
+ toUpdate
218
+ });
219
+ }
220
+
221
+ await _aws.beanstalk.updateEnvironment({
222
+ EnvironmentName: environment,
223
+ VersionLabel: nextVersion.toString(),
224
+ OptionSettings: toUpdate,
225
+ OptionsToRemove: toRemove
226
+ }).promise();
227
+ await (0, _envReady.waitForEnvReady)(config, true);
228
+ const {
229
+ Environments
230
+ } = await _aws.beanstalk.describeEnvironments({
231
+ ApplicationName: app,
232
+ EnvironmentNames: [environment]
233
+ }).promise();
234
+ await api.runCommand('beanstalk.clean');
235
+ await api.runCommand('beanstalk.ssl'); // Check if deploy succeeded
236
+
237
+ const {
238
+ Environments: finalEnvironments
239
+ } = await _aws.beanstalk.describeEnvironments({
240
+ ApplicationName: app,
241
+ EnvironmentNames: [environment]
242
+ }).promise();
243
+
244
+ if (nextVersion.toString() === finalEnvironments[0].VersionLabel) {
245
+ console.log(_chalk.default.green(`App is running at ${Environments[0].CNAME}`));
246
+ } else {
247
+ console.log(_chalk.default.red`Deploy Failed. Visit the Aws Elastic Beanstalk console to view the logs from the failed deploy.`);
248
+ process.exitCode = 1;
249
+ }
250
+ }
251
+
252
+ async function logs(api) {
253
+ const logsContent = await (0, _utils.getLogs)(api, ['web.stdout.log', 'nodejs/nodejs.log']);
254
+ logsContent.forEach(({
255
+ instance,
256
+ data
257
+ }) => {
258
+ console.log(`${instance} `, data[0] || data[1]);
259
+ });
260
+ }
261
+
262
+ async function logsNginx(api) {
263
+ const logsContent = await (0, _utils.getLogs)(api, ['nginx/error.log', 'nginx/access.log']);
264
+ logsContent.forEach(({
265
+ instance,
266
+ data
267
+ }) => {
268
+ console.log(`${instance} `, data[0]);
269
+ console.log(`${instance} `, data[1]);
270
+ });
271
+ }
272
+
273
+ async function logsEb(api) {
274
+ const logsContent = await (0, _utils.getLogs)(api, ['eb-engine.log', 'eb-activity.log']);
275
+ logsContent.forEach(({
276
+ data,
277
+ instance
278
+ }) => {
279
+ console.log(`${instance} `, data[0] || data[1]);
280
+ });
281
+ }
282
+
283
+ async function start(api) {
284
+ const config = api.getConfig();
285
+ const {
286
+ environment
287
+ } = (0, _utils.names)(config);
288
+ (0, _utils.logStep)('=> Starting App');
289
+ const {
290
+ EnvironmentResources
291
+ } = await _aws.beanstalk.describeEnvironmentResources({
292
+ EnvironmentName: environment
293
+ }).promise();
294
+ const autoScalingGroup = EnvironmentResources.AutoScalingGroups[0].Name;
295
+ const {
296
+ minInstances,
297
+ maxInstances
298
+ } = config.app;
299
+ await _aws.autoScaling.updateAutoScalingGroup({
300
+ AutoScalingGroupName: autoScalingGroup,
301
+ MaxSize: maxInstances,
302
+ MinSize: minInstances,
303
+ DesiredCapacity: minInstances
304
+ }).promise();
305
+ await (0, _envReady.waitForHealth)(config);
306
+ }
307
+
308
+ async function stop(api) {
309
+ const config = api.getConfig();
310
+ const {
311
+ environment
312
+ } = (0, _utils.names)(config);
313
+ (0, _utils.logStep)('=> Stopping App');
314
+ const {
315
+ EnvironmentResources
316
+ } = await _aws.beanstalk.describeEnvironmentResources({
317
+ EnvironmentName: environment
318
+ }).promise();
319
+ const autoScalingGroup = EnvironmentResources.AutoScalingGroups[0].Name;
320
+ await _aws.autoScaling.updateAutoScalingGroup({
321
+ AutoScalingGroupName: autoScalingGroup,
322
+ MaxSize: 0,
323
+ MinSize: 0,
324
+ DesiredCapacity: 0
325
+ }).promise();
326
+ await (0, _envReady.waitForHealth)(config, 'Grey');
327
+ }
328
+
329
+ async function restart(api) {
330
+ const config = api.getConfig();
331
+ const {
332
+ environment
333
+ } = (0, _utils.names)(config);
334
+ (0, _utils.logStep)('=> Restarting App');
335
+ await _aws.beanstalk.restartAppServer({
336
+ EnvironmentName: environment
337
+ }).promise();
338
+ await (0, _envReady.waitForEnvReady)(config, false);
339
+ }
340
+
341
+ async function clean(api) {
342
+ const config = api.getConfig();
343
+ const {
344
+ app,
345
+ bucket
346
+ } = (0, _utils.names)(config);
347
+ (0, _utils.logStep)('=> Finding old versions');
348
+ const {
349
+ versions
350
+ } = await (0, _versions.oldVersions)(api);
351
+ const envVersions = await (0, _versions.oldEnvVersions)(api);
352
+ (0, _utils.logStep)('=> Removing old versions');
353
+ const promises = [];
354
+
355
+ for (let i = 0; i < versions.length; i++) {
356
+ promises.push(_aws.beanstalk.deleteApplicationVersion({
357
+ ApplicationName: app,
358
+ VersionLabel: versions[i].toString(),
359
+ DeleteSourceBundle: true
360
+ }).promise());
361
+ }
362
+
363
+ for (let i = 0; i < envVersions.length; i++) {
364
+ promises.push(_aws.s3.deleteObject({
365
+ Bucket: bucket,
366
+ Key: `env/${envVersions[i]}.txt`
367
+ }).promise());
368
+ } // TODO: remove bundles
369
+
370
+
371
+ await Promise.all(promises);
372
+ }
373
+
374
+ async function reconfig(api) {
375
+ const config = api.getConfig();
376
+ const {
377
+ app,
378
+ environment,
379
+ bucket
380
+ } = (0, _utils.names)(config);
381
+ const deploying = !!api.commandHistory.find(entry => entry.name === 'beanstalk.deploy');
382
+ (0, _utils.logStep)('=> Configuring Beanstalk environment'); // check if env exists
383
+
384
+ const {
385
+ Environments
386
+ } = await _aws.beanstalk.describeEnvironments({
387
+ ApplicationName: app,
388
+ EnvironmentNames: [environment]
389
+ }).promise();
390
+
391
+ if (!Environments.find(env => env.Status !== 'Terminated')) {
392
+ const desiredEbConfig = (0, _ebConfig.createDesiredConfig)(api.getConfig(), api.getSettings(), config.app.longEnvVars ? 1 : false);
393
+
394
+ if (config.app.longEnvVars) {
395
+ const envContent = (0, _envSettings.createEnvFile)(config.app.env, api.getSettings());
396
+ await (0, _upload.uploadEnvFile)(bucket, 1, envContent);
397
+ }
398
+
399
+ const platformArn = await (0, _utils.selectPlatformArn)();
400
+ const [version] = await (0, _versions.ebVersions)(api);
401
+ await _aws.beanstalk.createEnvironment({
402
+ ApplicationName: app,
403
+ EnvironmentName: environment,
404
+ Description: `Environment for ${config.app.name}, managed by Meteor Up`,
405
+ VersionLabel: version.toString(),
406
+ PlatformArn: platformArn,
407
+ OptionSettings: desiredEbConfig.OptionSettings
408
+ }).promise();
409
+ console.log(' Created Environment');
410
+ await (0, _envReady.waitForEnvReady)(config, false);
411
+ } else if (!deploying) {
412
+ // If we are deploying, the environment will be updated
413
+ // at the same time we update the environment version
414
+ const {
415
+ toRemove,
416
+ toUpdate
417
+ } = await (0, _ebConfig.prepareUpdateEnvironment)(api);
418
+
419
+ if (api.verbose) {
420
+ console.log('EB Config changes:');
421
+ console.dir({
422
+ toRemove,
423
+ toUpdate
424
+ });
425
+ }
426
+
427
+ if (toRemove.length > 0 || toUpdate.length > 0) {
428
+ await (0, _envReady.waitForEnvReady)(config, true);
429
+ await _aws.beanstalk.updateEnvironment({
430
+ EnvironmentName: environment,
431
+ OptionSettings: toUpdate,
432
+ OptionsToRemove: toRemove
433
+ }).promise();
434
+ console.log(' Updated Environment');
435
+ await (0, _envReady.waitForEnvReady)(config, true);
436
+ }
437
+ }
438
+
439
+ const {
440
+ ConfigurationSettings
441
+ } = await _aws.beanstalk.describeConfigurationSettings({
442
+ EnvironmentName: environment,
443
+ ApplicationName: app
444
+ }).promise();
445
+
446
+ if ((0, _ebConfig.scalingConfigChanged)(ConfigurationSettings[0].OptionSettings, config)) {
447
+ (0, _utils.logStep)('=> Configuring scaling');
448
+ await _aws.beanstalk.updateEnvironment({
449
+ EnvironmentName: environment,
450
+ OptionSettings: (0, _ebConfig.scalingConfig)(config.app).OptionSettings
451
+ }).promise();
452
+ await (0, _envReady.waitForEnvReady)(config, true);
453
+ }
454
+ }
455
+
456
+ async function events(api) {
457
+ const {
458
+ environment
459
+ } = (0, _utils.names)(api.getConfig());
460
+ const {
461
+ Events: envEvents
462
+ } = await _aws.beanstalk.describeEvents({
463
+ EnvironmentName: environment
464
+ }).promise();
465
+ console.log(envEvents.map(ev => `${ev.EventDate}: ${ev.Message}`).join('\n'));
466
+ }
467
+
468
+ async function status(api) {
469
+ const {
470
+ environment
471
+ } = (0, _utils.names)(api.getConfig());
472
+ let result;
473
+
474
+ try {
475
+ result = await _aws.beanstalk.describeEnvironmentHealth({
476
+ AttributeNames: ['All'],
477
+ EnvironmentName: environment
478
+ }).promise();
479
+ } catch (e) {
480
+ if (e.message.includes('No Environment found for EnvironmentName')) {
481
+ console.log(' AWS Beanstalk environment does not exist');
482
+ return;
483
+ }
484
+
485
+ throw e;
486
+ }
487
+
488
+ const {
489
+ InstanceHealthList
490
+ } = await _aws.beanstalk.describeInstancesHealth({
491
+ AttributeNames: ['All'],
492
+ EnvironmentName: environment
493
+ }).promise();
494
+ const {
495
+ RequestCount,
496
+ Duration,
497
+ StatusCodes,
498
+ Latency
499
+ } = result.ApplicationMetrics;
500
+ console.log(`Environment Status: ${result.Status}`);
501
+ console.log(`Health Status: ${(0, _utils.coloredStatusText)(result.Color, result.HealthStatus)}`);
502
+
503
+ if (result.Causes.length > 0) {
504
+ console.log('Causes: ');
505
+ result.Causes.forEach(cause => console.log(` ${cause}`));
506
+ }
507
+
508
+ console.log('');
509
+ console.log(`=== Metrics For Last ${Duration || 'Unknown'} Minutes ===`);
510
+ console.log(` Requests: ${RequestCount}`);
511
+
512
+ if (StatusCodes) {
513
+ console.log(' Status Codes');
514
+ console.log(` 2xx: ${StatusCodes.Status2xx}`);
515
+ console.log(` 3xx: ${StatusCodes.Status3xx}`);
516
+ console.log(` 4xx: ${StatusCodes.Status4xx}`);
517
+ console.log(` 5xx: ${StatusCodes.Status5xx}`);
518
+ }
519
+
520
+ if (Latency) {
521
+ console.log(' Latency');
522
+ console.log(` 99.9%: ${Latency.P999}`);
523
+ console.log(` 99% : ${Latency.P99}`);
524
+ console.log(` 95% : ${Latency.P95}`);
525
+ console.log(` 90% : ${Latency.P90}`);
526
+ console.log(` 85% : ${Latency.P85}`);
527
+ console.log(` 75% : ${Latency.P75}`);
528
+ console.log(` 50% : ${Latency.P50}`);
529
+ console.log(` 10% : ${Latency.P10}`);
530
+ }
531
+
532
+ console.log('');
533
+ console.log('=== Instances ===');
534
+ InstanceHealthList.forEach(instance => {
535
+ console.log(` ${instance.InstanceId}: ${(0, _utils.coloredStatusText)(instance.Color, instance.HealthStatus)}`);
536
+ });
537
+
538
+ if (InstanceHealthList.length === 0) {
539
+ console.log(' 0 Instances');
540
+ }
541
+ }
542
+
543
+ async function ssl(api) {
544
+ const config = api.getConfig();
545
+ await (0, _envReady.waitForEnvReady)(config, true);
546
+
547
+ if (!config.app || !config.app.sslDomains) {
548
+ (0, _utils.logStep)('=> Updating Beanstalk SSL Config');
549
+ await (0, _certificates.default)(config);
550
+ return;
551
+ }
552
+
553
+ (0, _utils.logStep)('=> Checking Certificate Status');
554
+ const domains = config.app.sslDomains;
555
+ const {
556
+ CertificateSummaryList
557
+ } = await _aws.acm.listCertificates().promise();
558
+ let found = null;
559
+
560
+ for (let i = 0; i < CertificateSummaryList.length; i++) {
561
+ const {
562
+ DomainName,
563
+ CertificateArn
564
+ } = CertificateSummaryList[i];
565
+
566
+ if (DomainName === domains[0]) {
567
+ const {
568
+ Certificate
569
+ } = await _aws.acm.describeCertificate({
570
+ // eslint-disable-line no-await-in-loop
571
+ CertificateArn
572
+ }).promise();
573
+
574
+ if (domains.join(',') === Certificate.SubjectAlternativeNames.join(',')) {
575
+ found = CertificateSummaryList[i];
576
+ }
577
+ }
578
+ }
579
+
580
+ let certificateArn;
581
+
582
+ if (!found) {
583
+ (0, _utils.logStep)('=> Requesting Certificate');
584
+ const result = await _aws.acm.requestCertificate({
585
+ DomainName: domains.shift(),
586
+ SubjectAlternativeNames: domains.length > 0 ? domains : null
587
+ }).promise();
588
+ certificateArn = result.CertificateArn;
589
+ }
590
+
591
+ if (found) {
592
+ certificateArn = found.CertificateArn;
593
+ }
594
+
595
+ let emailsProvided = false;
596
+ let checks = 0;
597
+ let certificate;
598
+ /* eslint-disable no-await-in-loop */
599
+
600
+ while (!emailsProvided && checks < 5) {
601
+ const {
602
+ Certificate
603
+ } = await _aws.acm.describeCertificate({
604
+ CertificateArn: certificateArn
605
+ }).promise();
606
+ const validationOptions = Certificate.DomainValidationOptions[0];
607
+
608
+ if (typeof validationOptions.ValidationEmails === 'undefined') {
609
+ emailsProvided = true;
610
+ certificate = Certificate;
611
+ } else if (validationOptions.ValidationEmails.length > 0 || checks === 6) {
612
+ emailsProvided = true;
613
+ certificate = Certificate;
614
+ } else {
615
+ checks += 1;
616
+ await new Promise(resolve => {
617
+ setTimeout(resolve, 1000 * 10);
618
+ });
619
+ }
620
+ }
621
+
622
+ if (certificate.Status === 'PENDING_VALIDATION') {
623
+ console.log('Certificate is pending validation.');
624
+ certificate.DomainValidationOptions.forEach(({
625
+ DomainName,
626
+ ValidationEmails,
627
+ ValidationDomain,
628
+ ValidationStatus
629
+ }) => {
630
+ if (ValidationStatus === 'SUCCESS') {
631
+ console.log(_chalk.default.green(`${ValidationDomain || DomainName} has been verified`));
632
+ return;
633
+ }
634
+
635
+ console.log(_chalk.default.yellow(`${ValidationDomain || DomainName} is pending validation`));
636
+
637
+ if (ValidationEmails) {
638
+ console.log('Emails with instructions have been sent to:');
639
+ ValidationEmails.forEach(email => {
640
+ console.log(` ${email}`);
641
+ });
642
+ }
643
+
644
+ console.log('Run "mup beanstalk ssl" after you have verified the domains, or to check the verification status');
645
+ });
646
+ } else if (certificate.Status === 'ISSUED') {
647
+ console.log(_chalk.default.green('Certificate has been issued'));
648
+ (0, _utils.logStep)('=> Updating Beanstalk SSL config');
649
+ await (0, _certificates.default)(config, certificateArn);
650
+ }
651
+ }
652
+
653
+ async function shell(api) {
654
+ const {
655
+ selected,
656
+ description
657
+ } = await (0, _utils.pickInstance)(api.getConfig(), api.getArgs()[2]);
658
+
659
+ if (!selected) {
660
+ console.log(description);
661
+ console.log('Run "mup beanstalk shell <instance id>"');
662
+ process.exitCode = 1;
663
+ return;
664
+ }
665
+
666
+ const {
667
+ sshOptions,
668
+ removeSSHAccess
669
+ } = await (0, _utils.connectToInstance)(api, selected, 'mup beanstalk shell');
670
+ const conn = new _ssh.Client();
671
+ conn.on('ready', () => {
672
+ conn.exec('sudo node /home/webapp/meteor-shell.js', {
673
+ pty: true
674
+ }, (err, stream) => {
675
+ if (err) {
676
+ throw err;
677
+ }
678
+
679
+ stream.on('close', async () => {
680
+ conn.end();
681
+ await removeSSHAccess();
682
+ process.exit();
683
+ });
684
+ process.stdin.setRawMode(true);
685
+ process.stdin.pipe(stream);
686
+ stream.pipe(process.stdout);
687
+ stream.stderr.pipe(process.stderr);
688
+ stream.setWindow(process.stdout.rows, process.stdout.columns);
689
+ process.stdout.on('resize', () => {
690
+ stream.setWindow(process.stdout.rows, process.stdout.columns);
691
+ });
692
+ });
693
+ }).connect(sshOptions);
694
+ }
695
+
696
+ async function debug(api) {
697
+ const config = api.getConfig();
698
+ const {
699
+ selected,
700
+ description
701
+ } = await (0, _utils.pickInstance)(config, api.getArgs()[2]);
702
+
703
+ if (!selected) {
704
+ console.log(description);
705
+ console.log('Run "mup beanstalk debug <instance id>"');
706
+ process.exitCode = 1;
707
+ return;
708
+ }
709
+
710
+ const {
711
+ sshOptions,
712
+ removeSSHAccess
713
+ } = await (0, _utils.connectToInstance)(api, selected, 'mup beanstalk debug');
714
+ const conn = new _ssh.Client();
715
+ conn.on('ready', async () => {
716
+ const result = await (0, _utils.executeSSHCommand)(conn, 'sudo pkill -USR1 -u webapp -n node || sudo pkill -USR1 -u nodejs -n node');
717
+
718
+ if (api.verbose) {
719
+ console.log(result.output);
720
+ }
721
+
722
+ const server = _objectSpread(_objectSpread({}, sshOptions), {}, {
723
+ pem: api.resolvePath(config.app.sshKey.privateKey)
724
+ });
725
+
726
+ let loggedConnection = false;
727
+ api.forwardPort({
728
+ server,
729
+ localAddress: '0.0.0.0',
730
+ localPort: 9229,
731
+ remoteAddress: '127.0.0.1',
732
+ remotePort: 9229,
733
+
734
+ onError(error) {
735
+ console.error(error);
736
+ },
737
+
738
+ onReady() {
739
+ console.log('Connected to server');
740
+ console.log('');
741
+ console.log('Debugger listening on ws://127.0.0.1:9229');
742
+ console.log('');
743
+ console.log('To debug:');
744
+ console.log('1. Open chrome://inspect in Chrome');
745
+ console.log('2. Select "Open dedicated DevTools for Node"');
746
+ console.log('3. Wait a minute while it connects and loads the app.');
747
+ console.log(' When it is ready, the app\'s files will appear in the Sources tab');
748
+ console.log('');
749
+ console.log('Warning: Do not use breakpoints when debugging a production server.');
750
+ console.log('They will pause your server when hit, causing it to not handle methods or subscriptions.');
751
+ console.log('Use logpoints or something else that does not pause the server');
752
+ console.log('');
753
+ console.log('The debugger will be enabled until the next time the app is restarted,');
754
+ console.log('though only accessible while this command is running');
755
+ },
756
+
757
+ onConnection() {
758
+ if (!loggedConnection) {
759
+ // It isn't guaranteed the debugger is connected, but not many
760
+ // other tools will try to connect to port 9229.
761
+ console.log('');
762
+ console.log('Detected by debugger');
763
+ loggedConnection = true;
764
+ }
765
+ }
766
+
767
+ });
768
+ }).connect(sshOptions);
769
+ process.on('SIGINT', async () => {
770
+ await removeSSHAccess();
771
+ process.exit();
772
+ });
773
+ }
774
+ //# sourceMappingURL=command-handlers.js.map