Repository: elastic/synthetics
Pull request #764 (2023-05-10 10:46:34)

Add throttling details
Add details about network throttling changes and latest behaviour


Patch:
diff --git a/docs/throttling.md b/docs/throttling.md
index 3a43087..d27e9ad 100644
--- a/docs/throttling.md
+++ b/docs/throttling.md
@@ -1,2 +1,22 @@
-## Throttling
+### Network throttling in Elastic Synthetics
+
+We have disabled network throttling in Synthetics for browser-based monitors. This is a temporary measure and throttling will become available in a future update.
+
+⚠️ With network throttling being disabled, note that your monitors may run more quickly (i.e. have a lower duration) than you observed previously, and when network throttling is enabled again in the future.
+
+
+### Current status
+
+* Elastic’s global managed testing infrastructure
+  * Network throttling disabled for all locations from ~21:00 GMT 09 May 2023
+  * All network throttling configurations defined for your monitors are ignored
+* Private Locations (provided through Elastic Agent)
+  * Versions prior to 8.8.0 have network throttling enabled (based on your monitor configuration)
+  * Private Locations running on Elastic Agent from 8.8.0 onwards have network throttling disabled
+    * All network throttling configurations defined for your monitors are ignored
+
+
+### Changes
+
+* ~21:00 GMT 09 May 2023 - Network throttling disabled for all browser monitors running on Elastic’s global managed testing infrastructure
 
diff --git a/src/cli.ts b/src/cli.ts
index be5bbbd..ce5ea1b 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -56,6 +56,7 @@ import { Generator } from './generator';
 import { error } from './helpers';
 import { LocationsMap } from './locations/public-locations';
 import { createLightweightMonitors } from './push/monitor';
+import { getVersion } from './push/kibana_api';
 
 /* eslint-disable-next-line @typescript-eslint/no-var-requires */
 const { name, version } = require('../package.json');
@@ -214,6 +215,7 @@ program
       if ((options as CliArgs).throttling == null) {
         warnIfThrottled(monitors);
       }
+      options.kibanaVersion = await getVersion(options);
       monitors.push(...(await createLightweightMonitors(workDir, options)));
       await push(monitors, options);
     } catch (e) {
diff --git a/src/common_types.ts b/src/common_types.ts
index ad5e54f..8b5b540 100644
--- a/src/common_types.ts
+++ b/src/common_types.ts
@@ -244,6 +244,8 @@ export type PushOptions = Partial<ProjectSettings> & {
   schedule?: MonitorConfig['schedule'];
   locations?: MonitorConfig['locations'];
   privateLocations?: MonitorConfig['privateLocations'];
+  params?: MonitorConfig['params'];
+  kibanaVersion?: number;
   yes?: boolean;
   pattern?: string;
   match?: string;
diff --git a/src/helpers.ts b/src/helpers.ts
index 4c55423..2e6b6ae 100644
--- a/src/helpers.ts
+++ b/src/helpers.ts
@@ -389,7 +389,7 @@ export function warn(message: string) {
   write(bold(yellow(`${symbols['warning']} ${message}`)));
 }
 
-export function removeTrailingSlash(url: string) {
+export function removeTrailingSlash(url = '') {
   return url.replace(/\/+$/, '');
 }
 
diff --git a/src/index.ts b/src/index.ts
index 2fd5232..56bed84 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -66,6 +66,7 @@ export type { SyntheticsConfig } from './common_types';
 export type {
   Action,
   ActionInContext,
+  FrameDescription,
   Signal,
   Step,
   Steps,
diff --git a/src/push/index.ts b/src/push/index.ts
index f6ffb07..2c6f228 100644
--- a/src/push/index.ts
+++ b/src/push/index.ts
@@ -22,7 +22,6 @@
  * THE SOFTWARE.
  *
  */
-import semver from 'semver';
 import { readFile, writeFile } from 'fs/promises';
 import { prompt } from 'enquirer';
 import { bold, grey } from 'kleur/colors';
@@ -50,11 +49,15 @@ import {
   bulkDeleteMonitors,
   bulkGetMonitors,
   bulkPutMonitors,
-  getVersion,
   createMonitorsLegacy,
   CHUNK_SIZE,
 } from './kibana_api';
-import { getChunks, logDiff } from './utils';
+import {
+  getChunks,
+  isBulkAPISupported,
+  isLightweightMonitorSupported,
+  logDiff,
+} from './utils';
 
 export async function push(monitors: Monitor[], options: PushOptions) {
   const duplicates = trackDuplicates(monitors);
@@ -63,10 +66,11 @@ export async function push(monitors: Monitor[], options: PushOptions) {
   }
   progress(`Pushing monitors for project: ${options.id}`);
 
-  const stackVersion = await getVersion(options);
-  const isV2 = semver.satisfies(stackVersion, '>=8.6.0');
-  if (!isV2) {
-    return await pushLegacy(monitors, options, stackVersion);
+  /**
+   * Legacy API for kibana which does not support bulk operations
+   */
+  if (!isBulkAPISupported(options.kibanaVersion)) {
+    return await pushLegacy(monitors, options);
   }
 
   const local = getLocalMonitors(monitors);
@@ -245,18 +249,10 @@ export async function catchIncorrectSettings(
   }
 }
 
-export async function pushLegacy(
-  monitors: Monitor[],
-  options: PushOptions,
-  version: number
-) {
-  const noLightWeightSupport = semver.satisfies(version, '<8.5.0');
-  if (
-    noLightWeightSupport &&
-    monitors.some(monitor => monitor.type !== 'browser')
-  ) {
+export async function pushLegacy(monitors: Monitor[], options: PushOptions) {
+  if (isLightweightMonitorSupported(monitors, options)) {
     throw error(
-      `Aborted: Lightweight monitors are not supported in ${version}. Please upgrade to 8.5.0 or above.`
+      `Aborted: Lightweight monitors are not supported in ${options.kibanaVersion}. Please upgrade to 8.5.0 or above.`
     );
   }
 
diff --git a/src/push/monitor.ts b/src/push/monitor.ts
index a3549a2..ca3a8e4 100644
--- a/src/push/monitor.ts
+++ b/src/push/monitor.ts
@@ -32,6 +32,7 @@ import { SYNTHETICS_PATH, totalist, indent, warn, isMatch } from '../helpers';
 import { LocationsMap } from '../locations/public-locations';
 import { ALLOWED_SCHEDULES, Monitor, MonitorConfig } from '../dsl/monitor';
 import { PushOptions } from '../common_types';
+import { isParamOptionSupported } from './utils';
 
 // Allowed extensions for lightweight monitor files
 const ALLOWED_LW_EXTENSIONS = ['.yml', '.yaml'];
@@ -235,14 +236,22 @@ export function buildMonitorFromYaml(
   delete config['private_locations'];
 
   const alertConfig = parseAlertConfig(config);
-
-  return new Monitor({
+  const mon = new Monitor({
     locations: options.locations,
     ...config,
     privateLocations,
     schedule: schedule || options.schedule,
     alert: alertConfig,
   });
+
+  /**
+   * Params support is only available for lighweight monitors
+   * post 8.7.2 stack
+   */
+  if (isParamOptionSupported(options.kibanaVersion)) {
+    mon.config.params = options.params;
+  }
+  return mon;
 }
 
 export const parseAlertConfig = (config: MonitorConfig) => {
diff --git a/src/push/utils.ts b/src/push/utils.ts
index a9d4f59..bff826d 100644
--- a/src/push/utils.ts
+++ b/src/push/utils.ts
@@ -23,9 +23,11 @@
  *
  */
 
+import semver from 'semver';
 import { progress, removeTrailingSlash } from '../helpers';
 import { green, red, grey, yellow } from 'kleur/colors';
 import { PushOptions } from '../common_types';
+import { Monitor } from '../dsl/monitor';
 
 export function logDiff<T extends Set<string>>(
   newIDs: T,
@@ -75,3 +77,32 @@ export function generateURL(options: PushOptions, operation: Operation) {
       throw new Error('Invalid operation');
   }
 }
+
+/**
+ * Bulk API is supported for push monitors only from 8.6.0 and above
+ */
+export function isBulkAPISupported(version: number) {
+  return semver.satisfies(version, '>=8.6.0');
+}
+
+/**
+ * Lightweight monitors are supported only from 8.5.0 and above
+ */
+export function isLightweightMonitorSupported(
+  monitors: Monitor[],
+  options: PushOptions
+) {
+  const version = options.kibanaVersion;
+  return (
+    semver.satisfies(version, '<8.5.0') &&
+    monitors.some(monitor => monitor.type !== 'browser')
+  );
+}
+
+/**
+ * Lighweight monitor param options are supported only from
+ * 8.7.2 and above
+ */
+export function isParamOptionSupported(version: number) {
+  return semver.satisfies(version, '>=8.7.2');
+}


Test patch:
diff --git a/__tests__/push/index.test.ts b/__tests__/push/index.test.ts
index 2083178..a7a52f3 100644
--- a/__tests__/push/index.test.ts
+++ b/__tests__/push/index.test.ts
@@ -34,6 +34,7 @@ import { CLIMock } from '../utils/test-config';
 import { THROTTLING_WARNING_MSG } from '../../src/helpers';
 
 describe('Push', () => {
+  let server: Server;
   const PROJECT_DIR = join(__dirname, 'new-project');
   const DEFAULT_ARGS = ['--auth', 'foo'];
 
@@ -55,10 +56,12 @@ describe('Push', () => {
   }
 
   beforeAll(async () => {
+    server = await createKibanaTestServer('8.6.0');
     await mkdir(PROJECT_DIR, { recursive: true });
   });
   afterAll(async () => {
     process.env.NO_COLOR = '';
+    await server.close();
     await rm(PROJECT_DIR, { recursive: true, force: true });
   });
 
@@ -134,7 +137,7 @@ journey('journey 1', () => monitor.use({ id: 'j1', schedule: 8 }));`
 
   it('errors on duplicate browser monitors', async () => {
     await fakeProjectSetup(
-      { id: 'test-project' },
+      { id: 'test-project', space: 'dummy', url: server.PREFIX },
       { locations: ['test-loc'], schedule: 3 }
     );
 
@@ -173,7 +176,7 @@ journey('duplicate name', () => monitor.use({ schedule: 15 }));`
 
   it('errors on duplicate lightweight monitors', async () => {
     await fakeProjectSetup(
-      { id: 'test-project' },
+      { id: 'test-project', space: 'dummy', url: server.PREFIX },
       { locations: ['test-loc'], schedule: 3 }
     );
 
diff --git a/__tests__/push/monitor.test.ts b/__tests__/push/monitor.test.ts
index add64b9..5c8bfa6 100644
--- a/__tests__/push/monitor.test.ts
+++ b/__tests__/push/monitor.test.ts
@@ -261,6 +261,35 @@ heartbeat.monitors:
       });
     });
 
+    it('use params from config', async () => {
+      await writeHBFile(`
+heartbeat.monitors:
+- type: icmp
+  id: foo
+  name: without schedule
+      `);
+      const [monitor1] = await createLightweightMonitors(
+        PROJECT_DIR,
+        {} as PushOptions
+      );
+      expect(monitor1.config).toMatchObject({
+        id: 'foo',
+        name: 'without schedule',
+        type: 'icmp',
+      });
+
+      const [monitor2] = await createLightweightMonitors(PROJECT_DIR, {
+        params: { foo: 'bar' },
+        kibanaVersion: '8.8.0',
+      } as any);
+      expect(monitor2.config).toEqual({
+        id: 'foo',
+        name: 'without schedule',
+        type: 'icmp',
+        params: { foo: 'bar' },
+      });
+    });
+
     it('parses monitor config correctly', async () => {
       await writeHBFile(`
 heartbeat.monitors:
diff --git a/__tests__/utils/kibana-test-server.ts b/__tests__/utils/kibana-test-server.ts
index cb32340..09a0d71 100644
--- a/__tests__/utils/kibana-test-server.ts
+++ b/__tests__/utils/kibana-test-server.ts
@@ -30,7 +30,7 @@ import {
 } from '../../src/push/kibana_api';
 
 export const createKibanaTestServer = async (kibanaVersion: string) => {
-  const server = await Server.create({ port: 54455 });
+  const server = await Server.create({ port: 0 });
   server.route('/s/dummy/api/status', (req, res) =>
     res.end(JSON.stringify({ version: { number: kibanaVersion } }))
   );