@brunwig/mup-aws-beanstalk 0.8.7 → 2.0.3

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