@elastic/synthetics
Version:
Elastic synthetic monitoring agent
237 lines • 11.8 kB
JavaScript
#!/usr/bin/env node
"use strict";
/**
* MIT License
*
* Copyright (c) 2020-present, Elastic NV
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const process_1 = require("process");
const colors_1 = require("kleur/colors");
const path_1 = require("path");
const reporters_1 = require("./reporters");
const options_1 = require("./options");
const loader_1 = require("./loader");
const _1 = require("./");
const globals_1 = require("./core/globals");
const monitor_1 = require("./dsl/monitor");
const push_1 = require("./push");
const locations_1 = require("./locations");
const generator_1 = require("./generator");
const helpers_1 = require("./helpers");
const public_locations_1 = require("./locations/public-locations");
const monitor_2 = require("./push/monitor");
const kibana_api_1 = require("./push/kibana_api");
const transform_1 = require("./core/transform");
const mfa_1 = require("./core/mfa");
const helpers_2 = require("./helpers");
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
const { name, version } = require('../package.json');
const proxySettings = {};
const { params, pattern, playwrightOpts, auth, authMandatory, configOpt, tags, match, fields, maintenanceWindows, } = (0, options_1.getCommonCommandOpts)();
commander_1.program
.name(`npx ${name}`)
.usage('[options] [dir] [files] file')
.addOption(configOpt)
.addOption(pattern)
.addOption(tags)
.addOption(match)
.addOption(params)
.addOption(new commander_1.Option('--reporter <value>', `output reporter format`).choices(Object.keys(reporters_1.reporters)))
.option('--inline', 'read journeys from stdin instead of reading from files')
.option('-r, --require <modules...>', 'module(s) to preload')
.option('--sandbox', 'enable chromium sand-boxing')
.option('--rich-events', 'preset flag used when running monitors directly via Heartbeat')
.option('--no-headless', 'run with the browser in headful mode')
.option('--capability <features...>', 'Enable capabilities through feature flags')
.addOption(new commander_1.Option('--screenshots [flag]', 'Control whether to capture screenshots at the end of each step').choices(['on', 'off', 'only-on-failure']))
.option('--dry-run', "don't actually execute anything, report only registered journeys")
.option('--outfd <fd>', 'specify a file descriptor for logs. Default is stdout', parseInt)
.option('--ws-endpoint <endpoint>', 'Browser WebSocket endpoint to connect to')
.option('--pause-on-error', 'pause on error until a keypress is made in the console. Useful during development')
.option('--ignore-https-errors', 'ignores any HTTPS errors in sites being tested, including ones related to unrecognized certs or signatures. This can be insecure!')
.option('--quiet-exit-code', 'always return 0 as an exit code status, regardless of test pass / fail. Only return > 0 exit codes on internal errors where the suite could not be run')
.option('--throttling <config>', 'JSON object to throttle network conditions for download and upload throughput in megabits/second and latency in milliseconds. Ex: { "download": 10, "upload": 5, "latency": 200 }.', options_1.parseThrottling)
.option('--no-throttling', 'Turns off default network throttling.', options_1.parseThrottling)
.addOption(playwrightOpts)
.version(version)
.description('Run synthetic tests')
.action(async (cliArgs) => {
const tearDown = await (0, loader_1.globalSetup)(cliArgs, commander_1.program.args);
try {
const options = await (0, options_1.normalizeOptions)(cliArgs, 'run');
const results = await (0, _1.run)(options);
/**
* Exit with error status if any journey fails
*/
if (!options.quietExitCode) {
for (const result of Object.values(results)) {
if (result.status === 'failed') {
process.exit(1);
}
}
}
}
catch (e) {
console.error(e);
process.exit(1);
}
finally {
tearDown();
}
});
// Push command
commander_1.program
.command('push')
.description('Push all journeys in the current directory to create monitors within the Kibana monitor management UI')
.addOption(authMandatory)
.option('--schedule <time-in-minutes>', "schedule in minutes for the pushed monitors. Setting `10`, for example, configures monitors which don't have an interval defined to run every 10 minutes.", parseInt)
.addOption(new commander_1.Option('--locations <locations...>', 'default list of locations from which your monitors will run.').choices(monitor_1.SyntheticsLocations))
.option('--private-locations <locations...>', 'default list of private locations from which your monitors will run.')
.option('--url <url>', 'Kibana URL to upload the project monitors')
.option('--id <id>', 'project id that will be used for logically grouping monitors')
.option('--space <space>', 'the target Kibana spaces for the pushed monitors — spaces help you organise pushed monitors.')
.option('-y, --yes', 'skip all questions and run non-interactively')
.option('--proxy-uri <uri>', 'proxy uri to use when pushing to kibana', (0, options_1.collectOpts)('uri', proxySettings))
.option('--proxy-token <token>', 'auth token to use the proxy', (0, options_1.collectOpts)('token', proxySettings))
.option('--proxy-ca <path>', 'provide a CA override for proxy endpoint, as a path to be loaded or as string', (0, options_1.collectOpts)('ca', proxySettings, options_1.parseFileOption))
.option('--proxy-cert <path>', 'provide a cert override for proxy endpoint, as a path to be loaded or as string', (0, options_1.collectOpts)('cert', proxySettings, options_1.parseFileOption))
.option('--proxy-no-verify', 'disable TLS verification for the proxy connection', (0, options_1.collectOpts)('noVerify', proxySettings), false)
.addOption(pattern)
.addOption(tags)
.addOption(fields)
.addOption(match)
.addOption(params)
.addOption(playwrightOpts)
.addOption(configOpt)
.addOption(maintenanceWindows)
.action(async (cmdOpts) => {
cmdOpts = { ...cmdOpts, ...commander_1.program.opts() };
const workDir = (0, process_1.cwd)();
const tearDown = await (0, loader_1.globalSetup)({ inline: false, ...cmdOpts }, [
workDir,
]);
try {
const settings = await (0, push_1.loadSettings)(cmdOpts.config);
const options = (await (0, options_1.normalizeOptions)({
...settings,
...cmdOpts,
...{
proxy: proxySettings,
},
}, 'push'));
//Set up global proxy agent if any of the related options are set
(0, helpers_2.setGlobalProxy)(options.proxy ?? {});
await (0, push_1.validatePush)(options, settings);
const monitors = globals_1.runner._buildMonitors(options);
if (options.throttling == null) {
(0, push_1.warnIfThrottled)(monitors);
}
options.kibanaVersion = await (0, kibana_api_1.getVersion)(options);
monitors.push(...(await (0, monitor_2.createLightweightMonitors)(workDir, options)));
await (0, push_1.push)(monitors, options);
}
catch (e) {
e && console.error(e);
process.exit(1);
}
finally {
tearDown();
}
});
// Init command
commander_1.program
.command('init [dir]')
.description('Initialize Elastic synthetics project')
.action(async (dir = '') => {
try {
const generator = await new generator_1.Generator((0, path_1.resolve)(process.cwd(), dir));
await generator.setup();
}
catch (e) {
e && (0, helpers_1.error)(e);
process.exit(1);
}
});
// Locations command
commander_1.program
.command('locations')
.description(`List all locations to run the synthetics monitors. Pass optional '--url' and '--auth' to list private locations.`)
.option('--url <url>', 'Kibana URL to fetch all public and private locations')
.addOption(auth)
.option('--proxy-uri <uri>', 'proxy uri to use when pushing to kibana', (0, options_1.collectOpts)('uri', proxySettings))
.option('--proxy-token <token>', 'auth token to use the proxy', (0, options_1.collectOpts)('token', proxySettings))
.option('--proxy-ca <path>', 'provide a CA override for proxy endpoint, as a path to be loaded or as string', (0, options_1.collectOpts)('ca', proxySettings, (0, options_1.parseFileOption)('--proxy-ca')))
.option('--proxy-cert <path>', 'provide a cert override for proxy endpoint, as a path to be loaded or as string', (0, options_1.collectOpts)('cert', proxySettings, (0, options_1.parseFileOption)('--proxy-cert')))
.option('--proxy-no-verify', 'disable TLS verification for the proxy connection', (0, options_1.collectOpts)('noVerify', proxySettings), false)
.action(async (cmdOpts) => {
const revert = (0, transform_1.installTransform)();
const url = cmdOpts.url ?? (await (0, push_1.loadSettings)(null, true))?.url;
try {
const settings = await (0, push_1.loadSettings)(null, true);
const options = (await (0, options_1.normalizeOptions)({
...settings,
...cmdOpts,
...{
proxy: proxySettings,
},
}));
//Set up global proxy agent if any of the related options are set
(0, helpers_2.setGlobalProxy)(options.proxy ?? {});
if (url && cmdOpts.auth) {
const allLocations = await (0, locations_1.getLocations)({
url,
auth: cmdOpts.auth,
});
(0, locations_1.renderLocations)((0, locations_1.formatLocations)(allLocations));
}
else {
(0, locations_1.renderLocations)({ publicLocations: Object.keys(public_locations_1.LocationsMap) });
}
}
catch (e) {
e && (0, helpers_1.error)(e);
process.exit(1);
}
finally {
revert();
}
});
// TOTP command
commander_1.program
.command('totp <secret>')
.description('Generate a Time-based One-Time token using the provided secret.')
.option('--issuer <issuer>', 'Provider or Service the secret is associated with.')
.option('--label <label>', 'Account Identifier (default: SyntheticsTOTP)')
.action((secret, cmdOpts) => {
try {
const token = (0, mfa_1.totp)(secret, cmdOpts);
(0, helpers_1.write)((0, colors_1.bold)(`OTP Token: ${token}`));
}
catch (e) {
(0, helpers_1.error)(e);
process.exit(1);
}
});
commander_1.program.parse(process.argv);
//# sourceMappingURL=cli.js.map