From 2fdaf88fbd20d7a16e0d8108a93c386025bfdbdc Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 16 Sep 2020 15:30:33 -0700 Subject: [PATCH] schema utils --- .../plugins/reporting/common/schema_utils.ts | 36 +++++++++++++++++++ .../public/components/report_listing.tsx | 8 ++--- x-pack/plugins/reporting/public/plugin.tsx | 4 +-- .../browsers/chromium/driver_factory/index.ts | 5 ++- .../export_types/csv/generate_csv/index.ts | 11 ++---- .../lib/screenshots/get_number_of_items.ts | 6 ++-- .../server/lib/screenshots/open_url.ts | 6 ++-- .../server/lib/screenshots/wait_for_render.ts | 8 ++--- .../screenshots/wait_for_visualizations.ts | 6 ++-- .../reporting/server/lib/store/store.ts | 4 +-- .../server/routes/diagnostic/config.ts | 7 ++-- 11 files changed, 60 insertions(+), 41 deletions(-) create mode 100644 x-pack/plugins/reporting/common/schema_utils.ts diff --git a/x-pack/plugins/reporting/common/schema_utils.ts b/x-pack/plugins/reporting/common/schema_utils.ts new file mode 100644 index 0000000000000..1f924ab272bcc --- /dev/null +++ b/x-pack/plugins/reporting/common/schema_utils.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ByteSizeValue } from '@kbn/config-schema'; +import moment from 'moment'; + +/* + * For cleaner code: use these functions when a config schema value could be + * one type or another. This allows you to treat the value as one type. + */ + +export const durationToNumber = (value: number | moment.Duration): number => { + if (typeof value === 'number') { + return value; + } + return value.asMilliseconds(); +}; + +export const numberToByteSizeValue = (value: number | ByteSizeValue) => { + if (typeof value === 'number') { + return new ByteSizeValue(value); + } + + return value; +}; + +export const byteSizeValueToNumber = (value: number | ByteSizeValue) => { + if (typeof value === 'number') { + return value; + } + + return value.getValueInBytes(); +}; diff --git a/x-pack/plugins/reporting/public/components/report_listing.tsx b/x-pack/plugins/reporting/public/components/report_listing.tsx index fc964fc599c62..a09ec22a93797 100644 --- a/x-pack/plugins/reporting/public/components/report_listing.tsx +++ b/x-pack/plugins/reporting/public/components/report_listing.tsx @@ -6,8 +6,8 @@ import { EuiBasicTable, - EuiFlexItem, EuiFlexGroup, + EuiFlexItem, EuiPageContent, EuiSpacer, EuiText, @@ -23,6 +23,7 @@ import { Subscription } from 'rxjs'; import { ApplicationStart, ToastsSetup } from 'src/core/public'; import { ILicense, LicensingPluginSetup } from '../../../licensing/public'; import { Poller } from '../../common/poller'; +import { durationToNumber } from '../../common/schema_utils'; import { JobStatuses } from '../../constants'; import { checkLicense } from '../lib/license_check'; import { JobQueueEntry, ReportingAPIClient } from '../lib/reporting_api_client'; @@ -185,10 +186,7 @@ class ReportListingUi extends Component { this.mounted = true; const { pollConfig, license$ } = this.props; - const pollFrequencyInMillis = - typeof pollConfig.jobsRefresh.interval === 'number' - ? pollConfig.jobsRefresh.interval - : pollConfig.jobsRefresh.interval.asMilliseconds(); + const pollFrequencyInMillis = durationToNumber(pollConfig.jobsRefresh.interval); this.poller = new Poller({ functionToPoll: () => { return this.fetchJobs(); diff --git a/x-pack/plugins/reporting/public/plugin.tsx b/x-pack/plugins/reporting/public/plugin.tsx index 1f2efbfcba889..a134377e194b8 100644 --- a/x-pack/plugins/reporting/public/plugin.tsx +++ b/x-pack/plugins/reporting/public/plugin.tsx @@ -26,6 +26,7 @@ import { import { ManagementSetup } from '../../../../src/plugins/management/public'; import { SharePluginSetup } from '../../../../src/plugins/share/public'; import { LicensingPluginSetup } from '../../licensing/public'; +import { durationToNumber } from '../common/schema_utils'; import { JobId, JobStatusBuckets, ReportingConfigType } from '../common/types'; import { JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY } from '../constants'; import { getGeneralErrorToast } from './components'; @@ -158,8 +159,7 @@ export class ReportingPublicPlugin implements Plugin { const { http, notifications } = core; const apiClient = new ReportingAPIClient(http); const streamHandler = new StreamHandler(notifications, apiClient); - const { interval: intervalRaw } = this.config.poll.jobsRefresh; - const interval = typeof intervalRaw === 'number' ? intervalRaw : intervalRaw.asMilliseconds(); + const interval = durationToNumber(this.config.poll.jobsRefresh.interval); Rx.timer(0, interval) .pipe( takeUntil(this.stop$), // stop the interval when stop method is called diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts index 2ceb92a4fe399..6897f07c45e2b 100644 --- a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts +++ b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts @@ -21,6 +21,7 @@ import { InnerSubscriber } from 'rxjs/internal/InnerSubscriber'; import { ignoreElements, map, mergeMap, tap } from 'rxjs/operators'; import { getChromiumDisconnectedError } from '../'; import { BROWSER_TYPE } from '../../../../common/constants'; +import { durationToNumber } from '../../../../common/schema_utils'; import { CaptureConfig } from '../../../../server/types'; import { LevelLogger } from '../../../lib'; import { safeChildProcess } from '../../safe_child_process'; @@ -90,9 +91,7 @@ export class HeadlessChromiumDriverFactory { // Set the default timeout for all navigation methods to the openUrl timeout (30 seconds) // All waitFor methods have their own timeout config passed in to them - const timeoutRaw = this.captureConfig.timeouts.openUrl; - const timeout = typeof timeoutRaw === 'number' ? timeoutRaw : timeoutRaw.asMilliseconds(); - page.setDefaultTimeout(timeout); + page.setDefaultTimeout(durationToNumber(this.captureConfig.timeouts.openUrl)); logger.debug(`Browser page driver created`); } catch (err) { diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts index 5e8c36e9fe328..e383f21143149 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ByteSizeValue } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { IUiSettingsClient } from 'src/core/server'; import { ReportingConfig } from '../../../'; import { CancellationToken } from '../../../../../../plugins/reporting/common'; import { CSV_BOM_CHARS } from '../../../../common/constants'; +import { byteSizeValueToNumber } from '../../../../common/schema_utils'; import { LevelLogger } from '../../../lib'; import { getFieldFormats } from '../../../services'; import { IndexPatternSavedObject, SavedSearchGeneratorResult } from '../types'; @@ -47,13 +47,6 @@ export interface GenerateCsvParams { conflictedTypesFields: string[]; } -const getBytes = (sizeBytes: number | ByteSizeValue): number => { - if (typeof sizeBytes === 'number') { - return sizeBytes; - } - return sizeBytes.getValueInBytes(); -}; - export function createGenerateCsv(logger: LevelLogger) { const hitIterator = createHitIterator(logger); @@ -72,7 +65,7 @@ export function createGenerateCsv(logger: LevelLogger) { ); const escapeValue = createEscapeValue(settings.quoteValues, settings.escapeFormulaValues); const bom = config.get('csv', 'useByteOrderMarkEncoding') ? CSV_BOM_CHARS : ''; - const builder = new MaxSizeStringBuilder(getBytes(settings.maxSizeBytes), bom); + const builder = new MaxSizeStringBuilder(byteSizeValueToNumber(settings.maxSizeBytes), bom); const { fields, metaFields, conflictedTypesFields } = job; const header = `${fields.map(escapeValue).join(settings.separator)}\n`; diff --git a/x-pack/plugins/reporting/server/lib/screenshots/get_number_of_items.ts b/x-pack/plugins/reporting/server/lib/screenshots/get_number_of_items.ts index 52c35e29eb995..89cb4221c96b2 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/get_number_of_items.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/get_number_of_items.ts @@ -5,9 +5,10 @@ */ import { i18n } from '@kbn/i18n'; +import { durationToNumber } from '../../../common/schema_utils'; +import { LevelLogger, startTrace } from '../'; import { HeadlessChromiumDriver } from '../../browsers'; import { CaptureConfig } from '../../types'; -import { LevelLogger, startTrace } from '../'; import { LayoutInstance } from '../layouts'; import { CONTEXT_GETNUMBEROFITEMS, CONTEXT_READMETADATA } from './constants'; @@ -31,8 +32,7 @@ export const getNumberOfItems = async ( // the dashboard is using the `itemsCountAttribute` attribute to let us // know how many items to expect since gridster incrementally adds panels // we have to use this hint to wait for all of them - const timeoutRaw = captureConfig.timeouts.waitForElements; - const timeout = typeof timeoutRaw === 'number' ? timeoutRaw : timeoutRaw.asMilliseconds(); + const timeout = durationToNumber(captureConfig.timeouts.waitForElements); await browser.waitForSelector( `${renderCompleteSelector},[${itemsCountAttribute}]`, { timeout }, diff --git a/x-pack/plugins/reporting/server/lib/screenshots/open_url.ts b/x-pack/plugins/reporting/server/lib/screenshots/open_url.ts index bd4a7f339927f..e28f50851f4d9 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/open_url.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/open_url.ts @@ -5,9 +5,10 @@ */ import { i18n } from '@kbn/i18n'; +import { durationToNumber } from '../../../common/schema_utils'; +import { LevelLogger, startTrace } from '../'; import { HeadlessChromiumDriver } from '../../browsers'; import { CaptureConfig, ConditionalHeaders } from '../../types'; -import { LevelLogger, startTrace } from '../'; export const openUrl = async ( captureConfig: CaptureConfig, @@ -19,8 +20,7 @@ export const openUrl = async ( ): Promise => { const endTrace = startTrace('open_url', 'wait'); try { - const timeoutRaw = captureConfig.timeouts.openUrl; - const timeout = typeof timeoutRaw === 'number' ? timeoutRaw : timeoutRaw.asMilliseconds(); + const timeout = durationToNumber(captureConfig.timeouts.openUrl); await browser.open( url, { conditionalHeaders, waitForSelector: pageLoadSelector, timeout }, diff --git a/x-pack/plugins/reporting/server/lib/screenshots/wait_for_render.ts b/x-pack/plugins/reporting/server/lib/screenshots/wait_for_render.ts index 5cf2b0b8cb678..edd4f71b2adac 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/wait_for_render.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/wait_for_render.ts @@ -5,17 +5,13 @@ */ import { i18n } from '@kbn/i18n'; -import { Duration } from 'moment'; +import { durationToNumber } from '../../../common/schema_utils'; import { HeadlessChromiumDriver } from '../../browsers'; import { CaptureConfig } from '../../types'; import { LevelLogger, startTrace } from '../'; import { LayoutInstance } from '../layouts'; import { CONTEXT_WAITFORRENDER } from './constants'; -const toMilliseconds = (rawValue: number | Duration) => { - return typeof rawValue === 'number' ? rawValue : rawValue.asMilliseconds(); -}; - export const waitForRenderComplete = async ( captureConfig: CaptureConfig, browser: HeadlessChromiumDriver, @@ -72,7 +68,7 @@ export const waitForRenderComplete = async ( return Promise.all(renderedTasks).then(hackyWaitForVisualizations); }, - args: [layout.selectors.renderComplete, toMilliseconds(captureConfig.loadDelay)], + args: [layout.selectors.renderComplete, durationToNumber(captureConfig.loadDelay)], }, { context: CONTEXT_WAITFORRENDER }, logger diff --git a/x-pack/plugins/reporting/server/lib/screenshots/wait_for_visualizations.ts b/x-pack/plugins/reporting/server/lib/screenshots/wait_for_visualizations.ts index 03b52718a9e14..5f86a2b3bf00b 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/wait_for_visualizations.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/wait_for_visualizations.ts @@ -5,8 +5,9 @@ */ import { i18n } from '@kbn/i18n'; -import { HeadlessChromiumDriver } from '../../browsers'; +import { durationToNumber } from '../../../common/schema_utils'; import { LevelLogger, startTrace } from '../'; +import { HeadlessChromiumDriver } from '../../browsers'; import { CaptureConfig } from '../../types'; import { LayoutInstance } from '../layouts'; import { CONTEXT_WAITFORELEMENTSTOBEINDOM } from './constants'; @@ -40,8 +41,7 @@ export const waitForVisualizations = async ( ); try { - const timeoutRaw = captureConfig.timeouts.renderComplete; - const timeout = typeof timeoutRaw === 'number' ? timeoutRaw : timeoutRaw.asMilliseconds(); + const timeout = durationToNumber(captureConfig.timeouts.renderComplete); await browser.waitFor( { fn: getCompletedItemsCount, args: [{ renderCompleteSelector }], toEqual, timeout }, { context: CONTEXT_WAITFORELEMENTSTOBEINDOM }, diff --git a/x-pack/plugins/reporting/server/lib/store/store.ts b/x-pack/plugins/reporting/server/lib/store/store.ts index c5e6c3798aded..ce28715e1ba46 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.ts @@ -5,6 +5,7 @@ */ import { ElasticsearchServiceSetup } from 'src/core/server'; +import { durationToNumber } from '../../../common/schema_utils'; import { LevelLogger, statuses } from '../'; import { ReportingCore } from '../../'; import { BaseParams, BaseParamsEncryptedFields, ReportingUser } from '../../types'; @@ -47,9 +48,8 @@ export class ReportingStore { this.indexPrefix = config.get('index'); this.indexInterval = config.get('queue', 'indexInterval'); - const timeoutRaw = config.get('queue', 'timeout'); this.jobSettings = { - timeout: typeof timeoutRaw === 'number' ? timeoutRaw : timeoutRaw.asMilliseconds(), + timeout: durationToNumber(config.get('queue', 'timeout')), browser_type: config.get('capture', 'browser', 'type'), max_attempts: config.get('capture', 'maxAttempts'), priority: 10, // unused diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/config.ts b/x-pack/plugins/reporting/server/routes/diagnostic/config.ts index 6f23d406ff640..3ce46cf233472 100644 --- a/x-pack/plugins/reporting/server/routes/diagnostic/config.ts +++ b/x-pack/plugins/reporting/server/routes/diagnostic/config.ts @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { defaults, get } from 'lodash'; import { ReportingCore } from '../..'; import { API_DIAGNOSE_URL } from '../../../common/constants'; +import { numberToByteSizeValue } from '../../../common/schema_utils'; import { LevelLogger as Logger } from '../../lib'; import { DiagnosticResponse } from '../../types'; import { authorizedUserPreRoutingFactory } from '../lib/authorized_user_pre_routing'; @@ -43,11 +44,7 @@ export const registerDiagnoseConfig = (reporting: ReportingCore, logger: Logger) '100mb' ); const elasticSearchMaxContentBytes = ByteSizeValue.parse(elasticSearchMaxContent); - const kibanaMaxContentBytesRaw = config.get('csv', 'maxSizeBytes'); - const kibanaMaxContentBytes = - typeof kibanaMaxContentBytesRaw === 'number' - ? new ByteSizeValue(kibanaMaxContentBytesRaw) - : kibanaMaxContentBytesRaw; + const kibanaMaxContentBytes = numberToByteSizeValue(config.get('csv', 'maxSizeBytes')); if (kibanaMaxContentBytes.isGreaterThan(elasticSearchMaxContentBytes)) { const maxContentSizeWarning = i18n.translate(