diff --git a/packages/core/custom-branding/core-custom-branding-common/index.d.ts b/packages/core/custom-branding/core-custom-branding-common/index.d.ts new file mode 100644 index 0000000000000..88b1cd0a20335 --- /dev/null +++ b/packages/core/custom-branding/core-custom-branding-common/index.d.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface CustomBranding { + /** + * Custom replacement for the Elastic logo in the top lef * + * */ + logo?: string; + /** + * Custom replacement for favicon in SVG format + */ + faviconSVG?: string; + /** + * Custom page title + */ + pageTitle?: string; + /** + * Custom replacement for Elastic Mark + * @link packages/core/chrome/core-chrome-browser-internal/src/ui/header/elastic_mark.tsx + */ + customizedLogo?: string; + /** + * Custom replacement for favicon in PNG format + */ + faviconPNG?: string; +} diff --git a/packages/core/custom-branding/core-custom-branding-common/index.js b/packages/core/custom-branding/core-custom-branding-common/index.js new file mode 100644 index 0000000000000..d92515c8edb6f --- /dev/null +++ b/packages/core/custom-branding/core-custom-branding-common/index.js @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +Object.defineProperty(exports, '__esModule', { value: true }); diff --git a/src/plugins/usage_collection/common/types/index.ts b/src/plugins/usage_collection/common/types/index.ts new file mode 100644 index 0000000000000..423bde69accdb --- /dev/null +++ b/src/plugins/usage_collection/common/types/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1Stats from './stats'; +export * as v1UiCounters from './ui_counters'; +export * as v1UsageCounters from './usage_counters'; diff --git a/src/plugins/usage_collection/common/types/stats/core_metrics_duplicated.ts b/src/plugins/usage_collection/common/types/stats/core_metrics_duplicated.ts new file mode 100644 index 0000000000000..63a80dde1c371 --- /dev/null +++ b/src/plugins/usage_collection/common/types/stats/core_metrics_duplicated.ts @@ -0,0 +1,207 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * an IntervalHistogram object that samples and reports the event loop delay over time. + * The delays will be reported in milliseconds. + * + * @public + */ +export interface IntervalHistogram { + // The first timestamp the interval timer kicked in for collecting data points. + fromTimestamp: string; + // Last timestamp the interval timer kicked in for collecting data points. + lastUpdatedAt: string; + // The minimum recorded event loop delay. + min: number; + // The maximum recorded event loop delay. + max: number; + // The mean of the recorded event loop delays. + mean: number; + // The number of times the event loop delay exceeded the maximum 1 hour event loop delay threshold. + exceeds: number; + // The standard deviation of the recorded event loop delays. + stddev: number; + // An object detailing the accumulated percentile distribution. + percentiles: { + // 50th percentile of delays of the collected data points. + 50: number; + // 75th percentile of delays of the collected data points. + 75: number; + // 95th percentile of delays of the collected data points. + 95: number; + // 99th percentile of delays of the collected data points. + 99: number; + }; +} + +/** + * Protocol(s) used by the Elasticsearch Client + * @public + */ + +export type ElasticsearchClientProtocol = 'none' | 'http' | 'https' | 'mixed'; + +/** + * Metrics related to the elasticsearch clients + * @public + */ +export interface ElasticsearchClientsMetrics { + /** Total number of active sockets (all nodes, all connections) */ + totalActiveSockets: number; + /** Total number of available sockets (alive but idle, all nodes, all connections) */ + totalIdleSockets: number; + /** Total number of queued requests (all nodes, all connections) */ + totalQueuedRequests: number; +} + +/** + * Process related metrics + * @public + */ +export interface OpsProcessMetrics { + /** pid of the kibana process */ + pid: number; + /** process memory usage */ + memory: { + /** heap memory usage */ + heap: { + /** total heap available */ + total_in_bytes: number; + /** used heap */ + used_in_bytes: number; + /** v8 heap size limit */ + size_limit: number; + }; + /** node rss */ + resident_set_size_in_bytes: number; + }; + /** mean event loop delay since last collection*/ + event_loop_delay: number; + /** node event loop delay histogram since last collection */ + event_loop_delay_histogram: IntervalHistogram; + /** uptime of the kibana process */ + uptime_in_millis: number; +} + +/** + * OS related metrics + * @public + */ +export interface OpsOsMetrics { + /** The os platform */ + platform: NodeJS.Platform; + /** The os platform release, prefixed by the platform name */ + platformRelease: string; + /** The os distrib. Only present for linux platforms */ + distro?: string; + /** The os distrib release, prefixed by the os distrib. Only present for linux platforms */ + distroRelease?: string; + /** cpu load metrics */ + load: { + /** load for last minute */ + '1m': number; + /** load for last 5 minutes */ + '5m': number; + /** load for last 15 minutes */ + '15m': number; + }; + /** system memory usage metrics */ + memory: { + /** total memory available */ + total_in_bytes: number; + /** current free memory */ + free_in_bytes: number; + /** current used memory */ + used_in_bytes: number; + }; + /** the OS uptime */ + uptime_in_millis: number; + + /** cpu accounting metrics, undefined when not running in a cgroup */ + cpuacct?: { + /** name of this process's cgroup */ + control_group: string; + /** cpu time used by this process's cgroup */ + usage_nanos: number; + }; + + /** cpu cgroup metrics, undefined when not running in a cgroup */ + cpu?: { + /** name of this process's cgroup */ + control_group: string; + /** the length of the cfs period */ + cfs_period_micros: number; + /** total available run-time within a cfs period */ + cfs_quota_micros: number; + /** current stats on the cfs periods */ + stat: { + /** number of cfs periods that elapsed */ + number_of_elapsed_periods: number; + /** number of times the cgroup has been throttled */ + number_of_times_throttled: number; + /** total amount of time the cgroup has been throttled for */ + time_throttled_nanos: number; + }; + }; +} + +/** + * server related metrics + * @public + */ +export interface OpsServerMetrics { + /** server response time stats */ + response_times: { + /** average response time */ + avg_in_millis: number; + /** maximum response time */ + max_in_millis: number; + }; + /** server requests stats */ + requests: { + /** number of disconnected requests since startup */ + disconnects: number; + /** total number of requests handled since startup */ + total: number; + /** number of request handled per response status code */ + statusCodes: Record; + }; + /** number of current concurrent connections to the server */ + concurrent_connections: number; +} + +/** + * Regroups metrics gathered by all the collectors. + * This contains metrics about the os/runtime, the kibana process and the http server. + * + * @public + */ +export interface OpsMetrics { + /** Time metrics were recorded at. */ + collected_at: Date; + /** + * Metrics related to the elasticsearch client + */ + elasticsearch_client: ElasticsearchClientsMetrics; + /** + * Process related metrics. + * @remarks processes field preferred + */ + process: OpsProcessMetrics; + /** Process related metrics. Reports an array of objects for each kibana pid.*/ + processes: OpsProcessMetrics[]; + /** OS related metrics */ + os: OpsOsMetrics; + /** server response time stats */ + response_times: OpsServerMetrics['response_times']; + /** server requests stats */ + requests: OpsServerMetrics['requests']; + /** number of current concurrent connections to the server */ + concurrent_connections: OpsServerMetrics['concurrent_connections']; +} diff --git a/src/plugins/usage_collection/common/types/stats/index.ts b/src/plugins/usage_collection/common/types/stats/index.ts new file mode 100644 index 0000000000000..f14c7c0580841 --- /dev/null +++ b/src/plugins/usage_collection/common/types/stats/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; +export * from './latest'; diff --git a/src/plugins/usage_collection/common/types/stats/latest.ts b/src/plugins/usage_collection/common/types/stats/latest.ts new file mode 100644 index 0000000000000..ff21a8ea323e3 --- /dev/null +++ b/src/plugins/usage_collection/common/types/stats/latest.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +export * as OpsMetricsCopy from './core_metrics_duplicated'; +export * from './v1'; diff --git a/src/plugins/usage_collection/common/types/stats/v1.ts b/src/plugins/usage_collection/common/types/stats/v1.ts new file mode 100644 index 0000000000000..e3881d19aec19 --- /dev/null +++ b/src/plugins/usage_collection/common/types/stats/v1.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import * as OpsMetricsCopy from './core_metrics_duplicated'; +/** v1 types Start */ + +/** + * stats query v1 + * @remarks exclude_usage is always interpreted as true. query param retained to prevent breaking changes to existing consumers. + */ +export interface StatsHTTPQuery { + extended?: boolean | ''; + legacy?: boolean | ''; + exclude_usage?: boolean | ''; +} + +export interface UsageObject { + kibana?: UsageObject; + xpack?: UsageObject; + [key: string]: unknown | UsageObject; +} +/** + * Extended usage stats. + * Legacy implementation used to conditionally include kibana usage metrics + * as of https://github.com/elastic/kibana/pull/151082, usage is no longer reported + * and set to an empty object to prevent breaking changes to existing consumers. + */ +export interface ExtendedStats { + [key: string]: unknown; + clusterUuid?: string; // camel case if legacy === true + cluster_uuid?: string; // snake_case if legacy === false +} +/** + * OpsMetrics: aliased from a duplicate of core's OpsMetrics types + * @remarks the alternative to creating a local copy of the OpsMetrics types is to declare them as `unknown` and assume validation happens elsewhere. + * The disadvantage is that any changes made to the original OpsMetrics will be passed through without needing to update the API types. + */ +export type LastOpsMetrics = OpsMetricsCopy.OpsMetrics; + +/** explicitly typed stats for kibana */ +export interface KibanaStats { + // kibana + kibana: { + uuid: string; + name: string; + index: string; + host: string; + locale: string; + transport_address: string; + version: string; + snapshot: boolean; + status: string; + }; +} +/** Stats response body */ +export type StatsHTTPBodyTyped = LastOpsMetrics | KibanaStats | ExtendedStats; + +/** + * unused, for demonstration purposes only. + * alternative generic type for api response body + */ +export interface LastOpsMetricsUnknown { + [key: string]: unknown; +} + +/** + * unused, for demonstration purposes only. + * alternative generic type for api response body + */ +export interface StatsHTTPBodyUnknown { + [key: string]: unknown; +} diff --git a/src/plugins/usage_collection/common/types/ui_counters/index.ts b/src/plugins/usage_collection/common/types/ui_counters/index.ts new file mode 100644 index 0000000000000..f14c7c0580841 --- /dev/null +++ b/src/plugins/usage_collection/common/types/ui_counters/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; +export * from './latest'; diff --git a/src/plugins/usage_collection/common/types/ui_counters/latest.ts b/src/plugins/usage_collection/common/types/ui_counters/latest.ts new file mode 100644 index 0000000000000..f966e698fb59e --- /dev/null +++ b/src/plugins/usage_collection/common/types/ui_counters/latest.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; diff --git a/src/plugins/usage_collection/common/types/ui_counters/v1.ts b/src/plugins/usage_collection/common/types/ui_counters/v1.ts new file mode 100644 index 0000000000000..0f110aee5a4e9 --- /dev/null +++ b/src/plugins/usage_collection/common/types/ui_counters/v1.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * ui_counters query v1 + * @remarks + */ +export interface UiCountersHTTPRequestBody { + report: { + reportVersion?: 3; + userAgent?: Record< + string, + Readonly< + {} & { + key: string; + type: string; + appName: string; + userAgent: string; + } + > + >; + uiCounter?: Record< + string, + Readonly< + {} & { + key: string; + type: string; + appName: string; + eventName: string; + total: number; + } + > + >; + application_usage?: Record< + string, + Readonly<{ + minutesOnScreen: number; + numberOfClicks: number; + appId: string; + viewId: string; + }> + >; + }; +} +/** explicit response type for store report success. The status value is hardcoded. */ +export interface UiCountersResponseOk { + status: 'ok'; +} + +/** explicit response type for store report fail. The status value is hardcoded. */ +export interface UiCountersResponseFail { + status: 'fail'; +} diff --git a/src/plugins/usage_collection/common/types/usage_counters/index.ts b/src/plugins/usage_collection/common/types/usage_counters/index.ts new file mode 100644 index 0000000000000..f14c7c0580841 --- /dev/null +++ b/src/plugins/usage_collection/common/types/usage_counters/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; +export * from './latest'; diff --git a/src/plugins/usage_collection/common/types/usage_counters/latest.ts b/src/plugins/usage_collection/common/types/usage_counters/latest.ts new file mode 100644 index 0000000000000..f966e698fb59e --- /dev/null +++ b/src/plugins/usage_collection/common/types/usage_counters/latest.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; diff --git a/src/plugins/usage_collection/common/types/usage_counters/v1.ts b/src/plugins/usage_collection/common/types/usage_counters/v1.ts new file mode 100644 index 0000000000000..fa53a9d9e93b0 --- /dev/null +++ b/src/plugins/usage_collection/common/types/usage_counters/v1.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface CounterMetric { + domainId: string; + counterName: string; + counterType: string; + incrementBy: number; +} + +/** + * Details about the counter to be incremented + */ +export interface IncrementCounterParams { + /** The name of the counter **/ + counterName: string; + /** The counter type ("count" by default) **/ + counterType?: string; + /** Increment the counter by this number (1 if not specified) **/ + incrementBy?: number; +} diff --git a/src/plugins/usage_collection/public/services/create_reporter.ts b/src/plugins/usage_collection/public/services/create_reporter.ts index 95d5fff9cc943..685e3063e0a95 100644 --- a/src/plugins/usage_collection/public/services/create_reporter.ts +++ b/src/plugins/usage_collection/public/services/create_reporter.ts @@ -8,6 +8,7 @@ import { Reporter, Storage } from '@kbn/analytics'; import { HttpSetup } from '@kbn/core/public'; +import { v1 } from '../../common/types/ui_counters'; interface AnalyicsReporterConfig { localStorage: Storage; @@ -21,14 +22,15 @@ export function createReporter(config: AnalyicsReporterConfig): Reporter { return new Reporter({ debug, storage: localStorage, - async http(report) { + // not sure if these versioned-type related changes are strictly needed for defining the Reporter. + async http(report: v1.UiCountersHTTPRequestBody['report']) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const response = await fetch.post('/api/ui_counters/_report', { body: JSON.stringify({ report }), asSystemRequest: true, }); - - if (response.status !== 'ok') { + const okStatus: v1.UiCountersResponseOk = response.status; + if (response.status !== okStatus) { throw Error('Unable to store report.'); } return response; diff --git a/src/plugins/usage_collection/server/report/schema.ts b/src/plugins/usage_collection/server/report/schema.ts index 1f76d3a4db76d..259f893d5eaa5 100644 --- a/src/plugins/usage_collection/server/report/schema.ts +++ b/src/plugins/usage_collection/server/report/schema.ts @@ -43,5 +43,6 @@ export const reportSchema = schema.object({ application_usage: schema.maybe(schema.recordOf(schema.string(), applicationUsageReportSchema)), }); +// should the schema types also be versioned explicitly? export type ReportSchemaType = TypeOf; export type ApplicationUsageReport = TypeOf; diff --git a/src/plugins/usage_collection/server/routes/stats/stats.ts b/src/plugins/usage_collection/server/routes/stats/stats.ts index 242e93a7554e3..cb745768abe9f 100644 --- a/src/plugins/usage_collection/server/routes/stats/stats.ts +++ b/src/plugins/usage_collection/server/routes/stats/stats.ts @@ -9,7 +9,6 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { firstValueFrom, Observable } from 'rxjs'; - import { ElasticsearchClient, IRouter, @@ -17,15 +16,11 @@ import { ServiceStatus, ServiceStatusLevels, } from '@kbn/core/server'; +import { v1 } from '../../../common/types/stats'; + import { CollectorSet } from '../../collector'; const SNAPSHOT_REGEX = /-snapshot/i; -interface UsageObject { - kibana?: UsageObject; - xpack?: UsageObject; - [key: string]: unknown | UsageObject; -} - export function registerStatsRoute({ router, config, @@ -73,28 +68,23 @@ export function registerStatsRoute({ }, }, async (context, req, res) => { - const isExtended = req.query.extended === '' || req.query.extended; - const isLegacy = req.query.legacy === '' || req.query.legacy; + const requestQuery: v1.StatsHTTPQuery = req.query; + + const isExtended = requestQuery.extended === '' || requestQuery.extended; + const isLegacy = requestQuery.legacy === '' || requestQuery.legacy; let extended; + if (isExtended) { const core = await context.core; const { asCurrentUser } = core.elasticsearch.client; - - const usage = {} as UsageObject; + // as of https://github.com/elastic/kibana/pull/151082, usage will always be an empty object. const clusterUuid = await getClusterUuid(asCurrentUser); - - // In an effort to make telemetry more easily augmented, we need to ensure - // we can passthrough the data without every part of the process needing - // to know about the change; however, to support legacy use cases where this - // wasn't true, we need to be backwards compatible with how the legacy data - // looked and support those use cases here. - extended = isLegacy - ? { usage, clusterUuid } - : collectorSet.toApiFieldNames({ - usage, - clusterUuid, - }); + const extendedClusterUuid = isLegacy ? { clusterUuid } : { cluster_uuid: clusterUuid }; + extended = { + usage: {}, + extendedClusterUuid, + }; } // Guaranteed to resolve immediately due to replay effect on getOpsMetrics$ @@ -119,12 +109,12 @@ export function registerStatsRoute({ last_updated: collectedAt.toISOString(), collection_interval_in_millis: metrics.collectionInterval, }); - + const body: v1.StatsHTTPBodyTyped = { + ...kibanaStats, + ...extended, + }; return res.ok({ - body: { - ...kibanaStats, - ...extended, - }, + body, }); } ); diff --git a/src/plugins/usage_collection/server/routes/ui_counters.ts b/src/plugins/usage_collection/server/routes/ui_counters.ts index f4d7385195012..d87fb50b124a0 100644 --- a/src/plugins/usage_collection/server/routes/ui_counters.ts +++ b/src/plugins/usage_collection/server/routes/ui_counters.ts @@ -10,6 +10,7 @@ import { schema } from '@kbn/config-schema'; import { IRouter, ISavedObjectsRepository } from '@kbn/core/server'; import { storeReport, reportSchema } from '../report'; import { UsageCounter } from '../usage_counters'; +import { v1 } from '../../common/types/ui_counters'; export function registerUiCountersRoute( router: IRouter, @@ -26,16 +27,22 @@ export function registerUiCountersRoute( }, }, async (context, req, res) => { - const { report } = req.body; + const requestBody: v1.UiCountersHTTPRequestBody = req.body; try { const internalRepository = getSavedObjects(); if (!internalRepository) { throw Error(`The saved objects client hasn't been initialised yet`); } - await storeReport(internalRepository, uiCountersUsageCounter, report); - return res.ok({ body: { status: 'ok' } }); + await storeReport(internalRepository, uiCountersUsageCounter, requestBody.report); + const bodyOk: v1.UiCountersResponseOk = { + status: 'ok', + }; + return res.ok({ body: bodyOk }); } catch (error) { - return res.ok({ body: { status: 'fail' } }); + const bodyFail: v1.UiCountersResponseFail = { + status: 'fail', + }; + return res.ok({ body: bodyFail }); } } ); diff --git a/src/plugins/usage_collection/server/usage_counters/index.ts b/src/plugins/usage_collection/server/usage_counters/index.ts index cc1ee77ef3ea4..3ff122d8509de 100644 --- a/src/plugins/usage_collection/server/usage_counters/index.ts +++ b/src/plugins/usage_collection/server/usage_counters/index.ts @@ -8,7 +8,10 @@ export type { UsageCountersServiceSetup } from './usage_counters_service'; export type { UsageCountersSavedObjectAttributes, UsageCountersSavedObject } from './saved_objects'; -export type { IUsageCounter as UsageCounter, IncrementCounterParams } from './usage_counter'; +export type { IUsageCounter as UsageCounter } from './usage_counter'; + +import { v1 } from '../../common/types/usage_counters'; +export type IncrementCounterParams = v1.IncrementCounterParams; export { UsageCountersService } from './usage_counters_service'; export type { SerializeCounterParams } from './saved_objects'; diff --git a/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts b/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts index cb3c5e7683b16..40f92ea3a5e3a 100644 --- a/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts +++ b/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts @@ -8,7 +8,7 @@ import { serializeCounterKey, storeCounter } from './saved_objects'; import { savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; -import { CounterMetric } from './usage_counter'; +import { v1 } from '../../common/types/usage_counters'; import moment from 'moment'; describe('counterKey', () => { @@ -38,7 +38,7 @@ describe('storeCounter', () => { }); it('stores counter in a saved object', async () => { - const counterMetric: CounterMetric = { + const counterMetric: v1.CounterMetric = { domainId: 'a', counterName: 'b', counterType: 'c', diff --git a/src/plugins/usage_collection/server/usage_counters/saved_objects.ts b/src/plugins/usage_collection/server/usage_counters/saved_objects.ts index 701bbba404c49..615321a004a44 100644 --- a/src/plugins/usage_collection/server/usage_counters/saved_objects.ts +++ b/src/plugins/usage_collection/server/usage_counters/saved_objects.ts @@ -12,7 +12,7 @@ import type { SavedObjectsServiceSetup, } from '@kbn/core/server'; import moment from 'moment'; -import type { CounterMetric } from './usage_counter'; +import { v1 } from '../../common/types/usage_counters'; /** * The attributes stored in the UsageCounters' SavedObjects @@ -83,7 +83,7 @@ export const serializeCounterKey = ({ }; export const storeCounter = async ( - counterMetric: CounterMetric, + counterMetric: v1.CounterMetric, internalRepository: Pick ) => { const { counterName, counterType, domainId, incrementBy } = counterMetric; diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counter.test.ts b/src/plugins/usage_collection/server/usage_counters/usage_counter.test.ts index 3602ff1a29376..8bd35b85edc21 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counter.test.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counter.test.ts @@ -5,13 +5,14 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { UsageCounter, CounterMetric } from './usage_counter'; +import { UsageCounter } from './usage_counter'; import * as Rx from 'rxjs'; import * as rxOp from 'rxjs/operators'; +import { v1 } from '../../common/types/usage_counters'; describe('UsageCounter', () => { const domainId = 'test-domain-id'; - const counter$ = new Rx.Subject(); + const counter$ = new Rx.Subject(); const usageCounter = new UsageCounter({ domainId, counter$ }); afterAll(() => { diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counter.ts b/src/plugins/usage_collection/server/usage_counters/usage_counter.ts index b8057fdda8eb6..8ec006abb7553 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counter.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counter.ts @@ -7,29 +7,10 @@ */ import * as Rx from 'rxjs'; - -export interface CounterMetric { - domainId: string; - counterName: string; - counterType: string; - incrementBy: number; -} - +import { v1 } from '../../common/types/usage_counters'; export interface UsageCounterDeps { domainId: string; - counter$: Rx.Subject; -} - -/** - * Details about the counter to be incremented - */ -export interface IncrementCounterParams { - /** The name of the counter **/ - counterName: string; - /** The counter type ("count" by default) **/ - counterType?: string; - /** Increment the counter by this number (1 if not specified) **/ - incrementBy?: number; + counter$: Rx.Subject; } /** @@ -42,19 +23,19 @@ export interface IUsageCounter { * Notifies the counter about a new event happening so it can increase the count internally. * @param params {@link IncrementCounterParams} */ - incrementCounter: (params: IncrementCounterParams) => void; + incrementCounter: (params: v1.IncrementCounterParams) => void; } export class UsageCounter implements IUsageCounter { private domainId: string; - private counter$: Rx.Subject; + private counter$: Rx.Subject; constructor({ domainId, counter$ }: UsageCounterDeps) { this.domainId = domainId; this.counter$ = counter$; } - public incrementCounter = (params: IncrementCounterParams) => { + public incrementCounter = (params: v1.IncrementCounterParams) => { const { counterName, counterType = 'count', incrementBy = 1 } = params; this.counter$.next({ diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts index 095f314a8e80b..84326586732f4 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts @@ -16,7 +16,8 @@ import { import type { Logger, LogMeta } from '@kbn/core/server'; import moment from 'moment'; -import { CounterMetric, UsageCounter } from './usage_counter'; +import { UsageCounter } from './usage_counter'; +import { v1UsageCounters } from '../../common/types'; import { registerUsageCountersSavedObjectType, storeCounter, @@ -54,7 +55,7 @@ export class UsageCountersService { private readonly bufferDurationMs: number; private readonly counterSets = new Map(); - private readonly source$ = new Rx.Subject(); + private readonly source$ = new Rx.Subject(); // updates the types to specifically target what the HTTP API's require private readonly counter$ = this.source$.pipe(rxOp.multicast(new Rx.Subject()), rxOp.refCount()); private readonly flushCache$ = new Rx.Subject(); @@ -69,7 +70,7 @@ export class UsageCountersService { } public setup = (core: UsageCountersServiceSetupDeps): UsageCountersServiceSetup => { - const cache$ = new Rx.ReplaySubject(); + const cache$ = new Rx.ReplaySubject(); // updates the types to specifically target what the HTTP API's require const storingCache$ = new Rx.BehaviorSubject(false); // flush cache data from cache -> source this.flushCache$ @@ -134,8 +135,9 @@ export class UsageCountersService { this.stop$.next(); }; + // using updated types from the ones the HTTP API requires private storeDate$( - counters: CounterMetric[], + counters: v1UsageCounters.v1.CounterMetric[], internalRepository: Pick ) { return Rx.forkJoin( @@ -170,7 +172,10 @@ export class UsageCountersService { return this.counterSets.get(type); }; - private mergeCounters = (counters: CounterMetric[]): Record => { + // using updated types from the ones the HTTP API requires + private mergeCounters = ( + counters: v1UsageCounters.v1.CounterMetric[] + ): Record => { const date = moment.now(); return counters.reduce((acc, counter) => { const { counterName, domainId, counterType } = counter; @@ -188,6 +193,6 @@ export class UsageCountersService { incrementBy: existingCounter.incrementBy + counter.incrementBy, }, }; - }, {} as Record); + }, {} as Record); }; } diff --git a/src/plugins/usage_collection/tsconfig.json b/src/plugins/usage_collection/tsconfig.json index f6e360d80b3ad..becc176c0451e 100644 --- a/src/plugins/usage_collection/tsconfig.json +++ b/src/plugins/usage_collection/tsconfig.json @@ -7,7 +7,7 @@ "include": [ "public/**/*", "server/**/*", - "common/*", + "common/**/*", "../../../typings/**/*" ], "kbn_references": [ diff --git a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts new file mode 100644 index 0000000000000..1167766e6ab8c --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// / +declare const _default: Cypress.ConfigOptions; +export default _default; diff --git a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js new file mode 100644 index 0000000000000..4450c3f136a59 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +Object.defineProperty(exports, '__esModule', { value: true }); +const cypress_config_1 = require('@kbn/cypress-config'); +// eslint-disable-next-line @kbn/imports/no_boundary_crossing +const data_loaders_1 = require('./cypress/support/data_loaders'); +// eslint-disable-next-line import/no-default-export +exports.default = (0, cypress_config_1.defineCypressConfig)({ + defaultCommandTimeout: 60000, + execTimeout: 120000, + pageLoadTimeout: 12000, + retries: { + runMode: 1, + openMode: 0, + }, + screenshotsFolder: + '../../../target/kibana-security-solution/public/management/cypress/screenshots', + trashAssetsBeforeRuns: false, + video: false, + viewportHeight: 900, + viewportWidth: 1440, + experimentalStudio: true, + env: { + 'cypress-react-selector': { + root: '#security-solution-app', + }, + }, + e2e: { + baseUrl: 'http://localhost:5620', + supportFile: 'public/management/cypress/support/e2e.ts', + specPattern: 'public/management/cypress/e2e/endpoint/*.cy.{js,jsx,ts,tsx}', + experimentalRunAllSpecs: true, + setupNodeEvents(on, config) { + (0, data_loaders_1.dataLoaders)(on, config); + }, + }, +});