@elastic/synthetics 1.0.0-beta.34 → 1.0.0-beta.36
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/dist/cli.js +5 -1
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +2 -1
- package/dist/common_types.d.ts.map +1 -1
- package/dist/core/browser-service.d.ts +1 -1
- package/dist/core/browser-service.d.ts.map +1 -1
- package/dist/dsl/journey.d.ts.map +1 -1
- package/dist/dsl/journey.js +1 -0
- package/dist/dsl/journey.js.map +1 -1
- package/dist/dsl/monitor.d.ts +2 -0
- package/dist/dsl/monitor.d.ts.map +1 -1
- package/dist/dsl/monitor.js +3 -0
- package/dist/dsl/monitor.js.map +1 -1
- package/dist/formatter/javascript.d.ts +1 -1
- package/dist/formatter/javascript.d.ts.map +1 -1
- package/dist/formatter/javascript.js +1 -1
- package/dist/formatter/javascript.js.map +1 -1
- package/dist/helpers.d.ts +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +3 -3
- package/dist/helpers.js.map +1 -1
- package/dist/plugins/network.js +3 -3
- package/dist/plugins/network.js.map +1 -1
- package/dist/push/index.d.ts.map +1 -1
- package/dist/push/index.js +75 -59
- package/dist/push/index.js.map +1 -1
- package/dist/push/monitor.d.ts +5 -2
- package/dist/push/monitor.d.ts.map +1 -1
- package/dist/push/monitor.js +108 -8
- package/dist/push/monitor.js.map +1 -1
- package/dist/push/plugin.d.ts.map +1 -1
- package/dist/push/plugin.js +6 -2
- package/dist/push/plugin.js.map +1 -1
- package/dist/push/request.d.ts.map +1 -1
- package/dist/push/request.js +5 -5
- package/dist/push/request.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +23 -22
- package/src/cli.ts +5 -1
- package/src/common_types.ts +2 -1
- package/src/dsl/journey.ts +1 -0
- package/src/dsl/monitor.ts +5 -0
- package/src/formatter/javascript.ts +1 -1
- package/src/helpers.ts +1 -1
- package/src/plugins/network.ts +3 -3
- package/src/push/index.ts +82 -65
- package/src/push/monitor.ts +132 -11
- package/src/push/plugin.ts +6 -2
- package/src/push/request.ts +9 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elastic/synthetics",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.36",
|
|
4
4
|
"description": "Elastic synthetic monitoring agent",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -42,39 +42,40 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@cspotcode/source-map-support": "^0.8.1",
|
|
44
44
|
"@esbuild-plugins/node-resolve": "^0.1.4",
|
|
45
|
-
"archiver": "^5.3.
|
|
46
|
-
"commander": "^9.
|
|
45
|
+
"archiver": "^5.3.1",
|
|
46
|
+
"commander": "^9.4.0",
|
|
47
47
|
"deepmerge": "^4.2.2",
|
|
48
48
|
"enquirer": "^2.3.6",
|
|
49
|
-
"esbuild": "^0.14.
|
|
49
|
+
"esbuild": "^0.14.54",
|
|
50
50
|
"expect": "^28.1.3",
|
|
51
51
|
"http-proxy": "^1.18.1",
|
|
52
|
-
"kleur": "^4.1.
|
|
53
|
-
"micromatch": "^4.0.
|
|
54
|
-
"playwright-chromium": "=1.
|
|
55
|
-
"playwright-core": "=1.
|
|
52
|
+
"kleur": "^4.1.5",
|
|
53
|
+
"micromatch": "^4.0.5",
|
|
54
|
+
"playwright-chromium": "=1.26.0",
|
|
55
|
+
"playwright-core": "=1.26.0",
|
|
56
56
|
"sharp": "^0.31.0",
|
|
57
|
-
"snakecase-keys": "^
|
|
58
|
-
"sonic-boom": "^2.
|
|
59
|
-
"ts-node": "^10.9.
|
|
60
|
-
"typescript": "^4.
|
|
61
|
-
"undici": "^5.10.0"
|
|
57
|
+
"snakecase-keys": "^4.0.0",
|
|
58
|
+
"sonic-boom": "^3.2.0",
|
|
59
|
+
"ts-node": "^10.9.1",
|
|
60
|
+
"typescript": "^4.8.3",
|
|
61
|
+
"undici": "^5.10.0",
|
|
62
|
+
"yaml": "^2.1.1"
|
|
62
63
|
},
|
|
63
64
|
"devDependencies": {
|
|
64
|
-
"@types/jest": "^28.1.
|
|
65
|
-
"@types/micromatch": "^4.0.
|
|
66
|
-
"@types/node": "^16.11.
|
|
67
|
-
"@types/sharp": "^0.28.
|
|
68
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
69
|
-
"@typescript-eslint/parser": "^5.
|
|
70
|
-
"eslint": "^8.
|
|
65
|
+
"@types/jest": "^28.1.8",
|
|
66
|
+
"@types/micromatch": "^4.0.2",
|
|
67
|
+
"@types/node": "^16.11.59",
|
|
68
|
+
"@types/sharp": "^0.28.6",
|
|
69
|
+
"@typescript-eslint/eslint-plugin": "^5.38.0",
|
|
70
|
+
"@typescript-eslint/parser": "^5.38.0",
|
|
71
|
+
"eslint": "^8.23.1",
|
|
71
72
|
"husky": "^4.3.6",
|
|
72
73
|
"is-positive": "3.1.0",
|
|
73
74
|
"jest": "^28.1.3",
|
|
74
75
|
"lint-staged": "^10.5.3",
|
|
75
|
-
"prettier": "^2.
|
|
76
|
+
"prettier": "^2.7.1",
|
|
76
77
|
"rimraf": "^3.0.2",
|
|
77
|
-
"ts-jest": "^28.0.
|
|
78
|
+
"ts-jest": "^28.0.8",
|
|
78
79
|
"unzipper": "^0.10.11"
|
|
79
80
|
},
|
|
80
81
|
"engines": {
|
package/src/cli.ts
CHANGED
|
@@ -54,6 +54,7 @@ import { resolve } from 'path';
|
|
|
54
54
|
import { Generator } from './generator';
|
|
55
55
|
import { error } from './helpers';
|
|
56
56
|
import { LocationsMap } from './locations/public-locations';
|
|
57
|
+
import { createLightweightMonitors } from './push/monitor';
|
|
57
58
|
|
|
58
59
|
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
|
|
59
60
|
const { name, version } = require('../package.json');
|
|
@@ -184,6 +185,7 @@ program
|
|
|
184
185
|
'--space <space>',
|
|
185
186
|
'the target Kibana spaces for the pushed monitors — spaces help you organise pushed monitors.'
|
|
186
187
|
)
|
|
188
|
+
.option('-y, --yes', 'skip all questions and run non-interactively')
|
|
187
189
|
.addOption(pattern)
|
|
188
190
|
.addOption(tags)
|
|
189
191
|
.addOption(match)
|
|
@@ -191,7 +193,8 @@ program
|
|
|
191
193
|
.addOption(playwrightOpts)
|
|
192
194
|
.action(async (cmdOpts: PushOptions) => {
|
|
193
195
|
try {
|
|
194
|
-
|
|
196
|
+
const workDir = cwd();
|
|
197
|
+
await loadTestFiles({ inline: false, ...program.opts() }, [workDir]);
|
|
195
198
|
const settings = await loadSettings();
|
|
196
199
|
const options = normalizeOptions({
|
|
197
200
|
...program.opts(),
|
|
@@ -201,6 +204,7 @@ program
|
|
|
201
204
|
validateSettings(options);
|
|
202
205
|
await catchIncorrectSettings(settings, options);
|
|
203
206
|
const monitors = runner.buildMonitors(options);
|
|
207
|
+
monitors.push(...(await createLightweightMonitors(workDir, options)));
|
|
204
208
|
await push(monitors, options);
|
|
205
209
|
} catch (e) {
|
|
206
210
|
e && console.error(e);
|
package/src/common_types.ts
CHANGED
|
@@ -241,11 +241,12 @@ export type RunOptions = BaseArgs & {
|
|
|
241
241
|
reporter?: BuiltInReporterName | ReporterInstance;
|
|
242
242
|
};
|
|
243
243
|
|
|
244
|
-
export type PushOptions = ProjectSettings & {
|
|
244
|
+
export type PushOptions = Partial<ProjectSettings> & {
|
|
245
245
|
auth: string;
|
|
246
246
|
schedule?: MonitorConfig['schedule'];
|
|
247
247
|
locations?: MonitorConfig['locations'];
|
|
248
248
|
privateLocations?: MonitorConfig['privateLocations'];
|
|
249
|
+
yes?: boolean;
|
|
249
250
|
};
|
|
250
251
|
|
|
251
252
|
export type ProjectSettings = {
|
package/src/dsl/journey.ts
CHANGED
package/src/dsl/monitor.ts
CHANGED
|
@@ -41,6 +41,7 @@ export const SyntheticsLocations = Object.keys(
|
|
|
41
41
|
export type MonitorConfig = {
|
|
42
42
|
id?: string;
|
|
43
43
|
name?: string;
|
|
44
|
+
type?: string;
|
|
44
45
|
tags?: string[];
|
|
45
46
|
schedule?: number;
|
|
46
47
|
enabled?: boolean;
|
|
@@ -73,6 +74,10 @@ export class Monitor {
|
|
|
73
74
|
});
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
get type() {
|
|
78
|
+
return this.config.type;
|
|
79
|
+
}
|
|
80
|
+
|
|
76
81
|
setSource(source: Location) {
|
|
77
82
|
this.source = source;
|
|
78
83
|
}
|
package/src/helpers.ts
CHANGED
|
@@ -359,7 +359,7 @@ export function done(message: string) {
|
|
|
359
359
|
write(bold(green(`${symbols['succeeded']} ${message}`)));
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
export function
|
|
362
|
+
export function warn(message: string) {
|
|
363
363
|
write(bold(yellow(`${symbols['warning']} ${message}`)));
|
|
364
364
|
}
|
|
365
365
|
|
package/src/plugins/network.ts
CHANGED
|
@@ -283,12 +283,12 @@ export class NetworkManager {
|
|
|
283
283
|
networkEntry.request.body = {
|
|
284
284
|
bytes: sizes.requestBodySize,
|
|
285
285
|
};
|
|
286
|
-
|
|
287
|
-
|
|
286
|
+
const transferSize = sizes.responseHeadersSize + sizes.responseBodySize;
|
|
287
|
+
networkEntry.transferSize = transferSize;
|
|
288
|
+
networkEntry.response.bytes = transferSize;
|
|
288
289
|
networkEntry.response.body = {
|
|
289
290
|
bytes: sizes.responseBodySize,
|
|
290
291
|
};
|
|
291
|
-
networkEntry.transferSize = sizes.responseBodySize;
|
|
292
292
|
})
|
|
293
293
|
);
|
|
294
294
|
}
|
package/src/push/index.ts
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import { readFile, writeFile } from 'fs/promises';
|
|
27
27
|
import { prompt } from 'enquirer';
|
|
28
|
-
import { bold
|
|
28
|
+
import { bold } from 'kleur/colors';
|
|
29
29
|
import {
|
|
30
30
|
ok,
|
|
31
31
|
formatAPIError,
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
apiProgress,
|
|
41
41
|
write,
|
|
42
42
|
error,
|
|
43
|
-
|
|
43
|
+
warn,
|
|
44
44
|
indent,
|
|
45
45
|
safeNDJSONParse,
|
|
46
46
|
done,
|
|
@@ -49,24 +49,42 @@ import type { PushOptions, ProjectSettings } from '../common_types';
|
|
|
49
49
|
import { findSyntheticsConfig, readConfig } from '../config';
|
|
50
50
|
|
|
51
51
|
export async function push(monitors: Monitor[], options: PushOptions) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
52
|
+
let schemas: MonitorSchema[] = [];
|
|
53
|
+
if (monitors.length > 0) {
|
|
54
|
+
const duplicates = trackDuplicates(monitors);
|
|
55
|
+
if (duplicates.size > 0) {
|
|
56
|
+
throw error(formatDuplicateError(duplicates));
|
|
57
|
+
}
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
progress(`preparing all monitors`);
|
|
60
|
+
schemas = await buildMonitorSchema(monitors);
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
progress(`creating all monitors`);
|
|
63
|
+
for (const schema of schemas) {
|
|
64
|
+
await pushMonitors({ schemas: [schema], keepStale: true, options });
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
write('');
|
|
68
|
+
const { deleteAll } = await prompt<{ deleteAll: boolean }>({
|
|
69
|
+
type: 'confirm',
|
|
70
|
+
skip() {
|
|
71
|
+
if (options.yes) {
|
|
72
|
+
this.initial = process.env.TEST_OVERRIDE ?? true;
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
},
|
|
77
|
+
name: 'deleteAll',
|
|
78
|
+
message: `Pushing without any monitors will delete all monitors associated with the project.\n Do you want to continue?`,
|
|
79
|
+
initial: false,
|
|
80
|
+
});
|
|
81
|
+
if (!deleteAll) {
|
|
82
|
+
throw warn('Push command Aborted');
|
|
83
|
+
}
|
|
66
84
|
}
|
|
67
|
-
|
|
68
85
|
progress(`deleting all stale monitors`);
|
|
69
86
|
await pushMonitors({ schemas, keepStale: false, options });
|
|
87
|
+
|
|
70
88
|
done('Pushed');
|
|
71
89
|
}
|
|
72
90
|
|
|
@@ -79,43 +97,39 @@ export async function pushMonitors({
|
|
|
79
97
|
keepStale: boolean;
|
|
80
98
|
options: PushOptions;
|
|
81
99
|
}) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
for
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
write(yellow(formatStaleMonitors(failedStaleMonitors)));
|
|
114
|
-
}
|
|
100
|
+
const { body, statusCode } = await createMonitors(
|
|
101
|
+
schemas,
|
|
102
|
+
options,
|
|
103
|
+
keepStale
|
|
104
|
+
);
|
|
105
|
+
if (statusCode === 404) {
|
|
106
|
+
throw formatNotFoundError(await body.text());
|
|
107
|
+
}
|
|
108
|
+
if (!ok(statusCode)) {
|
|
109
|
+
const { error, message } = await body.json();
|
|
110
|
+
throw formatAPIError(statusCode, error, message);
|
|
111
|
+
}
|
|
112
|
+
body.setEncoding('utf-8');
|
|
113
|
+
for await (const data of body) {
|
|
114
|
+
// Its kind of hacky for now where Kibana streams the response by
|
|
115
|
+
// writing the data as NDJSON events (data can be interleaved), we
|
|
116
|
+
// distinguish the final data by checking if the event was a progress vs complete event
|
|
117
|
+
const chunks = safeNDJSONParse(data);
|
|
118
|
+
for (const chunk of chunks) {
|
|
119
|
+
if (typeof chunk === 'string') {
|
|
120
|
+
// TODO: add progress back for all states once we get the fix
|
|
121
|
+
// on kibana side
|
|
122
|
+
keepStale && apiProgress(chunk);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const { failedMonitors, failedStaleMonitors } = chunk;
|
|
126
|
+
if (failedMonitors && failedMonitors.length > 0) {
|
|
127
|
+
throw formatFailedMonitors(failedMonitors);
|
|
128
|
+
}
|
|
129
|
+
if (failedStaleMonitors.length > 0) {
|
|
130
|
+
throw formatStaleMonitors(failedStaleMonitors);
|
|
115
131
|
}
|
|
116
132
|
}
|
|
117
|
-
} catch (e) {
|
|
118
|
-
error(e);
|
|
119
133
|
}
|
|
120
134
|
}
|
|
121
135
|
|
|
@@ -149,7 +163,7 @@ const INSTALLATION_HELP = `Run 'npx @elastic/synthetics init' to create project
|
|
|
149
163
|
|
|
150
164
|
export async function loadSettings() {
|
|
151
165
|
try {
|
|
152
|
-
const config = await readConfig('
|
|
166
|
+
const config = await readConfig(process.env['NODE_ENV'] || 'development');
|
|
153
167
|
// Missing config file, fake throw to capture as missing file
|
|
154
168
|
if (Object.keys(config).length === 0) {
|
|
155
169
|
throw '';
|
|
@@ -193,7 +207,7 @@ async function overrideSettings(oldValue: string, newValue: string) {
|
|
|
193
207
|
const cwd = process.cwd();
|
|
194
208
|
const configPath = await findSyntheticsConfig(cwd, cwd);
|
|
195
209
|
if (!configPath) {
|
|
196
|
-
throw
|
|
210
|
+
throw warn(`Unable to find synthetics config file: ${configPath}`);
|
|
197
211
|
}
|
|
198
212
|
const config = await readFile(configPath, 'utf-8');
|
|
199
213
|
const updatedConfig = config.replace(
|
|
@@ -209,20 +223,23 @@ export async function catchIncorrectSettings(
|
|
|
209
223
|
) {
|
|
210
224
|
let override = !settings.id;
|
|
211
225
|
if (settings.id && settings.id !== options.id) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
226
|
+
// Add an extra line to make it easier to read the prompt
|
|
227
|
+
write('');
|
|
228
|
+
({ override } = await prompt<{ override: boolean }>({
|
|
229
|
+
type: 'confirm',
|
|
230
|
+
name: 'override',
|
|
231
|
+
skip() {
|
|
232
|
+
if (options.yes) {
|
|
233
|
+
this.initial = process.env.TEST_OVERRIDE ?? true;
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
},
|
|
238
|
+
message: `Monitors were pushed under the '${settings.id}' project. Are you sure you want to push them under the new '${options.id}' (note that this will duplicate the monitors, the old ones being orphaned)`,
|
|
239
|
+
initial: false,
|
|
240
|
+
}));
|
|
224
241
|
if (!override) {
|
|
225
|
-
throw
|
|
242
|
+
throw warn('Push command Aborted');
|
|
226
243
|
}
|
|
227
244
|
}
|
|
228
245
|
if (override) {
|
package/src/push/monitor.ts
CHANGED
|
@@ -23,19 +23,27 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { mkdir, rm } from 'fs/promises';
|
|
26
|
+
import { mkdir, rm, readFile } from 'fs/promises';
|
|
27
27
|
import { join } from 'path';
|
|
28
|
+
import { LineCounter, parseDocument, YAMLSeq, YAMLMap } from 'yaml';
|
|
29
|
+
import { bold, red } from 'kleur/colors';
|
|
28
30
|
import { Bundler } from './bundler';
|
|
29
31
|
import { sendRequest } from './request';
|
|
30
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
removeTrailingSlash,
|
|
34
|
+
SYNTHETICS_PATH,
|
|
35
|
+
totalist,
|
|
36
|
+
indent,
|
|
37
|
+
warn,
|
|
38
|
+
} from '../helpers';
|
|
31
39
|
import { LocationsMap } from '../locations/public-locations';
|
|
32
40
|
import { Monitor, MonitorConfig } from '../dsl/monitor';
|
|
33
41
|
import { PushOptions } from '../common_types';
|
|
34
42
|
|
|
35
43
|
export type MonitorSchema = Omit<MonitorConfig, 'locations'> & {
|
|
36
|
-
content: string;
|
|
37
44
|
locations: string[];
|
|
38
|
-
|
|
45
|
+
content?: string;
|
|
46
|
+
filter?: Monitor['filter'];
|
|
39
47
|
};
|
|
40
48
|
|
|
41
49
|
export type APISchema = {
|
|
@@ -60,21 +68,134 @@ export async function buildMonitorSchema(monitors: Monitor[]) {
|
|
|
60
68
|
const schemas: MonitorSchema[] = [];
|
|
61
69
|
|
|
62
70
|
for (const monitor of monitors) {
|
|
63
|
-
const { source, config, filter } = monitor;
|
|
64
|
-
const
|
|
65
|
-
const content = await bundler.build(source.file, outPath);
|
|
66
|
-
schemas.push({
|
|
71
|
+
const { source, config, filter, type } = monitor;
|
|
72
|
+
const schema = {
|
|
67
73
|
...config,
|
|
68
|
-
content,
|
|
69
74
|
locations: translateLocation(config.locations),
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
};
|
|
76
|
+
if (type === 'browser') {
|
|
77
|
+
const outPath = join(bundlePath, config.name + '.zip');
|
|
78
|
+
const content = await bundler.build(source.file, outPath);
|
|
79
|
+
Object.assign(schema, { content, filter });
|
|
80
|
+
}
|
|
81
|
+
schemas.push(schema);
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
await rm(bundlePath, { recursive: true });
|
|
75
85
|
return schemas;
|
|
76
86
|
}
|
|
77
87
|
|
|
88
|
+
export async function createLightweightMonitors(
|
|
89
|
+
workDir: string,
|
|
90
|
+
options: PushOptions
|
|
91
|
+
) {
|
|
92
|
+
const lwFiles = new Set<string>();
|
|
93
|
+
await totalist(workDir, (rel, abs) => {
|
|
94
|
+
if (/.(yml|yaml)$/.test(rel)) {
|
|
95
|
+
lwFiles.add(abs);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
// Warn users about schedule that are less than 60 seconds
|
|
99
|
+
if (lwFiles.size > 0) {
|
|
100
|
+
warn(
|
|
101
|
+
'lightweight monitors schedule < 1 minute resolution are not supported, will get reset to their nearest minute interval.'
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const monitors: Monitor[] = [];
|
|
106
|
+
for (const file of lwFiles.values()) {
|
|
107
|
+
const content = await readFile(file, 'utf-8');
|
|
108
|
+
const lineCounter = new LineCounter();
|
|
109
|
+
const parsedDoc = parseDocument(content, {
|
|
110
|
+
lineCounter,
|
|
111
|
+
keepSourceTokens: true,
|
|
112
|
+
});
|
|
113
|
+
// Skip other yml files that are not relevant
|
|
114
|
+
const monitorSeq = parsedDoc.get('heartbeat.monitors') as YAMLSeq<YAMLMap>;
|
|
115
|
+
if (!monitorSeq) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (const monNode of monitorSeq.items) {
|
|
120
|
+
// Skip browser monitors and disabled monitors from pushing
|
|
121
|
+
if (
|
|
122
|
+
monNode.get('type') === 'browser' ||
|
|
123
|
+
monNode.get('enabled') === false
|
|
124
|
+
) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const config = monNode.toJSON();
|
|
128
|
+
const { line, col } = lineCounter.linePos(monNode.srcToken.offset);
|
|
129
|
+
try {
|
|
130
|
+
const mon = buildMonitorFromYaml(config, options);
|
|
131
|
+
mon.setSource({ file, line, column: col });
|
|
132
|
+
monitors.push(mon);
|
|
133
|
+
} catch (e) {
|
|
134
|
+
let outer = bold(`Aborted: ${e}\n`);
|
|
135
|
+
outer += indent(
|
|
136
|
+
`* ${config.id || config.name} - ${file}:${line}:${col}\n`
|
|
137
|
+
);
|
|
138
|
+
throw red(outer);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return monitors;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const REQUIRED_MONITOR_FIELDS = ['id', 'name'];
|
|
146
|
+
export function buildMonitorFromYaml(
|
|
147
|
+
config: MonitorConfig,
|
|
148
|
+
options: PushOptions
|
|
149
|
+
) {
|
|
150
|
+
// Validate required fields
|
|
151
|
+
for (const field of REQUIRED_MONITOR_FIELDS) {
|
|
152
|
+
if (!config[field]) {
|
|
153
|
+
throw `Monitor ${field} is required`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const schedule = config.schedule && parseSchedule(String(config.schedule));
|
|
157
|
+
const privateLocations =
|
|
158
|
+
config['private_locations'] || options.privateLocations;
|
|
159
|
+
delete config['private_locations'];
|
|
160
|
+
|
|
161
|
+
return new Monitor({
|
|
162
|
+
locations: options.locations,
|
|
163
|
+
...config,
|
|
164
|
+
privateLocations,
|
|
165
|
+
schedule: schedule || options.schedule,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function parseSchedule(schedule: string) {
|
|
170
|
+
const EVERY_SYNTAX = '@every';
|
|
171
|
+
if (!(schedule + '').startsWith(EVERY_SYNTAX)) {
|
|
172
|
+
throw `Monitor schedule format(${schedule}) not supported: use '@every' syntax instead`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const duration = schedule.substring(EVERY_SYNTAX.length + 1);
|
|
176
|
+
// split between non-digit (\D) and a digit (\d)
|
|
177
|
+
const durations = duration.split(/(?<=\D)(?=\d)/g);
|
|
178
|
+
let minutes = 0;
|
|
179
|
+
for (const dur of durations) {
|
|
180
|
+
// split between a digit and non-digit
|
|
181
|
+
const [value, format] = dur.split(/(?<=\d)(?=\D)/g);
|
|
182
|
+
// Calculate based on the duration symbol
|
|
183
|
+
const scheduleValue = parseInt(value, 10);
|
|
184
|
+
switch (format) {
|
|
185
|
+
case 's':
|
|
186
|
+
minutes += Math.ceil(scheduleValue / 60);
|
|
187
|
+
break;
|
|
188
|
+
case 'm':
|
|
189
|
+
minutes += scheduleValue;
|
|
190
|
+
break;
|
|
191
|
+
case 'h':
|
|
192
|
+
minutes += scheduleValue * 60;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return minutes;
|
|
197
|
+
}
|
|
198
|
+
|
|
78
199
|
export async function createMonitors(
|
|
79
200
|
monitors: MonitorSchema[],
|
|
80
201
|
options: PushOptions,
|
package/src/push/plugin.ts
CHANGED
|
@@ -27,8 +27,12 @@ import { isAbsolute, dirname, extname, join } from 'path';
|
|
|
27
27
|
import fs from 'fs/promises';
|
|
28
28
|
import * as esbuild from 'esbuild';
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
const
|
|
30
|
+
// ROOT directory of the Package - /
|
|
31
|
+
const ROOT_DIR = join(__dirname, '..', '..');
|
|
32
|
+
// Source of the package - /src, /dist, etc.
|
|
33
|
+
const SOURCE_DIR = join(__dirname, '..');
|
|
34
|
+
// Node modules directory of the package - /node_modules
|
|
35
|
+
const SOURCE_NODE_MODULES = join(ROOT_DIR, 'node_modules');
|
|
32
36
|
|
|
33
37
|
export function commonOptions(): esbuild.BuildOptions {
|
|
34
38
|
return {
|
package/src/push/request.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { bold } from 'kleur/colors';
|
|
26
|
+
import { bold, red, yellow } from 'kleur/colors';
|
|
27
27
|
import { Dispatcher, request } from 'undici';
|
|
28
28
|
import { indent, symbols } from '../helpers';
|
|
29
29
|
|
|
@@ -47,7 +47,7 @@ export async function sendRequest(options: APIRequestOptions) {
|
|
|
47
47
|
'user-agent': `Elastic/Synthetics ${version}`,
|
|
48
48
|
'kbn-xsrf': 'true',
|
|
49
49
|
},
|
|
50
|
-
headersTimeout: 60 * 1000
|
|
50
|
+
headersTimeout: 60 * 1000,
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -62,8 +62,10 @@ export type APIMonitorError = {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
export function formatNotFoundError(message: string) {
|
|
65
|
-
return
|
|
66
|
-
|
|
65
|
+
return red(
|
|
66
|
+
bold(
|
|
67
|
+
`${symbols['failed']} Please check your kibana url and try again - 404:${message}`
|
|
68
|
+
)
|
|
67
69
|
);
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -78,7 +80,7 @@ export function formatAPIError(
|
|
|
78
80
|
);
|
|
79
81
|
inner += indent(message, ' ');
|
|
80
82
|
outer += indent(inner);
|
|
81
|
-
return outer;
|
|
83
|
+
return red(outer);
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
function formatMonitorError(errors: APIMonitorError[]) {
|
|
@@ -95,10 +97,10 @@ function formatMonitorError(errors: APIMonitorError[]) {
|
|
|
95
97
|
|
|
96
98
|
export function formatFailedMonitors(errors: APIMonitorError[]) {
|
|
97
99
|
const heading = bold(`${symbols['failed']} Error\n`);
|
|
98
|
-
return heading + formatMonitorError(errors);
|
|
100
|
+
return red(heading + formatMonitorError(errors));
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
export function formatStaleMonitors(errors: APIMonitorError[]) {
|
|
102
104
|
const heading = bold(`${symbols['warning']} Warnings\n`);
|
|
103
|
-
return heading + formatMonitorError(errors);
|
|
105
|
+
return yellow(heading + formatMonitorError(errors));
|
|
104
106
|
}
|