@datadog/datadog-ci 0.17.9 → 0.17.13
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/LICENSE-3rdparty.csv +2 -0
- package/README.md +9 -2
- package/dist/{commands/dependencies/index.d.ts → cli.d.ts} +0 -0
- package/dist/cli.js +34 -0
- package/dist/commands/{dsyms/index.d.ts → dependencies/cli.d.ts} +0 -0
- package/dist/commands/dependencies/{index.js → cli.js} +0 -0
- package/dist/commands/dependencies/upload.d.ts +1 -1
- package/dist/commands/{git-metadata/index.d.ts → dsyms/cli.d.ts} +0 -0
- package/dist/commands/dsyms/{index.js → cli.js} +0 -0
- package/dist/commands/dsyms/upload.d.ts +1 -1
- package/dist/commands/{junit/index.d.ts → git-metadata/cli.d.ts} +0 -0
- package/dist/commands/git-metadata/{index.js → cli.js} +0 -0
- package/dist/commands/git-metadata/upload.d.ts +1 -1
- package/dist/commands/git-metadata/upload.js +6 -1
- package/dist/commands/{lambda/index.d.ts → junit/cli.d.ts} +0 -0
- package/dist/commands/junit/{index.js → cli.js} +0 -0
- package/dist/commands/junit/upload.d.ts +1 -1
- package/dist/commands/junit/upload.js +1 -1
- package/dist/commands/lambda/__tests__/fixtures.d.ts +5 -1
- package/dist/commands/lambda/__tests__/fixtures.js +13 -2
- package/dist/commands/lambda/__tests__/functions/commons.test.js +400 -0
- package/dist/commands/lambda/__tests__/functions/instrument.test.js +229 -117
- package/dist/commands/lambda/__tests__/functions/uninstrument.test.js +80 -7
- package/dist/commands/lambda/__tests__/instrument.test.js +542 -111
- package/dist/commands/{sourcemaps/index.d.ts → lambda/__tests__/prompt.test.d.ts} +0 -0
- package/dist/commands/lambda/__tests__/prompt.test.js +216 -0
- package/dist/commands/lambda/__tests__/uninstrument.test.js +381 -17
- package/dist/commands/{trace/index.d.ts → lambda/cli.d.ts} +0 -0
- package/dist/commands/lambda/{index.js → cli.js} +0 -0
- package/dist/commands/lambda/constants.d.ts +27 -6
- package/dist/commands/lambda/constants.js +63 -6
- package/dist/commands/lambda/functions/commons.d.ts +49 -4
- package/dist/commands/lambda/functions/commons.js +198 -7
- package/dist/commands/lambda/functions/instrument.d.ts +5 -14
- package/dist/commands/lambda/functions/instrument.js +63 -80
- package/dist/commands/lambda/functions/uninstrument.d.ts +3 -2
- package/dist/commands/lambda/functions/uninstrument.js +23 -11
- package/dist/commands/lambda/instrument.d.ts +2 -1
- package/dist/commands/lambda/instrument.js +112 -58
- package/dist/commands/lambda/interfaces.d.ts +4 -1
- package/dist/commands/lambda/loggroup.js +3 -1
- package/dist/commands/lambda/prompt.d.ts +9 -0
- package/dist/commands/lambda/prompt.js +187 -0
- package/dist/commands/lambda/uninstrument.d.ts +2 -0
- package/dist/commands/lambda/uninstrument.js +107 -30
- package/dist/commands/sourcemaps/cli.d.ts +1 -0
- package/dist/commands/sourcemaps/{index.js → cli.js} +0 -0
- package/dist/commands/sourcemaps/upload.d.ts +1 -1
- package/dist/commands/synthetics/__tests__/cli.test.js +36 -13
- package/dist/commands/synthetics/__tests__/fixtures.js +1 -0
- package/dist/commands/synthetics/__tests__/run-test.test.js +48 -2
- package/dist/commands/synthetics/__tests__/utils.test.js +11 -4
- package/dist/commands/synthetics/__tests__/websocket.test.js +3 -3
- package/dist/commands/synthetics/cli.d.ts +1 -26
- package/dist/commands/synthetics/cli.js +2 -227
- package/dist/commands/synthetics/command.d.ts +27 -0
- package/dist/commands/synthetics/command.js +236 -0
- package/dist/commands/synthetics/index.d.ts +5 -1
- package/dist/commands/synthetics/index.js +31 -2
- package/dist/commands/synthetics/interfaces.d.ts +8 -3
- package/dist/commands/synthetics/interfaces.js +7 -3
- package/dist/commands/synthetics/reporters/default.js +5 -1
- package/dist/commands/synthetics/run-test.js +3 -1
- package/dist/commands/synthetics/utils.d.ts +3 -3
- package/dist/commands/synthetics/utils.js +17 -8
- package/dist/commands/trace/api.js +1 -1
- package/dist/commands/trace/cli.d.ts +1 -0
- package/dist/commands/trace/{index.js → cli.js} +0 -0
- package/dist/commands/trace/trace.d.ts +1 -1
- package/dist/helpers/__tests__/ci.test.js +97 -136
- package/dist/helpers/__tests__/user-provided-git.test.js +81 -27
- package/dist/helpers/__tests__/utils.test.js +4 -0
- package/dist/helpers/ci.js +54 -95
- package/dist/helpers/interfaces.d.ts +28 -2
- package/dist/helpers/user-provided-git.d.ts +2 -1
- package/dist/helpers/user-provided-git.js +29 -5
- package/dist/helpers/utils.d.ts +4 -0
- package/dist/helpers/utils.js +18 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +23 -31
- package/package.json +10 -8
|
@@ -19,74 +19,116 @@ const upload_1 = require("../git-metadata/upload");
|
|
|
19
19
|
const constants_1 = require("./constants");
|
|
20
20
|
const commons_1 = require("./functions/commons");
|
|
21
21
|
const instrument_1 = require("./functions/instrument");
|
|
22
|
+
const prompt_1 = require("./prompt");
|
|
22
23
|
class InstrumentCommand extends clipanion_1.Command {
|
|
23
24
|
constructor() {
|
|
24
25
|
super(...arguments);
|
|
25
26
|
this.config = {
|
|
26
27
|
functions: [],
|
|
27
|
-
region: process.env.
|
|
28
|
+
region: process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR],
|
|
28
29
|
tracing: 'true',
|
|
29
30
|
};
|
|
30
31
|
this.dryRun = false;
|
|
31
32
|
this.functions = [];
|
|
33
|
+
this.interactive = false;
|
|
32
34
|
this.sourceCodeIntegration = false;
|
|
33
35
|
}
|
|
34
36
|
execute() {
|
|
37
|
+
var _a, _b, _c;
|
|
35
38
|
return __awaiter(this, void 0, void 0, function* () {
|
|
36
39
|
const lambdaConfig = { lambda: this.config };
|
|
37
40
|
this.config = (yield utils_1.parseConfigFile(lambdaConfig, this.configPath)).lambda;
|
|
41
|
+
let hasSpecifiedFunctions = this.functions.length !== 0 || this.config.functions.length !== 0;
|
|
42
|
+
if (this.interactive) {
|
|
43
|
+
try {
|
|
44
|
+
if (commons_1.isMissingAWSCredentials()) {
|
|
45
|
+
this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[!]'))} No existing AWS credentials found, let's set them up!\n`);
|
|
46
|
+
yield prompt_1.requestAWSCredentials();
|
|
47
|
+
}
|
|
48
|
+
if (commons_1.isMissingDatadogEnvVars()) {
|
|
49
|
+
this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[!]'))} Configure Datadog settings.\n`);
|
|
50
|
+
yield prompt_1.requestDatadogEnvVars();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} ${e}\n`);
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
const region = (_b = (_a = this.region) !== null && _a !== void 0 ? _a : this.config.region) !== null && _b !== void 0 ? _b : process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR];
|
|
58
|
+
this.region = region;
|
|
59
|
+
// If user doesn't specify functions, allow them
|
|
60
|
+
// to select from all of the functions from the
|
|
61
|
+
// requested region.
|
|
62
|
+
if (!hasSpecifiedFunctions) {
|
|
63
|
+
try {
|
|
64
|
+
const lambda = new aws_sdk_1.Lambda({ region });
|
|
65
|
+
this.context.stdout.write('Fetching Lambda functions, this might take a while.\n');
|
|
66
|
+
const functionNames = (_c = (yield commons_1.getAllLambdaFunctionConfigs(lambda)).map((config) => config.FunctionName).sort()) !== null && _c !== void 0 ? _c : [];
|
|
67
|
+
if (functionNames.length === 0) {
|
|
68
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't find any Lambda functions in the specified region.\n`);
|
|
69
|
+
return 1;
|
|
70
|
+
}
|
|
71
|
+
const functions = yield prompt_1.requestFunctionSelection(functionNames);
|
|
72
|
+
this.functions = functions;
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
38
80
|
const settings = this.getSettings();
|
|
39
81
|
if (settings === undefined) {
|
|
40
82
|
return 1;
|
|
41
83
|
}
|
|
42
|
-
|
|
43
|
-
const hasSpecifiedRegExPattern = this.regExPattern !== undefined;
|
|
44
|
-
if (!
|
|
45
|
-
this.context.stdout.write('No functions specified for instrumentation.\n
|
|
84
|
+
hasSpecifiedFunctions = this.functions.length !== 0 || this.config.functions.length !== 0;
|
|
85
|
+
const hasSpecifiedRegExPattern = this.regExPattern !== undefined && this.regExPattern !== '';
|
|
86
|
+
if (!hasSpecifiedFunctions && !hasSpecifiedRegExPattern) {
|
|
87
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} No functions specified for instrumentation.\n`);
|
|
46
88
|
return 1;
|
|
47
89
|
}
|
|
48
90
|
if (settings.extensionVersion && settings.forwarderARN) {
|
|
49
|
-
this.context.stdout.write('"extensionVersion" and "forwarder" should not be used at the same time.\n
|
|
91
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} "extensionVersion" and "forwarder" should not be used at the same time.\n`);
|
|
50
92
|
return 1;
|
|
51
93
|
}
|
|
52
94
|
if (this.sourceCodeIntegration) {
|
|
53
95
|
if (!process.env.DATADOG_API_KEY) {
|
|
54
|
-
this.context.stdout.write('Missing DATADOG_API_KEY in your environment\n
|
|
96
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} Missing DATADOG_API_KEY in your environment\n`);
|
|
55
97
|
return 1;
|
|
56
98
|
}
|
|
57
99
|
try {
|
|
58
100
|
yield this.getGitDataAndUpload(settings);
|
|
59
101
|
}
|
|
60
102
|
catch (err) {
|
|
61
|
-
this.context.stdout.write(`${err}\n`);
|
|
103
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} ${err}\n`);
|
|
62
104
|
return 1;
|
|
63
105
|
}
|
|
64
106
|
}
|
|
65
107
|
const configGroups = [];
|
|
66
108
|
if (hasSpecifiedRegExPattern) {
|
|
67
|
-
if (
|
|
109
|
+
if (hasSpecifiedFunctions) {
|
|
68
110
|
const usedCommand = this.functions.length !== 0 ? '"--functions"' : 'Functions in config file';
|
|
69
|
-
this.context.stdout.write(`${usedCommand} and "--functions-regex" should not be used at the same time.\n`);
|
|
111
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} ${usedCommand} and "--functions-regex" should not be used at the same time.\n`);
|
|
70
112
|
return 1;
|
|
71
113
|
}
|
|
72
114
|
if (this.regExPattern.match(':')) {
|
|
73
|
-
this.context.stdout.write(
|
|
115
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} "--functions-regex" isn't meant to be used with ARNs.\n`);
|
|
74
116
|
return 1;
|
|
75
117
|
}
|
|
76
118
|
const region = this.region || this.config.region;
|
|
77
119
|
if (!region) {
|
|
78
|
-
this.context.stdout.write('No default region specified. Use
|
|
120
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} No default region specified. Use \`-r\`, \`--region\`.\n`);
|
|
79
121
|
return 1;
|
|
80
122
|
}
|
|
81
123
|
try {
|
|
82
124
|
const cloudWatchLogs = new aws_sdk_1.CloudWatchLogs({ region });
|
|
83
125
|
const lambda = new aws_sdk_1.Lambda({ region });
|
|
84
|
-
this.context.stdout.write('Fetching
|
|
85
|
-
const configs = yield instrument_1.
|
|
126
|
+
this.context.stdout.write('Fetching Lambda functions, this might take a while.\n');
|
|
127
|
+
const configs = yield instrument_1.getInstrumentedFunctionConfigsFromRegEx(lambda, cloudWatchLogs, region, this.regExPattern, settings);
|
|
86
128
|
configGroups.push({ configs, lambda, cloudWatchLogs, region: region });
|
|
87
129
|
}
|
|
88
130
|
catch (err) {
|
|
89
|
-
this.context.stdout.write(
|
|
131
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
|
|
90
132
|
return 1;
|
|
91
133
|
}
|
|
92
134
|
}
|
|
@@ -96,18 +138,18 @@ class InstrumentCommand extends clipanion_1.Command {
|
|
|
96
138
|
functionGroups = commons_1.collectFunctionsByRegion(this.functions.length !== 0 ? this.functions : this.config.functions, this.region || this.config.region);
|
|
97
139
|
}
|
|
98
140
|
catch (err) {
|
|
99
|
-
this.context.stdout.write(
|
|
141
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't group functions. ${err}`);
|
|
100
142
|
return 1;
|
|
101
143
|
}
|
|
102
144
|
for (const [region, functionList] of Object.entries(functionGroups)) {
|
|
103
145
|
const lambda = new aws_sdk_1.Lambda({ region });
|
|
104
146
|
const cloudWatchLogs = new aws_sdk_1.CloudWatchLogs({ region });
|
|
105
147
|
try {
|
|
106
|
-
const configs = yield instrument_1.
|
|
148
|
+
const configs = yield instrument_1.getInstrumentedFunctionConfigs(lambda, cloudWatchLogs, region, functionList, settings);
|
|
107
149
|
configGroups.push({ configs, lambda, cloudWatchLogs, region });
|
|
108
150
|
}
|
|
109
151
|
catch (err) {
|
|
110
|
-
this.context.stdout.write(
|
|
152
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
|
|
111
153
|
return 1;
|
|
112
154
|
}
|
|
113
155
|
}
|
|
@@ -117,20 +159,26 @@ class InstrumentCommand extends clipanion_1.Command {
|
|
|
117
159
|
if (this.dryRun || configList.length === 0) {
|
|
118
160
|
return 0;
|
|
119
161
|
}
|
|
162
|
+
const willUpdate = commons_1.willUpdateFunctionConfigs(configList);
|
|
163
|
+
if (this.interactive && willUpdate) {
|
|
164
|
+
this.context.stdout.write(`${chalk_1.yellow('[!]')} Confirmation needed.\n`);
|
|
165
|
+
const isConfirmed = yield prompt_1.requestChangesConfirmation('Do you want to apply the changes?');
|
|
166
|
+
if (!isConfirmed) {
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
this.context.stdout.write(`${chalk_1.yellow('[!]')} Instrumenting functions.\n`);
|
|
170
|
+
}
|
|
120
171
|
const promises = Object.values(configGroups).map((group) => commons_1.updateLambdaFunctionConfigs(group.lambda, group.cloudWatchLogs, group.configs));
|
|
121
172
|
try {
|
|
122
173
|
yield Promise.all(promises);
|
|
123
174
|
}
|
|
124
175
|
catch (err) {
|
|
125
|
-
this.context.stdout.write(
|
|
176
|
+
this.context.stdout.write(`${chalk_1.red('[Error]')} Failure during update. ${err}\n`);
|
|
126
177
|
return 1;
|
|
127
178
|
}
|
|
128
179
|
return 0;
|
|
129
180
|
});
|
|
130
181
|
}
|
|
131
|
-
convertStringBooleanToBoolean(fallback, value, configValue) {
|
|
132
|
-
return value ? value.toLowerCase() === 'true' : configValue ? configValue.toLowerCase() === 'true' : fallback;
|
|
133
|
-
}
|
|
134
182
|
getCurrentGitStatus() {
|
|
135
183
|
return __awaiter(this, void 0, void 0, function* () {
|
|
136
184
|
const simpleGit = yield git_1.newSimpleGit();
|
|
@@ -173,7 +221,7 @@ class InstrumentCommand extends clipanion_1.Command {
|
|
|
173
221
|
});
|
|
174
222
|
}
|
|
175
223
|
getSettings() {
|
|
176
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q
|
|
224
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
177
225
|
const layerVersionStr = (_a = this.layerVersion) !== null && _a !== void 0 ? _a : this.config.layerVersion;
|
|
178
226
|
const extensionVersionStr = (_b = this.extensionVersion) !== null && _b !== void 0 ? _b : this.config.extensionVersion;
|
|
179
227
|
const layerAWSAccount = (_c = this.layerAWSAccount) !== null && _c !== void 0 ? _c : this.config.layerAWSAccount;
|
|
@@ -195,23 +243,26 @@ class InstrumentCommand extends clipanion_1.Command {
|
|
|
195
243
|
return;
|
|
196
244
|
}
|
|
197
245
|
const stringBooleansMap = {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
246
|
+
captureLambdaPayload: (_e = this.captureLambdaPayload) !== null && _e !== void 0 ? _e : this.config.captureLambdaPayload,
|
|
247
|
+
flushMetricsToLogs: (_f = this.flushMetricsToLogs) !== null && _f !== void 0 ? _f : this.config.flushMetricsToLogs,
|
|
248
|
+
mergeXrayTraces: (_g = this.mergeXrayTraces) !== null && _g !== void 0 ? _g : this.config.mergeXrayTraces,
|
|
249
|
+
tracing: (_h = this.tracing) !== null && _h !== void 0 ? _h : this.config.tracing,
|
|
201
250
|
};
|
|
202
251
|
for (const [stringBoolean, value] of Object.entries(stringBooleansMap)) {
|
|
203
|
-
if (!['true', 'false', undefined].includes(value)) {
|
|
252
|
+
if (!['true', 'false', undefined].includes(value === null || value === void 0 ? void 0 : value.toString().toLowerCase())) {
|
|
204
253
|
this.context.stdout.write(`Invalid boolean specified for ${stringBoolean}.\n`);
|
|
205
254
|
return;
|
|
206
255
|
}
|
|
207
256
|
}
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
const
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
const
|
|
257
|
+
const captureLambdaPayload = commons_1.coerceBoolean(false, this.captureLambdaPayload, this.config.captureLambdaPayload);
|
|
258
|
+
const flushMetricsToLogs = commons_1.coerceBoolean(true, this.flushMetricsToLogs, this.config.flushMetricsToLogs);
|
|
259
|
+
const mergeXrayTraces = commons_1.coerceBoolean(false, this.mergeXrayTraces, this.config.mergeXrayTraces);
|
|
260
|
+
const tracingEnabled = commons_1.coerceBoolean(true, this.tracing, this.config.tracing);
|
|
261
|
+
const interactive = commons_1.coerceBoolean(false, this.interactive, this.config.interactive);
|
|
262
|
+
const logLevel = (_j = this.logLevel) !== null && _j !== void 0 ? _j : this.config.logLevel;
|
|
263
|
+
const service = (_k = this.service) !== null && _k !== void 0 ? _k : this.config.service;
|
|
264
|
+
const environment = (_l = this.environment) !== null && _l !== void 0 ? _l : this.config.environment;
|
|
265
|
+
const version = (_m = this.version) !== null && _m !== void 0 ? _m : this.config.version;
|
|
215
266
|
const tagsMap = {
|
|
216
267
|
environment,
|
|
217
268
|
service,
|
|
@@ -228,17 +279,19 @@ class InstrumentCommand extends clipanion_1.Command {
|
|
|
228
279
|
const plural = tagsMissing.length > 1;
|
|
229
280
|
this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[Warning]'))} The ${tags} tag${plural ? 's have' : ' has'} not been configured. Learn more about Datadog unified service tagging: ${chalk_1.underline(chalk_1.blueBright('https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging/#serverless-environment.'))}\n`);
|
|
230
281
|
}
|
|
231
|
-
const extraTags = (
|
|
282
|
+
const extraTags = (_p = (_o = this.extraTags) === null || _o === void 0 ? void 0 : _o.toLowerCase()) !== null && _p !== void 0 ? _p : (_q = this.config.extraTags) === null || _q === void 0 ? void 0 : _q.toLowerCase();
|
|
232
283
|
if (extraTags && !commons_1.sentenceMatchesRegEx(extraTags, constants_1.EXTRA_TAGS_REG_EXP)) {
|
|
233
284
|
this.context.stdout.write('Extra tags do not comply with the <key>:<value> array.\n');
|
|
234
285
|
return;
|
|
235
286
|
}
|
|
236
287
|
return {
|
|
288
|
+
captureLambdaPayload,
|
|
237
289
|
environment,
|
|
238
290
|
extensionVersion,
|
|
239
291
|
extraTags,
|
|
240
292
|
flushMetricsToLogs,
|
|
241
293
|
forwarderARN,
|
|
294
|
+
interactive,
|
|
242
295
|
layerAWSAccount,
|
|
243
296
|
layerVersion,
|
|
244
297
|
logLevel,
|
|
@@ -249,25 +302,24 @@ class InstrumentCommand extends clipanion_1.Command {
|
|
|
249
302
|
};
|
|
250
303
|
}
|
|
251
304
|
printPlannedActions(configs) {
|
|
252
|
-
var _a, _b, _c;
|
|
253
305
|
const prefix = this.dryRun ? chalk_1.bold(chalk_1.cyan('[Dry Run] ')) : '';
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (config.updateRequest !== undefined ||
|
|
257
|
-
((_a = config.logGroupConfiguration) === null || _a === void 0 ? void 0 : _a.createLogGroupRequest) !== undefined ||
|
|
258
|
-
((_b = config.logGroupConfiguration) === null || _b === void 0 ? void 0 : _b.deleteSubscriptionFilterRequest) !== undefined ||
|
|
259
|
-
((_c = config.logGroupConfiguration) === null || _c === void 0 ? void 0 : _c.subscriptionFilterRequest) !== undefined ||
|
|
260
|
-
(config === null || config === void 0 ? void 0 : config.tagConfiguration) !== undefined) {
|
|
261
|
-
anyUpdates = true;
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (!anyUpdates) {
|
|
306
|
+
const willUpdate = commons_1.willUpdateFunctionConfigs(configs);
|
|
307
|
+
if (!willUpdate) {
|
|
266
308
|
this.context.stdout.write(`\n${prefix}No updates will be applied\n`);
|
|
267
309
|
return;
|
|
268
310
|
}
|
|
269
311
|
this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[Warning]'))} Instrument your ${chalk_1.hex('#FF9900').bold('Lambda')} functions in a dev or staging environment first. Should the instrumentation result be unsatisfactory, run \`${chalk_1.bold('uninstrument')}\` with the same arguments to revert the changes.\n`);
|
|
270
|
-
this.context.stdout.write(
|
|
312
|
+
this.context.stdout.write(`\n${chalk_1.bold(chalk_1.yellow('[!]'))} Functions to be updated:\n`);
|
|
313
|
+
for (const config of configs) {
|
|
314
|
+
this.context.stdout.write(`\t- ${chalk_1.bold(config.functionARN)}\n`);
|
|
315
|
+
// Later, we should inform which layer is the latest.
|
|
316
|
+
if (this.interactive) {
|
|
317
|
+
if (!this.extensionVersion || !this.extensionVersion) {
|
|
318
|
+
this.context.stdout.write(`\t${chalk_1.bold(chalk_1.yellow('[Warning]'))} At least one latest layer version is being used. Ensure to lock in versions for production applications using \`--layerVersion\` and \`--extensionVersion\`.\n`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
this.context.stdout.write(`\n${prefix}Will apply the following updates:\n`);
|
|
271
323
|
for (const config of configs) {
|
|
272
324
|
if (config.updateRequest) {
|
|
273
325
|
this.context.stdout.write(`UpdateFunctionConfiguration -> ${config.functionARN}\n${JSON.stringify(config.updateRequest, undefined, 2)}\n`);
|
|
@@ -301,20 +353,22 @@ class InstrumentCommand extends clipanion_1.Command {
|
|
|
301
353
|
exports.InstrumentCommand = InstrumentCommand;
|
|
302
354
|
InstrumentCommand.addPath('lambda', 'instrument');
|
|
303
355
|
InstrumentCommand.addOption('functions', clipanion_1.Command.Array('-f,--function'));
|
|
304
|
-
InstrumentCommand.addOption('regExPattern', clipanion_1.Command.String('--functions-regex'));
|
|
356
|
+
InstrumentCommand.addOption('regExPattern', clipanion_1.Command.String('--functions-regex,--functionsRegex'));
|
|
305
357
|
InstrumentCommand.addOption('region', clipanion_1.Command.String('-r,--region'));
|
|
306
|
-
InstrumentCommand.addOption('extensionVersion', clipanion_1.Command.String('-e,--extensionVersion'));
|
|
307
|
-
InstrumentCommand.addOption('layerVersion', clipanion_1.Command.String('-v,--layerVersion'));
|
|
308
|
-
InstrumentCommand.addOption('layerAWSAccount', clipanion_1.Command.String('-a,--layerAccount', { hidden: true }));
|
|
358
|
+
InstrumentCommand.addOption('extensionVersion', clipanion_1.Command.String('-e,--extension-version,--extensionVersion'));
|
|
359
|
+
InstrumentCommand.addOption('layerVersion', clipanion_1.Command.String('-v,--layer-version,--layerVersion'));
|
|
360
|
+
InstrumentCommand.addOption('layerAWSAccount', clipanion_1.Command.String('-a,--layer-account,--layerAccount', { hidden: true }));
|
|
309
361
|
InstrumentCommand.addOption('tracing', clipanion_1.Command.String('--tracing'));
|
|
310
|
-
InstrumentCommand.addOption('mergeXrayTraces', clipanion_1.Command.String('--mergeXrayTraces'));
|
|
311
|
-
InstrumentCommand.addOption('flushMetricsToLogs', clipanion_1.Command.String('--flushMetricsToLogs'));
|
|
362
|
+
InstrumentCommand.addOption('mergeXrayTraces', clipanion_1.Command.String('--merge-xray-traces,--mergeXrayTraces'));
|
|
363
|
+
InstrumentCommand.addOption('flushMetricsToLogs', clipanion_1.Command.String('--flush-metrics-to-logs,--flushMetricsToLogs'));
|
|
312
364
|
InstrumentCommand.addOption('dryRun', clipanion_1.Command.Boolean('-d,--dry'));
|
|
313
365
|
InstrumentCommand.addOption('configPath', clipanion_1.Command.String('--config'));
|
|
314
366
|
InstrumentCommand.addOption('forwarder', clipanion_1.Command.String('--forwarder'));
|
|
315
|
-
InstrumentCommand.addOption('logLevel', clipanion_1.Command.String('--logLevel'));
|
|
367
|
+
InstrumentCommand.addOption('logLevel', clipanion_1.Command.String('--log-level,--logLevel'));
|
|
316
368
|
InstrumentCommand.addOption('service', clipanion_1.Command.String('--service'));
|
|
317
369
|
InstrumentCommand.addOption('environment', clipanion_1.Command.String('--env'));
|
|
318
370
|
InstrumentCommand.addOption('version', clipanion_1.Command.String('--version'));
|
|
319
|
-
InstrumentCommand.addOption('extraTags', clipanion_1.Command.String('--extra-tags'));
|
|
320
|
-
InstrumentCommand.addOption('sourceCodeIntegration', clipanion_1.Command.Boolean('-s,--source-code-integration'));
|
|
371
|
+
InstrumentCommand.addOption('extraTags', clipanion_1.Command.String('--extra-tags,--extraTags'));
|
|
372
|
+
InstrumentCommand.addOption('sourceCodeIntegration', clipanion_1.Command.Boolean('-s,--source-code-integration,--sourceCodeIntegration'));
|
|
373
|
+
InstrumentCommand.addOption('interactive', clipanion_1.Command.Boolean('-i,--interactive'));
|
|
374
|
+
InstrumentCommand.addOption('captureLambdaPayload', clipanion_1.Command.String('--capture-lambda-payload,--captureLambdaPayload'));
|
|
@@ -4,12 +4,14 @@ import { CloudWatchLogs, Lambda } from 'aws-sdk';
|
|
|
4
4
|
* the CLI in order to instrument properly.
|
|
5
5
|
*/
|
|
6
6
|
export interface LambdaConfigOptions {
|
|
7
|
+
captureLambdaPayload?: string;
|
|
7
8
|
environment?: string;
|
|
8
9
|
extensionVersion?: string;
|
|
9
10
|
extraTags?: string;
|
|
10
11
|
flushMetricsToLogs?: string;
|
|
11
12
|
forwarder?: string;
|
|
12
13
|
functions: string[];
|
|
14
|
+
interactive?: boolean;
|
|
13
15
|
layerAWSAccount?: string;
|
|
14
16
|
layerVersion?: string;
|
|
15
17
|
logLevel?: string;
|
|
@@ -27,7 +29,6 @@ export interface LambdaConfigOptions {
|
|
|
27
29
|
export interface FunctionConfiguration {
|
|
28
30
|
functionARN: string;
|
|
29
31
|
lambdaConfig: Lambda.FunctionConfiguration;
|
|
30
|
-
lambdaLibraryLayerArn?: string;
|
|
31
32
|
logGroupConfiguration?: LogGroupConfiguration;
|
|
32
33
|
tagConfiguration?: TagConfiguration;
|
|
33
34
|
updateRequest?: Lambda.UpdateFunctionConfigurationRequest;
|
|
@@ -37,9 +38,11 @@ export interface FunctionConfiguration {
|
|
|
37
38
|
* lambda to be instrumented.
|
|
38
39
|
*/
|
|
39
40
|
export interface InstrumentationSettings extends InstrumentationTags {
|
|
41
|
+
captureLambdaPayload?: boolean;
|
|
40
42
|
extensionVersion?: number;
|
|
41
43
|
flushMetricsToLogs: boolean;
|
|
42
44
|
forwarderARN?: string;
|
|
45
|
+
interactive?: boolean;
|
|
43
46
|
layerAWSAccount?: string;
|
|
44
47
|
layerVersion?: number;
|
|
45
48
|
logLevel?: string;
|
|
@@ -26,7 +26,9 @@ const applyLogGroupConfig = (logs, config) => __awaiter(void 0, void 0, void 0,
|
|
|
26
26
|
if (deleteSubscriptionFilterRequest !== undefined) {
|
|
27
27
|
yield logs.deleteSubscriptionFilter(deleteSubscriptionFilterRequest).promise();
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
if (subscriptionFilterRequest !== undefined) {
|
|
30
|
+
yield logs.putSubscriptionFilter(subscriptionFilterRequest).promise();
|
|
31
|
+
}
|
|
30
32
|
});
|
|
31
33
|
exports.applyLogGroupConfig = applyLogGroupConfig;
|
|
32
34
|
const calculateLogGroupUpdateRequest = (logs, logGroupName, forwarderARN) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CheckboxQuestion, ConfirmQuestion, InputQuestion, ListQuestion } from 'inquirer';
|
|
2
|
+
export declare const datadogApiKeyTypeQuestion: (datadogSite: string) => ListQuestion;
|
|
3
|
+
export declare const datadogEnvVarsQuestions: (datadogApiKeyType: Record<string, any>) => InputQuestion;
|
|
4
|
+
export declare const confirmationQuestion: (message: string) => ConfirmQuestion;
|
|
5
|
+
export declare const functionSelectionQuestion: (functionNames: string[]) => CheckboxQuestion;
|
|
6
|
+
export declare const requestAWSCredentials: () => Promise<void>;
|
|
7
|
+
export declare const requestDatadogEnvVars: () => Promise<void>;
|
|
8
|
+
export declare const requestChangesConfirmation: (message: string) => Promise<any>;
|
|
9
|
+
export declare const requestFunctionSelection: (functionNames: string[]) => Promise<any>;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.requestFunctionSelection = exports.requestChangesConfirmation = exports.requestDatadogEnvVars = exports.requestAWSCredentials = exports.functionSelectionQuestion = exports.confirmationQuestion = exports.datadogEnvVarsQuestions = exports.datadogApiKeyTypeQuestion = void 0;
|
|
13
|
+
const chalk_1 = require("chalk");
|
|
14
|
+
const inquirer_1 = require("inquirer");
|
|
15
|
+
const constants_1 = require("./constants");
|
|
16
|
+
const commons_1 = require("./functions/commons");
|
|
17
|
+
const awsCredentialsQuestions = [
|
|
18
|
+
{
|
|
19
|
+
// AWS_ACCESS_KEY_ID question
|
|
20
|
+
message: 'Enter AWS Access Key ID:',
|
|
21
|
+
name: constants_1.AWS_ACCESS_KEY_ID_ENV_VAR,
|
|
22
|
+
type: 'input',
|
|
23
|
+
validate: (value) => {
|
|
24
|
+
if (!value || !commons_1.sentenceMatchesRegEx(value, constants_1.AWS_ACCESS_KEY_ID_REG_EXP)) {
|
|
25
|
+
return 'Enter a valid AWS Access Key ID.';
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
// AWS_SECRET_ACCESS_KEY_ENV_VAR question
|
|
32
|
+
mask: true,
|
|
33
|
+
message: 'Enter AWS Secret Access Key:',
|
|
34
|
+
name: constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR,
|
|
35
|
+
type: 'password',
|
|
36
|
+
validate: (value) => {
|
|
37
|
+
if (!value || !commons_1.sentenceMatchesRegEx(value, constants_1.AWS_SECRET_ACCESS_KEY_REG_EXP)) {
|
|
38
|
+
return 'Enter a valid AWS Secret Access Key.';
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
// AWS_SESSION_TOKEN
|
|
45
|
+
mask: true,
|
|
46
|
+
message: 'Enter AWS Session Token (optional):',
|
|
47
|
+
name: constants_1.AWS_SESSION_TOKEN_ENV_VAR,
|
|
48
|
+
type: 'password',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
// AWS_DEFAULT_REGION
|
|
52
|
+
choices: constants_1.AWS_REGIONS,
|
|
53
|
+
default: 0,
|
|
54
|
+
message: 'Select an AWS region:',
|
|
55
|
+
name: constants_1.AWS_DEFAULT_REGION_ENV_VAR,
|
|
56
|
+
type: 'list',
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
const datadogApiKeyTypeQuestion = (datadogSite) => ({
|
|
60
|
+
choices: [
|
|
61
|
+
{
|
|
62
|
+
name: `Plain text ${chalk_1.bold('API Key')} (Recommended for trial users) `,
|
|
63
|
+
value: {
|
|
64
|
+
envVar: constants_1.CI_API_KEY_ENV_VAR,
|
|
65
|
+
message: 'API Key:',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
new inquirer_1.Separator(),
|
|
69
|
+
{
|
|
70
|
+
name: `API key encrypted with AWS Key Management Service ${chalk_1.bold('(KMS) API Key')}`,
|
|
71
|
+
value: {
|
|
72
|
+
envVar: constants_1.CI_KMS_API_KEY_ENV_VAR,
|
|
73
|
+
message: 'KMS Encrypted API Key:',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: `AWS Secrets Manager ${chalk_1.bold('API Key Secret ARN')}`,
|
|
78
|
+
value: {
|
|
79
|
+
envVar: constants_1.CI_API_KEY_SECRET_ARN_ENV_VAR,
|
|
80
|
+
message: 'API Key Secret ARN:',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
message: `Which type of Datadog API Key you want to set? \nLearn more at ${chalk_1.blueBright(`https://app.${datadogSite}/organization-settings/api-keys`)}`,
|
|
85
|
+
name: 'type',
|
|
86
|
+
type: 'list',
|
|
87
|
+
});
|
|
88
|
+
exports.datadogApiKeyTypeQuestion = datadogApiKeyTypeQuestion;
|
|
89
|
+
const datadogSiteQuestion = {
|
|
90
|
+
// DATADOG SITE
|
|
91
|
+
choices: constants_1.SITES,
|
|
92
|
+
message: `Select the Datadog site to send data. \nLearn more at ${chalk_1.blueBright('https://docs.datadoghq.com/getting_started/site/')}`,
|
|
93
|
+
name: constants_1.CI_SITE_ENV_VAR,
|
|
94
|
+
type: 'list',
|
|
95
|
+
};
|
|
96
|
+
const datadogEnvVarsQuestions = (datadogApiKeyType) => ({
|
|
97
|
+
// DATADOG API KEY given type
|
|
98
|
+
default: process.env[datadogApiKeyType.envVar],
|
|
99
|
+
message: datadogApiKeyType.message,
|
|
100
|
+
name: datadogApiKeyType.envVar,
|
|
101
|
+
type: 'input',
|
|
102
|
+
validate: (value) => {
|
|
103
|
+
if (!value || !commons_1.sentenceMatchesRegEx(value, constants_1.DATADOG_API_KEY_REG_EXP)) {
|
|
104
|
+
return 'Enter a valid Datadog API Key.';
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
exports.datadogEnvVarsQuestions = datadogEnvVarsQuestions;
|
|
110
|
+
const confirmationQuestion = (message) => ({
|
|
111
|
+
message,
|
|
112
|
+
name: 'confirmation',
|
|
113
|
+
type: 'confirm',
|
|
114
|
+
});
|
|
115
|
+
exports.confirmationQuestion = confirmationQuestion;
|
|
116
|
+
const functionSelectionQuestion = (functionNames) => ({
|
|
117
|
+
choices: functionNames,
|
|
118
|
+
message: 'Select the functions to modify',
|
|
119
|
+
name: 'functions',
|
|
120
|
+
type: 'checkbox',
|
|
121
|
+
validate: (selectedFunctions) => {
|
|
122
|
+
if (selectedFunctions.length < 1) {
|
|
123
|
+
return 'You must choose at least one function.';
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
exports.functionSelectionQuestion = functionSelectionQuestion;
|
|
129
|
+
const requestAWSCredentials = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
130
|
+
try {
|
|
131
|
+
const awsCredentialsAnswers = yield inquirer_1.prompt(awsCredentialsQuestions);
|
|
132
|
+
process.env[constants_1.AWS_ACCESS_KEY_ID_ENV_VAR] = awsCredentialsAnswers[constants_1.AWS_ACCESS_KEY_ID_ENV_VAR];
|
|
133
|
+
process.env[constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR] = awsCredentialsAnswers[constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR];
|
|
134
|
+
process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR] = awsCredentialsAnswers[constants_1.AWS_DEFAULT_REGION_ENV_VAR];
|
|
135
|
+
if (awsCredentialsAnswers[constants_1.AWS_SESSION_TOKEN_ENV_VAR] !== undefined) {
|
|
136
|
+
process.env[constants_1.AWS_SESSION_TOKEN_ENV_VAR] = awsCredentialsAnswers[constants_1.AWS_SESSION_TOKEN_ENV_VAR];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
if (e instanceof Error) {
|
|
141
|
+
throw Error(`Couldn't set AWS Credentials. ${e.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
exports.requestAWSCredentials = requestAWSCredentials;
|
|
146
|
+
const requestDatadogEnvVars = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
147
|
+
try {
|
|
148
|
+
const datadogSiteAnswer = yield inquirer_1.prompt(datadogSiteQuestion);
|
|
149
|
+
const selectedDatadogSite = datadogSiteAnswer[constants_1.CI_SITE_ENV_VAR];
|
|
150
|
+
process.env[constants_1.CI_SITE_ENV_VAR] = selectedDatadogSite;
|
|
151
|
+
const datadogApiKeyTypeAnswer = yield inquirer_1.prompt(exports.datadogApiKeyTypeQuestion(selectedDatadogSite));
|
|
152
|
+
const datadogApiKeyType = datadogApiKeyTypeAnswer.type;
|
|
153
|
+
const datadogEnvVars = yield inquirer_1.prompt(exports.datadogEnvVarsQuestions(datadogApiKeyType));
|
|
154
|
+
const selectedDatadogApiKeyEnvVar = datadogApiKeyType.envVar;
|
|
155
|
+
process.env[selectedDatadogApiKeyEnvVar] = datadogEnvVars[selectedDatadogApiKeyEnvVar];
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
if (e instanceof Error) {
|
|
159
|
+
throw Error(`Couldn't set Datadog Environment Variables. ${e.message}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
exports.requestDatadogEnvVars = requestDatadogEnvVars;
|
|
164
|
+
const requestChangesConfirmation = (message) => __awaiter(void 0, void 0, void 0, function* () {
|
|
165
|
+
try {
|
|
166
|
+
const confirmationAnswer = yield inquirer_1.prompt(exports.confirmationQuestion(message));
|
|
167
|
+
return confirmationAnswer.confirmation;
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
if (e instanceof Error) {
|
|
171
|
+
throw Error(`Couldn't receive confirmation. ${e.message}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
exports.requestChangesConfirmation = requestChangesConfirmation;
|
|
176
|
+
const requestFunctionSelection = (functionNames) => __awaiter(void 0, void 0, void 0, function* () {
|
|
177
|
+
try {
|
|
178
|
+
const selectedFunctionsAnswer = yield inquirer_1.prompt(exports.functionSelectionQuestion(functionNames));
|
|
179
|
+
return selectedFunctionsAnswer.functions;
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
if (e instanceof Error) {
|
|
183
|
+
throw Error(`Couldn't receive selected functions. ${e.message}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
exports.requestFunctionSelection = requestFunctionSelection;
|