Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reporting] Migrate server-side usage collector #67233

Merged
merged 5 commits into from
May 27, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/reporting/server/legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Legacy } from 'kibana';
import { take } from 'rxjs/operators';
import { PluginInitializerContext } from 'src/core/server';
import { ReportingPluginSpecOptions } from '../';
import { LicensingPluginSetup } from '../../../../plugins/licensing/server';
import { PluginsSetup } from '../../../../plugins/reporting/server';
import { SecurityPluginSetup } from '../../../../plugins/security/server';
import { buildConfig } from './config';
Expand Down Expand Up @@ -43,6 +44,7 @@ export const legacyInit = async (
);
await pluginInstance.setup(coreSetup, {
elasticsearch: coreSetup.elasticsearch,
licensing: server.newPlatform.setup.plugins.licensing as LicensingPluginSetup,
security: server.newPlatform.setup.plugins.security as SecurityPluginSetup,
usageCollection: server.newPlatform.setup.plugins.usageCollection,
__LEGACY,
Expand Down
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/reporting/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as Rx from 'rxjs';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { DataPluginStart } from 'src/plugins/data/server/plugin';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
import { LicensingPluginSetup } from '../../../../plugins/licensing/server';
import { ReportingPluginSpecOptions } from '../';
import { CancellationToken } from '../../../../plugins/reporting/common';
import { JobStatus } from '../../../../plugins/reporting/common/types';
Expand Down Expand Up @@ -160,6 +161,7 @@ export type ScreenshotsObservableFn = ({

export interface ReportingSetupDeps {
elasticsearch: ElasticsearchServiceSetup;
licensing: LicensingPluginSetup;
security: SecurityPluginSetup;
usageCollection?: UsageCollectionSetup;
__LEGACY: LegacySetup;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { XPackMainPlugin } from '../../../xpack_main/server/xpack_main';
import { ExportTypesRegistry } from '../lib/export_types_registry';
import { FeaturesAvailability } from './';

/*
* Gets a handle to the Reporting export types registry and returns a few
Expand All @@ -21,10 +21,10 @@ export function getExportTypesHandler(exportTypesRegistry: ExportTypesRegistry)
* @param {Object} xpackInfo: xpack_main plugin info object
* @return {Object} availability of each export type
*/
getAvailability(xpackInfo: XPackMainPlugin['info']) {
getAvailability(featuresAvailability: FeaturesAvailability): { [exportType: string]: boolean } {
const exportTypesAvailability: { [exportType: string]: boolean } = {};
const xpackInfoAvailable = xpackInfo && xpackInfo.isAvailable();
const licenseType: string | undefined = xpackInfo.license.getType();
const xpackInfoAvailable = featuresAvailability && featuresAvailability.isAvailable();
const licenseType = featuresAvailability.license.getType();
if (!licenseType) {
throw new Error('No license type returned from XPackMainPlugin#info!');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import { get } from 'lodash';
import { CallCluster } from 'src/legacy/core_plugins/elasticsearch';
import { ReportingConfig } from '../';
import { XPackMainPlugin } from '../../../xpack_main/server/xpack_main';
import { ExportTypesRegistry } from '../lib/export_types_registry';
import { GetLicense } from './';
import { decorateRangeStats } from './decorate_range_stats';
import { getExportTypesHandler } from './get_export_type_handler';
import {
AggregationResultBuckets,
AppCounts,
Expand All @@ -21,10 +23,6 @@ import {
SearchResponse,
StatusByAppBucket,
} from './types';
import { decorateRangeStats } from './decorate_range_stats';
import { getExportTypesHandler } from './get_export_type_handler';

type XPackInfo = XPackMainPlugin['info'];

const JOB_TYPES_KEY = 'jobTypes';
const JOB_TYPES_FIELD = 'jobtype';
Expand Down Expand Up @@ -123,10 +121,10 @@ async function handleResponse(response: SearchResponse): Promise<Partial<RangeSt

export async function getReportingUsage(
config: ReportingConfig,
xpackMainInfo: XPackInfo,
getLicense: GetLicense,
callCluster: CallCluster,
exportTypesRegistry: ExportTypesRegistry
) {
): Promise<ReportingUsageType> {
const reportingIndex = config.get('index');

const params = {
Expand Down Expand Up @@ -170,6 +168,7 @@ export async function getReportingUsage(
},
};

const featureAvailability = await getLicense();
return callCluster('search', params)
.then((response: SearchResponse) => handleResponse(response))
.then(
Expand All @@ -180,7 +179,7 @@ export async function getReportingUsage(

const exportTypesHandler = getExportTypesHandler(exportTypesRegistry);
const availability = exportTypesHandler.getAvailability(
xpackMainInfo
featureAvailability
) as FeatureAvailabilityMap;

const { last7Days, ...all } = usage;
Expand Down
9 changes: 9 additions & 0 deletions x-pack/legacy/plugins/reporting/server/usage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { LicenseType } from '../../../../../plugins/licensing/server';

export interface FeaturesAvailability {
isAvailable: () => boolean;
license: {
getType: () => LicenseType | undefined;
};
}
export type GetLicense = () => Promise<FeaturesAvailability>;
export { registerReportingUsageCollector } from './reporting_usage_collector';
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@
* you may not use this file except in compliance with the Elastic License.
*/

import * as Rx from 'rxjs';
import sinon from 'sinon';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
import { ReportingConfig } from '../';
import { createMockReportingCore } from '../../test_helpers';
import { getExportTypesRegistry } from '../lib/export_types_registry';
import { ReportingUsageType, SearchResponse } from './types';
import { ReportingSetupDeps } from '../types';
import { FeaturesAvailability } from './';
import {
getReportingUsageCollector,
registerReportingUsageCollector,
} from './reporting_usage_collector';
import { ReportingUsageType, SearchResponse } from './types';

const exportTypesRegistry = getExportTypesRegistry();

Expand All @@ -32,30 +36,22 @@ function getMockUsageCollection() {
};
}

const getLicenseMock = (licenseType = 'platinum') => () => {
return Promise.resolve({
isAvailable: () => true,
license: { getType: () => licenseType },
} as FeaturesAvailability);
};

function getPluginsMock(
{ license, usageCollection = getMockUsageCollection() } = { license: 'platinum' }
) {
const mockXpackMain = {
info: {
isAvailable: sinon.stub().returns(true),
feature: () => ({
getLicenseCheckResults: sinon.stub(),
}),
license: {
isOneOf: sinon.stub().returns(false),
getType: sinon.stub().returns(license),
},
toJSON: () => ({ b: 1 }),
},
};
return {
return ({
licensing: { license$: Rx.of(getLicenseMock(license)) },
usageCollection,
__LEGACY: {
plugins: {
xpack_main: mockXpackMain,
},
},
} as any;
elasticsearch: {},
security: {},
} as unknown) as ReportingSetupDeps & { usageCollection: UsageCollectionSetup };
}

const getMockReportingConfig = () => ({
Expand All @@ -78,7 +74,7 @@ describe('license checks', () => {
const { fetch } = getReportingUsageCollector(
mockConfig,
plugins.usageCollection,
plugins.__LEGACY.plugins.xpack_main.info,
getLicenseMock('basic'),
exportTypesRegistry,
function isReady() {
return Promise.resolve(true);
Expand Down Expand Up @@ -108,7 +104,7 @@ describe('license checks', () => {
const { fetch } = getReportingUsageCollector(
mockConfig,
plugins.usageCollection,
plugins.__LEGACY.plugins.xpack_main.info,
getLicenseMock('none'),
exportTypesRegistry,
function isReady() {
return Promise.resolve(true);
Expand Down Expand Up @@ -138,7 +134,7 @@ describe('license checks', () => {
const { fetch } = getReportingUsageCollector(
mockConfig,
plugins.usageCollection,
plugins.__LEGACY.plugins.xpack_main.info,
getLicenseMock('platinum'),
exportTypesRegistry,
function isReady() {
return Promise.resolve(true);
Expand Down Expand Up @@ -168,7 +164,7 @@ describe('license checks', () => {
const { fetch } = getReportingUsageCollector(
mockConfig,
plugins.usageCollection,
plugins.__LEGACY.plugins.xpack_main.info,
getLicenseMock('basic'),
exportTypesRegistry,
function isReady() {
return Promise.resolve(true);
Expand All @@ -194,7 +190,7 @@ describe('data modeling', () => {
const { fetch } = getReportingUsageCollector(
mockConfig,
plugins.usageCollection,
plugins.__LEGACY.plugins.xpack_main.info,
getLicenseMock(),
exportTypesRegistry,
function isReady() {
return Promise.resolve(true);
Expand Down Expand Up @@ -247,7 +243,7 @@ describe('data modeling', () => {
const { fetch } = getReportingUsageCollector(
mockConfig,
plugins.usageCollection,
plugins.__LEGACY.plugins.xpack_main.info,
getLicenseMock(),
exportTypesRegistry,
function isReady() {
return Promise.resolve(true);
Expand Down Expand Up @@ -300,7 +296,7 @@ describe('data modeling', () => {
const { fetch } = getReportingUsageCollector(
mockConfig,
plugins.usageCollection,
plugins.__LEGACY.plugins.xpack_main.info,
getLicenseMock(),
exportTypesRegistry,
function isReady() {
return Promise.resolve(true);
Expand Down Expand Up @@ -461,7 +457,7 @@ describe('Ready for collection observable', () => {
const makeCollectorSpy = sinon.spy();
usageCollection.makeUsageCollector = makeCollectorSpy;

const plugins = getPluginsMock({ usageCollection } as any);
const plugins = getPluginsMock({ usageCollection, license: 'platinum' });
registerReportingUsageCollector(mockReporting, plugins);

const [args] = makeCollectorSpy.firstCall.args;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { first, map } from 'rxjs/operators';
import { CallCluster } from 'src/legacy/core_plugins/elasticsearch';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
import { XPackMainPlugin } from '../../../xpack_main/server/xpack_main';
import { ReportingCore } from '../';
import { KIBANA_REPORTING_TYPE } from '../../common/constants';
import { ReportingConfig, ReportingCore } from '../../server';
import { ReportingSetupDeps } from '../../server/types';
import { ReportingConfig } from '../../server';
import { ExportTypesRegistry } from '../lib/export_types_registry';
import { RangeStats } from './types';
import { ReportingSetupDeps } from '../types';
import { GetLicense } from './';
import { getReportingUsage } from './get_reporting_usage';

type XPackInfo = XPackMainPlugin['info'];
import { RangeStats } from './types';

// places the reporting data as kibana stats
const METATYPE = 'kibana_stats';
Expand All @@ -25,14 +25,14 @@ const METATYPE = 'kibana_stats';
export function getReportingUsageCollector(
config: ReportingConfig,
usageCollection: UsageCollectionSetup,
xpackMainInfo: XPackInfo,
getLicense: GetLicense,
exportTypesRegistry: ExportTypesRegistry,
isReady: () => Promise<boolean>
) {
return usageCollection.makeUsageCollector({
type: KIBANA_REPORTING_TYPE,
fetch: (callCluster: CallCluster) =>
getReportingUsage(config, xpackMainInfo, callCluster, exportTypesRegistry),
getReportingUsage(config, getLicense, callCluster, exportTypesRegistry),
isReady,

/*
Expand All @@ -57,23 +57,35 @@ export function getReportingUsageCollector(

export function registerReportingUsageCollector(
reporting: ReportingCore,
plugins: ReportingSetupDeps
) {
if (!plugins.usageCollection) {
{ licensing, usageCollection }: ReportingSetupDeps
): void {
if (!usageCollection) {
return;
}
const xpackMainInfo = plugins.__LEGACY.plugins.xpack_main.info;

const config = reporting.getConfig();
const exportTypesRegistry = reporting.getExportTypesRegistry();
const getLicense = async () => {
return await licensing.license$
.pipe(
map(({ isAvailable, type }) => ({
Copy link
Member Author

@tsullivan tsullivan May 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FeaturesAvailable type being implemented here carries over the shape of the data from the Legacy xpack_main. This is done to avoid needing extra changes for underlying code.

isAvailable: () => isAvailable,
license: {
getType: () => type,
},
})),
first()
)
.toPromise();
};
const collectionIsReady = reporting.pluginHasStarted.bind(reporting);
const config = reporting.getConfig();

const collector = getReportingUsageCollector(
config,
plugins.usageCollection,
xpackMainInfo,
usageCollection,
getLicense,
exportTypesRegistry,
collectionIsReady
);
plugins.usageCollection.registerCollector(collector);
usageCollection.registerCollector(collector);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const createMockSetupDeps = (setupMock?: any): ReportingSetupDeps => {
return {
elasticsearch: setupMock.elasticsearch,
security: setupMock.security,
licensing: {} as any,
usageCollection: {} as any,
__LEGACY: { plugins: { xpack_main: { status: new EventEmitter() } } } as any,
};
Expand Down