@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.
- package/.babelrc +6 -0
- package/.eslintignore +2 -0
- package/.eslintrc.yml +10 -0
- package/.github/FUNDING.yml +12 -0
- package/changelog.md +56 -0
- package/docs/getting-started.md +83 -0
- package/docs/index.md +333 -0
- package/index.js +1 -0
- package/lib/assets/env.sh +30 -0
- package/lib/assets/env.yaml +19 -0
- package/lib/assets/graceful_shutdown.sh +14 -0
- package/lib/assets/graceful_shutdown.yaml +7 -0
- package/lib/assets/health-check.js +54 -0
- package/lib/assets/health-check.js.map +1 -0
- package/lib/assets/nginx-server.conf +59 -0
- package/lib/assets/nginx.conf +85 -0
- package/lib/assets/nginx.yaml +13 -0
- package/lib/assets/node.sh +25 -0
- package/lib/assets/node.yaml +8 -0
- package/lib/assets/npmrc +1 -0
- package/lib/assets/package.json +7 -0
- package/lib/assets/packages.yaml +5 -0
- package/lib/assets/start.sh +21 -0
- package/lib/aws.js +98 -0
- package/lib/aws.js.map +1 -0
- package/lib/certificates.js +64 -0
- package/lib/certificates.js.map +1 -0
- package/lib/command-handlers.js +774 -0
- package/lib/command-handlers.js.map +1 -0
- package/lib/commands.js +145 -0
- package/lib/commands.js.map +1 -0
- package/lib/download.js +27 -0
- package/lib/download.js.map +1 -0
- package/lib/eb-config.js +269 -0
- package/lib/eb-config.js.map +1 -0
- package/lib/env-ready.js +121 -0
- package/lib/env-ready.js.map +1 -0
- package/lib/env-settings.js +22 -0
- package/lib/env-settings.js.map +1 -0
- package/lib/index.js +111 -0
- package/lib/index.js.map +1 -0
- package/lib/policies.js +144 -0
- package/lib/policies.js.map +1 -0
- package/lib/prepare-bundle.js +245 -0
- package/lib/prepare-bundle.js.map +1 -0
- package/lib/recheck.js +27 -0
- package/lib/recheck.js.map +1 -0
- package/lib/upload.js +75 -0
- package/lib/upload.js.map +1 -0
- package/lib/utils.js +678 -0
- package/lib/utils.js.map +1 -0
- package/lib/validate.js +67 -0
- package/lib/validate.js.map +1 -0
- package/lib/versions.js +116 -0
- package/lib/versions.js.map +1 -0
- package/package.json +65 -0
- 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
|