@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.
- package/.babelrc +15 -4
- package/.eslintrc.yml +2 -2
- package/.yarn/install-state.gz +0 -0
- package/docs/getting-started.md +1 -1
- package/docs/index.md +22 -6
- package/index.js +1 -1
- package/lib/assets/Procfile +1 -0
- package/lib/assets/health-check.js +9 -1
- package/lib/assets/health-check.js.map +1 -1
- package/lib/assets/nginx-server.conf +14 -0
- package/lib/assets/node.sh +37 -7
- package/lib/assets/npm.sh +14 -0
- package/lib/assets/prevent-npm.sh +4 -0
- package/lib/assets/role-start.sh +61 -0
- package/lib/assets/start.sh +1 -1
- package/lib/assets/yarn.sh +17 -0
- package/lib/aws.js +43 -77
- package/lib/aws.js.map +1 -1
- package/lib/certificates.js +56 -59
- package/lib/certificates.js.map +1 -1
- package/lib/command-handlers.js +613 -637
- package/lib/command-handlers.js.map +1 -1
- package/lib/commands.js +144 -111
- package/lib/commands.js.map +1 -1
- package/lib/deployment-logs.js +127 -0
- package/lib/deployment-logs.js.map +1 -0
- package/lib/download.js +11 -18
- package/lib/download.js.map +1 -1
- package/lib/eb-config.js +246 -242
- package/lib/eb-config.js.map +1 -1
- package/lib/env-ready.js +87 -88
- package/lib/env-ready.js.map +1 -1
- package/lib/env-settings.js +13 -14
- package/lib/env-settings.js.map +1 -1
- package/lib/index.js +111 -81
- package/lib/index.js.map +1 -1
- package/lib/policies.js +130 -115
- package/lib/policies.js.map +1 -1
- package/lib/prepare-bundle.js +187 -194
- package/lib/prepare-bundle.js.map +1 -1
- package/lib/recheck.js +16 -13
- package/lib/recheck.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/upload.js +35 -49
- package/lib/upload.js.map +1 -1
- package/lib/utils.js +556 -577
- package/lib/utils.js.map +1 -1
- package/lib/validate.js +61 -59
- package/lib/validate.js.map +1 -1
- package/lib/versions.js +74 -81
- package/lib/versions.js.map +1 -1
- package/package.json +60 -26
- package/readme.md +2 -1
- package/tsconfig.json +41 -0
package/lib/utils.js
CHANGED
|
@@ -1,645 +1,624 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
});
|
|
6
|
-
exports.
|
|
7
|
-
exports.
|
|
8
|
-
exports.
|
|
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.
|
|
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.
|
|
31
|
-
exports.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
if (fs_1.default.existsSync(bundlePath) && useCachedBuild) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
61
58
|
}
|
|
62
59
|
function tmpBuildPath(appPath, api) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
217
|
-
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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(
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
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
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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(
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
added
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
385
|
+
return buckets.find(bucket => bucket.Name.indexOf(prefix) === 0);
|
|
398
386
|
}
|
|
399
387
|
async function ensureBucketPolicyAttached(bucketName, policy) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
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
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
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
|
-
|
|
479
|
-
|
|
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
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
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
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
EnvironmentResources
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
})
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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
|
-
|
|
546
|
-
sshKey
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
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
|