@elastic/synthetics 1.0.0-beta.33 → 1.0.0-beta.35
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 +7 -4
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +8 -4
- package/dist/common_types.d.ts.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/generator/index.d.ts +1 -6
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/index.js +5 -14
- package/dist/generator/index.js.map +1 -1
- package/dist/generator/utils.d.ts.map +1 -1
- package/dist/generator/utils.js +3 -0
- package/dist/generator/utils.js.map +1 -1
- package/dist/push/bundler.d.ts +1 -0
- package/dist/push/bundler.d.ts.map +1 -1
- package/dist/push/bundler.js +16 -1
- package/dist/push/bundler.js.map +1 -1
- package/dist/push/index.d.ts +1 -2
- package/dist/push/index.d.ts.map +1 -1
- package/dist/push/index.js +103 -76
- package/dist/push/index.js.map +1 -1
- package/dist/push/monitor.js +1 -1
- package/dist/push/monitor.js.map +1 -1
- package/dist/push/plugin.d.ts.map +1 -1
- package/dist/push/plugin.js +30 -7
- 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 +5 -3
- package/src/cli.ts +12 -7
- package/src/common_types.ts +9 -4
- package/src/config.ts +1 -1
- package/src/generator/index.ts +5 -20
- package/src/generator/utils.ts +3 -0
- package/src/push/bundler.ts +21 -2
- package/src/push/index.ts +111 -89
- package/src/push/monitor.ts +1 -1
- package/src/push/plugin.ts +38 -9
- package/src/push/request.ts +9 -7
- package/templates/synthetics.config.ts +8 -0
package/src/push/index.ts
CHANGED
|
@@ -23,11 +23,9 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { join } from 'path';
|
|
27
|
-
import { existsSync } from 'fs';
|
|
28
26
|
import { readFile, writeFile } from 'fs/promises';
|
|
29
27
|
import { prompt } from 'enquirer';
|
|
30
|
-
import { bold
|
|
28
|
+
import { bold } from 'kleur/colors';
|
|
31
29
|
import {
|
|
32
30
|
ok,
|
|
33
31
|
formatAPIError,
|
|
@@ -36,40 +34,57 @@ import {
|
|
|
36
34
|
formatStaleMonitors,
|
|
37
35
|
} from './request';
|
|
38
36
|
import { buildMonitorSchema, createMonitors, MonitorSchema } from './monitor';
|
|
39
|
-
import { ProjectSettings } from '../generator';
|
|
40
37
|
import { Monitor } from '../dsl/monitor';
|
|
41
38
|
import {
|
|
42
39
|
progress,
|
|
43
40
|
apiProgress,
|
|
44
41
|
write,
|
|
45
42
|
error,
|
|
46
|
-
SYNTHETICS_PATH,
|
|
47
43
|
aborted,
|
|
48
44
|
indent,
|
|
49
45
|
safeNDJSONParse,
|
|
50
46
|
done,
|
|
51
47
|
} from '../helpers';
|
|
52
|
-
import type { PushOptions } from '../common_types';
|
|
48
|
+
import type { PushOptions, ProjectSettings } from '../common_types';
|
|
49
|
+
import { findSyntheticsConfig, readConfig } from '../config';
|
|
53
50
|
|
|
54
51
|
export async function push(monitors: Monitor[], options: PushOptions) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
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
|
+
}
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
progress(`preparing all monitors`);
|
|
60
|
+
schemas = await buildMonitorSchema(monitors);
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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 aborted('Push command Aborted');
|
|
83
|
+
}
|
|
69
84
|
}
|
|
70
|
-
|
|
71
85
|
progress(`deleting all stale monitors`);
|
|
72
86
|
await pushMonitors({ schemas, keepStale: false, options });
|
|
87
|
+
|
|
73
88
|
done('Pushed');
|
|
74
89
|
}
|
|
75
90
|
|
|
@@ -82,43 +97,39 @@ export async function pushMonitors({
|
|
|
82
97
|
keepStale: boolean;
|
|
83
98
|
options: PushOptions;
|
|
84
99
|
}) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
for
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
write(yellow(formatStaleMonitors(failedStaleMonitors)));
|
|
117
|
-
}
|
|
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);
|
|
118
131
|
}
|
|
119
132
|
}
|
|
120
|
-
} catch (e) {
|
|
121
|
-
error(e);
|
|
122
133
|
}
|
|
123
134
|
}
|
|
124
135
|
|
|
@@ -148,34 +159,39 @@ export function formatDuplicateError(monitors: Set<Monitor>) {
|
|
|
148
159
|
return outer;
|
|
149
160
|
}
|
|
150
161
|
|
|
151
|
-
const PROJECT_SETTINGS_PATH = join(SYNTHETICS_PATH, 'project.json');
|
|
152
162
|
const INSTALLATION_HELP = `Run 'npx @elastic/synthetics init' to create project with default settings.`;
|
|
153
163
|
|
|
154
164
|
export async function loadSettings() {
|
|
155
|
-
|
|
156
|
-
|
|
165
|
+
try {
|
|
166
|
+
const config = await readConfig(process.env['NODE_ENV'] || 'development');
|
|
167
|
+
// Missing config file, fake throw to capture as missing file
|
|
168
|
+
if (Object.keys(config).length === 0) {
|
|
169
|
+
throw '';
|
|
170
|
+
}
|
|
171
|
+
return config.project || ({} as ProjectSettings);
|
|
172
|
+
} catch (e) {
|
|
173
|
+
throw error(`Aborted (missing synthetics config file), Project not set up corrrectly.
|
|
157
174
|
|
|
158
175
|
${INSTALLATION_HELP}`);
|
|
159
176
|
}
|
|
160
|
-
|
|
161
|
-
const contents = await readFile(PROJECT_SETTINGS_PATH, 'utf-8');
|
|
162
|
-
return JSON.parse(contents) as ProjectSettings;
|
|
163
177
|
}
|
|
164
178
|
|
|
165
179
|
export function validateSettings(opts: PushOptions) {
|
|
166
180
|
const INVALID = 'Aborted. Invalid synthetics project settings.';
|
|
167
181
|
|
|
168
182
|
let reason = '';
|
|
169
|
-
if (!opts.
|
|
170
|
-
reason =
|
|
183
|
+
if (!opts.id) {
|
|
184
|
+
reason = `Set project id via
|
|
185
|
+
- CLI '--id <id>'
|
|
186
|
+
- Config file 'project.id' field`;
|
|
171
187
|
} else if (!opts.locations && !opts.privateLocations) {
|
|
172
188
|
reason = `Set default location for all monitors via
|
|
173
|
-
- CLI
|
|
174
|
-
-
|
|
189
|
+
- CLI '--locations <values...> or --privateLocations <values...>'
|
|
190
|
+
- Config file 'monitors.locations' | 'monitors.privateLocations' field`;
|
|
175
191
|
} else if (!opts.schedule) {
|
|
176
192
|
reason = `Set default schedule in minutes for all monitors via
|
|
177
|
-
- CLI
|
|
178
|
-
-
|
|
193
|
+
- CLI '--schedule <mins>'
|
|
194
|
+
- Config file 'monitors.schedule' field`;
|
|
179
195
|
}
|
|
180
196
|
|
|
181
197
|
if (!reason) return;
|
|
@@ -187,40 +203,46 @@ ${reason}
|
|
|
187
203
|
${INSTALLATION_HELP}`);
|
|
188
204
|
}
|
|
189
205
|
|
|
190
|
-
async function overrideSettings(
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
206
|
+
async function overrideSettings(oldValue: string, newValue: string) {
|
|
207
|
+
const cwd = process.cwd();
|
|
208
|
+
const configPath = await findSyntheticsConfig(cwd, cwd);
|
|
209
|
+
if (!configPath) {
|
|
210
|
+
throw aborted(`Unable to find synthetics config file: ${configPath}`);
|
|
211
|
+
}
|
|
212
|
+
const config = await readFile(configPath, 'utf-8');
|
|
213
|
+
const updatedConfig = config.replace(
|
|
214
|
+
`id: '${oldValue}'`,
|
|
215
|
+
`id: '${newValue}'`
|
|
198
216
|
);
|
|
217
|
+
await writeFile(configPath, updatedConfig, 'utf-8');
|
|
199
218
|
}
|
|
200
219
|
|
|
201
220
|
export async function catchIncorrectSettings(
|
|
202
221
|
settings: ProjectSettings,
|
|
203
222
|
options: PushOptions
|
|
204
223
|
) {
|
|
205
|
-
let override = !settings.
|
|
206
|
-
if (settings.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
224
|
+
let override = !settings.id;
|
|
225
|
+
if (settings.id && settings.id !== options.id) {
|
|
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
|
+
}));
|
|
219
241
|
if (!override) {
|
|
220
242
|
throw aborted('Push command Aborted');
|
|
221
243
|
}
|
|
222
244
|
}
|
|
223
245
|
if (override) {
|
|
224
|
-
await overrideSettings(options.
|
|
246
|
+
await overrideSettings(settings.id, options.id);
|
|
225
247
|
}
|
|
226
248
|
}
|
package/src/push/monitor.ts
CHANGED
package/src/push/plugin.ts
CHANGED
|
@@ -23,14 +23,17 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import
|
|
26
|
+
import { isAbsolute, dirname, extname, join } from 'path';
|
|
27
27
|
import fs from 'fs/promises';
|
|
28
28
|
import * as esbuild from 'esbuild';
|
|
29
29
|
|
|
30
|
+
const SOURCE_DIR = join(__dirname, '..', '..');
|
|
31
|
+
const SOURCE_NODE_MODULES = join(SOURCE_DIR, 'node_modules');
|
|
32
|
+
|
|
30
33
|
export function commonOptions(): esbuild.BuildOptions {
|
|
31
34
|
return {
|
|
32
35
|
bundle: true,
|
|
33
|
-
external: ['
|
|
36
|
+
external: ['@elastic/synthetics'],
|
|
34
37
|
minify: false,
|
|
35
38
|
platform: 'node',
|
|
36
39
|
logLevel: 'silent',
|
|
@@ -55,27 +58,49 @@ export function MultiAssetPlugin(callback: PluginCallback): esbuild.Plugin {
|
|
|
55
58
|
// Note that we use `isAbsolute` to handle UNC/windows style paths like C:\path\to\thing
|
|
56
59
|
// This is not necessary for relative directories since `.\file` is not supported as an import
|
|
57
60
|
// nor is `~/path/to/file`.
|
|
58
|
-
if (
|
|
61
|
+
if (isAbsolute(str) || str.startsWith('./') || str.startsWith('../')) {
|
|
59
62
|
return true;
|
|
60
63
|
}
|
|
61
64
|
return false;
|
|
62
65
|
};
|
|
63
66
|
|
|
67
|
+
// If we're importing the @elastic/synthetics package
|
|
68
|
+
// directly from source instead of using the fully
|
|
69
|
+
// qualified name, we must skip it too. That's just
|
|
70
|
+
// so it doesn't get bundled on tests or when we locally
|
|
71
|
+
// refer to the package itself.
|
|
72
|
+
const isLocalSynthetics = (entryPath: string) => {
|
|
73
|
+
return entryPath.startsWith(SOURCE_DIR);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// When importing the local synthetics module directly
|
|
77
|
+
// it may import its own local dependencies, so we must
|
|
78
|
+
// make sure those will be resolved using Node's resolution
|
|
79
|
+
// algorithm, as they're still "node_modules" that we must bundle
|
|
80
|
+
const isLocalSyntheticsModule = (str: string) => {
|
|
81
|
+
return str.startsWith(SOURCE_NODE_MODULES);
|
|
82
|
+
};
|
|
83
|
+
|
|
64
84
|
return {
|
|
65
85
|
name: 'esbuild-multiasset-plugin',
|
|
66
86
|
setup(build) {
|
|
67
87
|
build.onResolve({ filter: /.*?/ }, async args => {
|
|
68
88
|
// External and other packages need be marked external to
|
|
69
89
|
// be removed from the bundle
|
|
70
|
-
if (
|
|
71
|
-
build.initialOptions.external?.includes(args.path) ||
|
|
72
|
-
!isBare(args.path)
|
|
73
|
-
) {
|
|
90
|
+
if (build.initialOptions.external?.includes(args.path)) {
|
|
74
91
|
return {
|
|
75
92
|
external: true,
|
|
76
93
|
};
|
|
77
94
|
}
|
|
78
95
|
|
|
96
|
+
if (
|
|
97
|
+
!isBare(args.path) ||
|
|
98
|
+
args.importer.includes('/node_modules/') ||
|
|
99
|
+
isLocalSyntheticsModule(args.importer)
|
|
100
|
+
) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
79
104
|
if (args.kind === 'entry-point') {
|
|
80
105
|
return {
|
|
81
106
|
path: args.path,
|
|
@@ -86,8 +111,12 @@ export function MultiAssetPlugin(callback: PluginCallback): esbuild.Plugin {
|
|
|
86
111
|
// If the modules are resolved locally, then
|
|
87
112
|
// use the imported path to get full path
|
|
88
113
|
const entryPath =
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
join(dirname(args.importer), args.path) + extname(args.importer);
|
|
115
|
+
|
|
116
|
+
if (isLocalSynthetics(entryPath)) {
|
|
117
|
+
return { external: true };
|
|
118
|
+
}
|
|
119
|
+
|
|
91
120
|
// Spin off another build to copy over the imported modules without bundling
|
|
92
121
|
const result = await esbuild.build({
|
|
93
122
|
...commonOptions(),
|
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
|
}
|
|
@@ -16,6 +16,14 @@ export default env => {
|
|
|
16
16
|
locations: ['{{locations}}'],
|
|
17
17
|
privateLocations: ['{{privateLocations}}'],
|
|
18
18
|
},
|
|
19
|
+
/**
|
|
20
|
+
* Project monitors settings
|
|
21
|
+
*/
|
|
22
|
+
project: {
|
|
23
|
+
id: '{{id}}',
|
|
24
|
+
url: '{{url}}',
|
|
25
|
+
space: '{{space}}',
|
|
26
|
+
},
|
|
19
27
|
};
|
|
20
28
|
if (env !== 'development') {
|
|
21
29
|
/**
|