mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[GET /api/status] Default to v8format and allow v7format=true (#110830)
This commit is contained in:
parent
4e9e7a8671
commit
dfea0fee21
39 changed files with 412 additions and 226 deletions
|
@ -31,10 +31,10 @@ async function getDeprecations({ esClient, savedObjectsClient }: GetDeprecations
|
|||
// Example of a manual correctiveAction
|
||||
deprecations.push({
|
||||
title: i18n.translate('xpack.timelion.deprecations.worksheetsTitle', {
|
||||
defaultMessage: 'Found Timelion worksheets.'
|
||||
defaultMessage: 'Timelion worksheets are deprecated'
|
||||
}),
|
||||
message: i18n.translate('xpack.timelion.deprecations.worksheetsMessage', {
|
||||
defaultMessage: 'You have {count} Timelion worksheets. The Timelion app will be removed in 8.0. To continue using your Timelion worksheets, migrate them to a dashboard.',
|
||||
defaultMessage: 'You have {count} Timelion worksheets. Migrate your Timelion worksheets to a dashboard to continue using them.',
|
||||
values: { count },
|
||||
}),
|
||||
documentationUrl:
|
||||
|
|
|
@ -8,26 +8,14 @@
|
|||
|
||||
import { KbnClientStatus } from './kbn_client_status';
|
||||
|
||||
const PLUGIN_STATUS_ID = /^plugin:(.+?)@/;
|
||||
|
||||
export class KbnClientPlugins {
|
||||
constructor(private readonly status: KbnClientStatus) {}
|
||||
/**
|
||||
* Get a list of plugin ids that are enabled on the server
|
||||
*/
|
||||
public async getEnabledIds() {
|
||||
const pluginIds: string[] = [];
|
||||
const apiResp = await this.status.get();
|
||||
|
||||
for (const status of apiResp.status.statuses) {
|
||||
if (status.id) {
|
||||
const match = status.id.match(PLUGIN_STATUS_ID);
|
||||
if (match) {
|
||||
pluginIds.push(match[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pluginIds;
|
||||
return Object.keys(apiResp.status.plugins);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,11 @@
|
|||
import { KbnClientRequester } from './kbn_client_requester';
|
||||
|
||||
interface Status {
|
||||
state: 'green' | 'red' | 'yellow';
|
||||
title?: string;
|
||||
id?: string;
|
||||
icon: string;
|
||||
message: string;
|
||||
uiColor: string;
|
||||
since: string;
|
||||
level: 'available' | 'degraded' | 'unavailable' | 'critical';
|
||||
summary: string;
|
||||
detail?: string;
|
||||
documentationUrl?: string;
|
||||
meta?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
interface ApiResponseStatus {
|
||||
|
@ -29,7 +27,8 @@ interface ApiResponseStatus {
|
|||
};
|
||||
status: {
|
||||
overall: Status;
|
||||
statuses: Status[];
|
||||
core: Record<string, Status>;
|
||||
plugins: Record<string, Status>;
|
||||
};
|
||||
metrics: unknown;
|
||||
}
|
||||
|
@ -55,6 +54,6 @@ export class KbnClientStatus {
|
|||
*/
|
||||
public async getOverallState() {
|
||||
const status = await this.get();
|
||||
return status.status.overall.state;
|
||||
return status.status.overall.level;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ export async function loadStatus({
|
|||
let response: StatusResponse;
|
||||
|
||||
try {
|
||||
response = await http.get('/api/status', { query: { v8format: true } });
|
||||
response = await http.get('/api/status');
|
||||
} catch (e) {
|
||||
// API returns a 503 response if not all services are available.
|
||||
// In this case, we want to treat this as a successful API call, so that we can
|
||||
|
|
|
@ -10,12 +10,14 @@ import { PublicMethodsOf } from '@kbn/utility-types';
|
|||
import { BehaviorSubject } from 'rxjs';
|
||||
import { CoreUsageDataService } from './core_usage_data_service';
|
||||
import { coreUsageStatsClientMock } from './core_usage_stats_client.mock';
|
||||
import { CoreUsageData, CoreUsageDataSetup, CoreUsageDataStart } from './types';
|
||||
import { CoreUsageData, InternalCoreUsageDataSetup, CoreUsageDataStart } from './types';
|
||||
|
||||
const createSetupContractMock = (usageStatsClient = coreUsageStatsClientMock.create()) => {
|
||||
const setupContract: jest.Mocked<CoreUsageDataSetup> = {
|
||||
const setupContract: jest.Mocked<InternalCoreUsageDataSetup> = {
|
||||
registerType: jest.fn(),
|
||||
getClient: jest.fn().mockReturnValue(usageStatsClient),
|
||||
registerUsageCounter: jest.fn(),
|
||||
incrementUsageCounter: jest.fn(),
|
||||
};
|
||||
return setupContract;
|
||||
};
|
||||
|
|
|
@ -150,6 +150,50 @@ describe('CoreUsageDataService', () => {
|
|||
expect(usageStatsClient).toBeInstanceOf(CoreUsageStatsClient);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Usage Counter', () => {
|
||||
it('registers a usage counter and uses it to increment the counters', async () => {
|
||||
const http = httpServiceMock.createInternalSetupContract();
|
||||
const metrics = metricsServiceMock.createInternalSetupContract();
|
||||
const savedObjectsStartPromise = Promise.resolve(
|
||||
savedObjectsServiceMock.createStartContract()
|
||||
);
|
||||
const changedDeprecatedConfigPath$ = configServiceMock.create().getDeprecatedConfigPath$();
|
||||
const coreUsageData = service.setup({
|
||||
http,
|
||||
metrics,
|
||||
savedObjectsStartPromise,
|
||||
changedDeprecatedConfigPath$,
|
||||
});
|
||||
const myUsageCounter = { incrementCounter: jest.fn() };
|
||||
coreUsageData.registerUsageCounter(myUsageCounter);
|
||||
coreUsageData.incrementUsageCounter({ counterName: 'test' });
|
||||
expect(myUsageCounter.incrementCounter).toHaveBeenCalledWith({ counterName: 'test' });
|
||||
});
|
||||
|
||||
it('swallows errors when provided increment counter fails', async () => {
|
||||
const http = httpServiceMock.createInternalSetupContract();
|
||||
const metrics = metricsServiceMock.createInternalSetupContract();
|
||||
const savedObjectsStartPromise = Promise.resolve(
|
||||
savedObjectsServiceMock.createStartContract()
|
||||
);
|
||||
const changedDeprecatedConfigPath$ = configServiceMock.create().getDeprecatedConfigPath$();
|
||||
const coreUsageData = service.setup({
|
||||
http,
|
||||
metrics,
|
||||
savedObjectsStartPromise,
|
||||
changedDeprecatedConfigPath$,
|
||||
});
|
||||
const myUsageCounter = {
|
||||
incrementCounter: jest.fn(() => {
|
||||
throw new Error('Something is really wrong');
|
||||
}),
|
||||
};
|
||||
coreUsageData.registerUsageCounter(myUsageCounter);
|
||||
expect(() => coreUsageData.incrementUsageCounter({ counterName: 'test' })).not.toThrow();
|
||||
expect(myUsageCounter.incrementCounter).toHaveBeenCalledWith({ counterName: 'test' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('start', () => {
|
||||
|
|
|
@ -27,7 +27,7 @@ import type {
|
|||
CoreServicesUsageData,
|
||||
CoreUsageData,
|
||||
CoreUsageDataStart,
|
||||
CoreUsageDataSetup,
|
||||
InternalCoreUsageDataSetup,
|
||||
ConfigUsageData,
|
||||
CoreConfigUsageData,
|
||||
} from './types';
|
||||
|
@ -39,6 +39,7 @@ import { LEGACY_URL_ALIAS_TYPE } from '../saved_objects/object_types';
|
|||
import { CORE_USAGE_STATS_TYPE } from './constants';
|
||||
import { CoreUsageStatsClient } from './core_usage_stats_client';
|
||||
import { MetricsServiceSetup, OpsMetrics } from '..';
|
||||
import { CoreIncrementUsageCounter } from './types';
|
||||
|
||||
export type ExposedConfigsToUsage = Map<string, Record<string, boolean>>;
|
||||
|
||||
|
@ -86,7 +87,8 @@ const isCustomIndex = (index: string) => {
|
|||
return index !== '.kibana';
|
||||
};
|
||||
|
||||
export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, CoreUsageDataStart> {
|
||||
export class CoreUsageDataService
|
||||
implements CoreService<InternalCoreUsageDataSetup, CoreUsageDataStart> {
|
||||
private logger: Logger;
|
||||
private elasticsearchConfig?: ElasticsearchConfigType;
|
||||
private configService: CoreContext['configService'];
|
||||
|
@ -98,6 +100,7 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
|
|||
private kibanaConfig?: KibanaConfigType;
|
||||
private coreUsageStatsClient?: CoreUsageStatsClient;
|
||||
private deprecatedConfigPaths: ChangedDeprecatedPaths = { set: [], unset: [] };
|
||||
private incrementUsageCounter: CoreIncrementUsageCounter = () => {}; // Initially set to noop
|
||||
|
||||
constructor(core: CoreContext) {
|
||||
this.logger = core.logger.get('core-usage-stats-service');
|
||||
|
@ -495,7 +498,24 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
|
|||
|
||||
this.coreUsageStatsClient = getClient();
|
||||
|
||||
return { registerType, getClient } as CoreUsageDataSetup;
|
||||
const contract: InternalCoreUsageDataSetup = {
|
||||
registerType,
|
||||
getClient,
|
||||
registerUsageCounter: (usageCounter) => {
|
||||
this.incrementUsageCounter = (params) => usageCounter.incrementCounter(params);
|
||||
},
|
||||
incrementUsageCounter: (params) => {
|
||||
try {
|
||||
this.incrementUsageCounter(params);
|
||||
} catch (e) {
|
||||
// Self-defense mechanism since the handler is externally registered
|
||||
this.logger.debug('Failed to increase the usage counter');
|
||||
this.logger.debug(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return contract;
|
||||
}
|
||||
|
||||
start({ savedObjects, elasticsearch, exposedConfigsToUsage }: StartDeps) {
|
||||
|
|
|
@ -7,7 +7,15 @@
|
|||
*/
|
||||
|
||||
export { CORE_USAGE_STATS_TYPE, CORE_USAGE_STATS_ID } from './constants';
|
||||
export type { CoreUsageDataSetup, ConfigUsageData, CoreUsageDataStart } from './types';
|
||||
export type {
|
||||
InternalCoreUsageDataSetup,
|
||||
ConfigUsageData,
|
||||
CoreUsageDataStart,
|
||||
CoreUsageDataSetup,
|
||||
CoreUsageCounter,
|
||||
CoreIncrementUsageCounter,
|
||||
CoreIncrementCounterParams,
|
||||
} from './types';
|
||||
export { CoreUsageDataService } from './core_usage_data_service';
|
||||
export { CoreUsageStatsClient, REPOSITORY_RESOLVE_OUTCOME_STATS } from './core_usage_stats_client';
|
||||
|
||||
|
|
|
@ -280,12 +280,59 @@ export interface CoreConfigUsageData {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Details about the counter to be incremented
|
||||
*/
|
||||
export interface CoreIncrementCounterParams {
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Method to call whenever an event occurs, so the counter can be increased.
|
||||
*/
|
||||
export type CoreIncrementUsageCounter = (params: CoreIncrementCounterParams) => void;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* API to track whenever an event occurs, so the core can report them.
|
||||
*/
|
||||
export interface CoreUsageCounter {
|
||||
/** @internal {@link CoreIncrementUsageCounter} **/
|
||||
incrementCounter: CoreIncrementUsageCounter;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface CoreUsageDataSetup {
|
||||
export interface InternalCoreUsageDataSetup extends CoreUsageDataSetup {
|
||||
registerType(
|
||||
typeRegistry: ISavedObjectTypeRegistry & Pick<SavedObjectTypeRegistry, 'registerType'>
|
||||
): void;
|
||||
getClient(): CoreUsageStatsClient;
|
||||
|
||||
/** @internal {@link CoreIncrementUsageCounter} **/
|
||||
incrementUsageCounter: CoreIncrementUsageCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal API for registering the Usage Tracker used for Core's usage data payload.
|
||||
*
|
||||
* @note This API should never be used to drive application logic and is only
|
||||
* intended for telemetry purposes.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface CoreUsageDataSetup {
|
||||
/**
|
||||
* @internal
|
||||
* API for a usage tracker plugin to inject the {@link CoreUsageCounter} to use
|
||||
* when tracking events.
|
||||
*/
|
||||
registerUsageCounter: (usageCounter: CoreUsageCounter) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -96,8 +96,8 @@ describe('fake elasticsearch', () => {
|
|||
|
||||
test('should return unknown product when it cannot perform the Product check (503 response)', async () => {
|
||||
const resp = await supertest(kibanaHttpServer).get('/api/status').expect(503);
|
||||
expect(resp.body.status.overall.state).toBe('red');
|
||||
expect(resp.body.status.statuses[0].message).toBe(
|
||||
expect(resp.body.status.overall.level).toBe('critical');
|
||||
expect(resp.body.status.core.elasticsearch.summary).toBe(
|
||||
'Unable to retrieve version information from Elasticsearch nodes. The client noticed that the server is not Elasticsearch and we do not support this unknown product.'
|
||||
);
|
||||
});
|
||||
|
|
|
@ -55,7 +55,7 @@ import { CapabilitiesSetup, CapabilitiesStart } from './capabilities';
|
|||
import { MetricsServiceSetup, MetricsServiceStart } from './metrics';
|
||||
import { StatusServiceSetup } from './status';
|
||||
import { AppenderConfigType, appendersSchema, LoggingServiceSetup } from './logging';
|
||||
import { CoreUsageDataStart } from './core_usage_data';
|
||||
import { CoreUsageDataStart, CoreUsageDataSetup } from './core_usage_data';
|
||||
import { I18nServiceSetup } from './i18n';
|
||||
import { DeprecationsServiceSetup, DeprecationsClient } from './deprecations';
|
||||
// Because of #79265 we need to explicitly import, then export these types for
|
||||
|
@ -410,7 +410,13 @@ export type {
|
|||
export { ServiceStatusLevels } from './status';
|
||||
export type { CoreStatus, ServiceStatus, ServiceStatusLevel, StatusServiceSetup } from './status';
|
||||
|
||||
export type { CoreUsageDataStart } from './core_usage_data';
|
||||
export type {
|
||||
CoreUsageDataSetup,
|
||||
CoreUsageDataStart,
|
||||
CoreUsageCounter,
|
||||
CoreIncrementUsageCounter,
|
||||
CoreIncrementCounterParams,
|
||||
} from './core_usage_data';
|
||||
|
||||
/**
|
||||
* Plugin specific context passed to a route handler.
|
||||
|
@ -500,6 +506,8 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
|
|||
deprecations: DeprecationsServiceSetup;
|
||||
/** {@link StartServicesAccessor} */
|
||||
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
|
||||
/** @internal {@link CoreUsageDataSetup} */
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,7 +36,7 @@ import { InternalRenderingServiceSetup } from './rendering';
|
|||
import { InternalHttpResourcesPreboot, InternalHttpResourcesSetup } from './http_resources';
|
||||
import { InternalStatusServiceSetup } from './status';
|
||||
import { InternalLoggingServicePreboot, InternalLoggingServiceSetup } from './logging';
|
||||
import { CoreUsageDataStart } from './core_usage_data';
|
||||
import { CoreUsageDataStart, InternalCoreUsageDataSetup } from './core_usage_data';
|
||||
import { I18nServiceSetup } from './i18n';
|
||||
import { InternalDeprecationsServiceSetup, InternalDeprecationsServiceStart } from './deprecations';
|
||||
import type {
|
||||
|
@ -73,6 +73,7 @@ export interface InternalCoreSetup {
|
|||
logging: InternalLoggingServiceSetup;
|
||||
metrics: InternalMetricsServiceSetup;
|
||||
deprecations: InternalDeprecationsServiceSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -169,6 +169,9 @@ function createCoreSetupMock({
|
|||
metrics: metricsServiceMock.createSetupContract(),
|
||||
deprecations: deprecationsServiceMock.createSetupContract(),
|
||||
executionContext: executionContextServiceMock.createInternalSetupContract(),
|
||||
coreUsageData: {
|
||||
registerUsageCounter: coreUsageDataServiceMock.createSetupContract().registerUsageCounter,
|
||||
},
|
||||
getStartServices: jest
|
||||
.fn<Promise<[ReturnType<typeof createCoreStartMock>, object, any]>, []>()
|
||||
.mockResolvedValue([createCoreStartMock(), pluginStartDeps, pluginStartContract]),
|
||||
|
@ -222,6 +225,7 @@ function createInternalCoreSetupMock() {
|
|||
metrics: metricsServiceMock.createInternalSetupContract(),
|
||||
deprecations: deprecationsServiceMock.createInternalSetupContract(),
|
||||
executionContext: executionContextServiceMock.createInternalSetupContract(),
|
||||
coreUsageData: coreUsageDataServiceMock.createSetupContract(),
|
||||
};
|
||||
return setupDeps;
|
||||
}
|
||||
|
|
|
@ -211,6 +211,9 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>(
|
|||
},
|
||||
getStartServices: () => plugin.startDependencies,
|
||||
deprecations: deps.deprecations.getRegistry(plugin.name),
|
||||
coreUsageData: {
|
||||
registerUsageCounter: deps.coreUsageData.registerUsageCounter,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerBulkCreateRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerBulkGetRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerBulkUpdateRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerCreateRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerDeleteRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -11,7 +11,7 @@ import stringify from 'json-stable-stringify';
|
|||
import { createPromiseFromStreams, createMapStream, createConcatStream } from '@kbn/utils';
|
||||
|
||||
import { IRouter, KibanaRequest } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { SavedObjectConfig } from '../saved_objects_config';
|
||||
import {
|
||||
SavedObjectsExportByTypeOptions,
|
||||
|
@ -22,7 +22,7 @@ import { validateTypes, validateObjects, catchAndReturnBoomErrors } from './util
|
|||
|
||||
interface RouteDependencies {
|
||||
config: SavedObjectConfig;
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
type EitherExportOptions = SavedObjectsExportByTypeOptions | SavedObjectsExportByObjectOptions;
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerFindRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerGetRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -10,14 +10,14 @@ import { Readable } from 'stream';
|
|||
import { extname } from 'path';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { SavedObjectConfig } from '../saved_objects_config';
|
||||
import { SavedObjectsImportError } from '../import';
|
||||
import { catchAndReturnBoomErrors, createSavedObjectsStreamFromNdJson } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
config: SavedObjectConfig;
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
interface FileStream extends Readable {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { InternalHttpServiceSetup } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { Logger } from '../../logging';
|
||||
import { SavedObjectConfig } from '../saved_objects_config';
|
||||
import { IKibanaMigrator } from '../migrations';
|
||||
|
@ -34,7 +34,7 @@ export function registerRoutes({
|
|||
migratorPromise,
|
||||
}: {
|
||||
http: InternalHttpServiceSetup;
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
logger: Logger;
|
||||
config: SavedObjectConfig;
|
||||
migratorPromise: Promise<IKibanaMigrator>;
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerResolveRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -11,13 +11,13 @@ import { Readable } from 'stream';
|
|||
import { schema } from '@kbn/config-schema';
|
||||
import { chain } from 'lodash';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { SavedObjectConfig } from '../saved_objects_config';
|
||||
import { SavedObjectsImportError } from '../import';
|
||||
import { catchAndReturnBoomErrors, createSavedObjectsStreamFromNdJson } from './utils';
|
||||
interface RouteDependencies {
|
||||
config: SavedObjectConfig;
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
interface FileStream extends Readable {
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
|
||||
import type { SavedObjectsUpdateOptions } from '../service/saved_objects_client';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
export const registerUpdateRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from './';
|
||||
import { KibanaMigrator, IKibanaMigrator } from './migrations';
|
||||
import { CoreContext } from '../core_context';
|
||||
import { CoreUsageDataSetup } from '../core_usage_data';
|
||||
import { InternalCoreUsageDataSetup } from '../core_usage_data';
|
||||
import {
|
||||
ElasticsearchClient,
|
||||
InternalElasticsearchServiceSetup,
|
||||
|
@ -250,7 +250,7 @@ export interface SavedObjectsRepositoryFactory {
|
|||
export interface SavedObjectsSetupDeps {
|
||||
http: InternalHttpServiceSetup;
|
||||
elasticsearch: InternalElasticsearchServiceSetup;
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
}
|
||||
|
||||
interface WrappedClientFactoryWrapper {
|
||||
|
|
|
@ -359,6 +359,16 @@ export interface CoreEnvironmentUsageData {
|
|||
// @internal (undocumented)
|
||||
export type CoreId = symbol;
|
||||
|
||||
// @internal
|
||||
export interface CoreIncrementCounterParams {
|
||||
counterName: string;
|
||||
counterType?: string;
|
||||
incrementBy?: number;
|
||||
}
|
||||
|
||||
// @internal
|
||||
export type CoreIncrementUsageCounter = (params: CoreIncrementCounterParams) => void;
|
||||
|
||||
// @public
|
||||
export interface CorePreboot {
|
||||
// (undocumented)
|
||||
|
@ -395,6 +405,8 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
|
|||
capabilities: CapabilitiesSetup;
|
||||
// (undocumented)
|
||||
context: ContextSetup;
|
||||
// @internal (undocumented)
|
||||
coreUsageData: CoreUsageDataSetup;
|
||||
// (undocumented)
|
||||
deprecations: DeprecationsServiceSetup;
|
||||
// (undocumented)
|
||||
|
@ -449,6 +461,12 @@ export interface CoreStatus {
|
|||
savedObjects: ServiceStatus;
|
||||
}
|
||||
|
||||
// @internal
|
||||
export interface CoreUsageCounter {
|
||||
// (undocumented)
|
||||
incrementCounter: CoreIncrementUsageCounter;
|
||||
}
|
||||
|
||||
// @internal
|
||||
export interface CoreUsageData extends CoreUsageStats {
|
||||
// (undocumented)
|
||||
|
@ -459,6 +477,11 @@ export interface CoreUsageData extends CoreUsageStats {
|
|||
services: CoreServicesUsageData;
|
||||
}
|
||||
|
||||
// @internal
|
||||
export interface CoreUsageDataSetup {
|
||||
registerUsageCounter: (usageCounter: CoreUsageCounter) => void;
|
||||
}
|
||||
|
||||
// @internal
|
||||
export interface CoreUsageDataStart {
|
||||
// (undocumented)
|
||||
|
|
|
@ -243,6 +243,7 @@ export class Server {
|
|||
environment: environmentSetup,
|
||||
http: httpSetup,
|
||||
metrics: metricsSetup,
|
||||
coreUsageData: coreUsageDataSetup,
|
||||
});
|
||||
|
||||
const renderingSetup = await this.rendering.setup({
|
||||
|
@ -278,6 +279,7 @@ export class Server {
|
|||
logging: loggingSetup,
|
||||
metrics: metricsSetup,
|
||||
deprecations: deprecationsSetup,
|
||||
coreUsageData: coreUsageDataSetup,
|
||||
};
|
||||
|
||||
const pluginsSetup = await this.plugins.setup(coreSetup);
|
||||
|
|
|
@ -29,6 +29,7 @@ describe('GET /api/status', () => {
|
|||
let server: HttpService;
|
||||
let httpSetup: InternalHttpServiceSetup;
|
||||
let metrics: jest.Mocked<MetricsServiceSetup>;
|
||||
let incrementUsageCounter: jest.Mock;
|
||||
|
||||
const setupServer = async ({ allowAnonymous = true }: { allowAnonymous?: boolean } = {}) => {
|
||||
const coreContext = createCoreContext({ coreId });
|
||||
|
@ -50,6 +51,8 @@ describe('GET /api/status', () => {
|
|||
d: { level: ServiceStatusLevels.critical, summary: 'd is critical' },
|
||||
});
|
||||
|
||||
incrementUsageCounter = jest.fn();
|
||||
|
||||
const router = httpSetup.createRouter('');
|
||||
registerStatusRoute({
|
||||
router,
|
||||
|
@ -71,6 +74,7 @@ describe('GET /api/status', () => {
|
|||
core$: status.core$,
|
||||
plugins$: pluginsStatus$,
|
||||
},
|
||||
incrementUsageCounter,
|
||||
});
|
||||
|
||||
// Register dummy auth provider for testing auth
|
||||
|
@ -137,69 +141,75 @@ describe('GET /api/status', () => {
|
|||
});
|
||||
|
||||
describe('legacy status format', () => {
|
||||
it('returns legacy status format when no query params provided', async () => {
|
||||
await setupServer();
|
||||
const result = await supertest(httpSetup.server.listener).get('/api/status').expect(200);
|
||||
expect(result.body.status).toEqual({
|
||||
overall: {
|
||||
const legacyFormat = {
|
||||
overall: {
|
||||
icon: 'success',
|
||||
nickname: 'Looking good',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
title: 'Green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
statuses: [
|
||||
{
|
||||
icon: 'success',
|
||||
nickname: 'Looking good',
|
||||
id: 'core:elasticsearch@9.9.9',
|
||||
message: 'Service is working',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
title: 'Green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
statuses: [
|
||||
{
|
||||
icon: 'success',
|
||||
id: 'core:elasticsearch@9.9.9',
|
||||
message: 'Service is working',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
{
|
||||
icon: 'success',
|
||||
id: 'core:savedObjects@9.9.9',
|
||||
message: 'Service is working',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
{
|
||||
icon: 'success',
|
||||
id: 'plugin:a@9.9.9',
|
||||
message: 'a is available',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
{
|
||||
icon: 'warning',
|
||||
id: 'plugin:b@9.9.9',
|
||||
message: 'b is degraded',
|
||||
since: expect.any(String),
|
||||
state: 'yellow',
|
||||
uiColor: 'warning',
|
||||
},
|
||||
{
|
||||
icon: 'danger',
|
||||
id: 'plugin:c@9.9.9',
|
||||
message: 'c is unavailable',
|
||||
since: expect.any(String),
|
||||
state: 'red',
|
||||
uiColor: 'danger',
|
||||
},
|
||||
{
|
||||
icon: 'danger',
|
||||
id: 'plugin:d@9.9.9',
|
||||
message: 'd is critical',
|
||||
since: expect.any(String),
|
||||
state: 'red',
|
||||
uiColor: 'danger',
|
||||
},
|
||||
],
|
||||
});
|
||||
{
|
||||
icon: 'success',
|
||||
id: 'core:savedObjects@9.9.9',
|
||||
message: 'Service is working',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
{
|
||||
icon: 'success',
|
||||
id: 'plugin:a@9.9.9',
|
||||
message: 'a is available',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
{
|
||||
icon: 'warning',
|
||||
id: 'plugin:b@9.9.9',
|
||||
message: 'b is degraded',
|
||||
since: expect.any(String),
|
||||
state: 'yellow',
|
||||
uiColor: 'warning',
|
||||
},
|
||||
{
|
||||
icon: 'danger',
|
||||
id: 'plugin:c@9.9.9',
|
||||
message: 'c is unavailable',
|
||||
since: expect.any(String),
|
||||
state: 'red',
|
||||
uiColor: 'danger',
|
||||
},
|
||||
{
|
||||
icon: 'danger',
|
||||
id: 'plugin:d@9.9.9',
|
||||
message: 'd is critical',
|
||||
since: expect.any(String),
|
||||
state: 'red',
|
||||
uiColor: 'danger',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('returns legacy status format when v7format=true is provided', async () => {
|
||||
await setupServer();
|
||||
const result = await supertest(httpSetup.server.listener)
|
||||
.get('/api/status?v7format=true')
|
||||
.expect(200);
|
||||
expect(result.body.status).toEqual(legacyFormat);
|
||||
expect(incrementUsageCounter).toHaveBeenCalledTimes(1);
|
||||
expect(incrementUsageCounter).toHaveBeenCalledWith({ counterName: 'status_v7format' });
|
||||
});
|
||||
|
||||
it('returns legacy status format when v8format=false is provided', async () => {
|
||||
|
@ -207,109 +217,105 @@ describe('GET /api/status', () => {
|
|||
const result = await supertest(httpSetup.server.listener)
|
||||
.get('/api/status?v8format=false')
|
||||
.expect(200);
|
||||
expect(result.body.status).toEqual({
|
||||
overall: {
|
||||
icon: 'success',
|
||||
nickname: 'Looking good',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
title: 'Green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
statuses: [
|
||||
{
|
||||
icon: 'success',
|
||||
id: 'core:elasticsearch@9.9.9',
|
||||
message: 'Service is working',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
{
|
||||
icon: 'success',
|
||||
id: 'core:savedObjects@9.9.9',
|
||||
message: 'Service is working',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
{
|
||||
icon: 'success',
|
||||
id: 'plugin:a@9.9.9',
|
||||
message: 'a is available',
|
||||
since: expect.any(String),
|
||||
state: 'green',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
{
|
||||
icon: 'warning',
|
||||
id: 'plugin:b@9.9.9',
|
||||
message: 'b is degraded',
|
||||
since: expect.any(String),
|
||||
state: 'yellow',
|
||||
uiColor: 'warning',
|
||||
},
|
||||
{
|
||||
icon: 'danger',
|
||||
id: 'plugin:c@9.9.9',
|
||||
message: 'c is unavailable',
|
||||
since: expect.any(String),
|
||||
state: 'red',
|
||||
uiColor: 'danger',
|
||||
},
|
||||
{
|
||||
icon: 'danger',
|
||||
id: 'plugin:d@9.9.9',
|
||||
message: 'd is critical',
|
||||
since: expect.any(String),
|
||||
state: 'red',
|
||||
uiColor: 'danger',
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result.body.status).toEqual(legacyFormat);
|
||||
expect(incrementUsageCounter).toHaveBeenCalledTimes(1);
|
||||
expect(incrementUsageCounter).toHaveBeenCalledWith({ counterName: 'status_v7format' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('v8format', () => {
|
||||
const newFormat = {
|
||||
core: {
|
||||
elasticsearch: {
|
||||
level: 'available',
|
||||
summary: 'Service is working',
|
||||
},
|
||||
savedObjects: {
|
||||
level: 'available',
|
||||
summary: 'Service is working',
|
||||
},
|
||||
},
|
||||
overall: {
|
||||
level: 'available',
|
||||
summary: 'Service is working',
|
||||
},
|
||||
plugins: {
|
||||
a: {
|
||||
level: 'available',
|
||||
summary: 'a is available',
|
||||
},
|
||||
b: {
|
||||
level: 'degraded',
|
||||
summary: 'b is degraded',
|
||||
},
|
||||
c: {
|
||||
level: 'unavailable',
|
||||
summary: 'c is unavailable',
|
||||
},
|
||||
d: {
|
||||
level: 'critical',
|
||||
summary: 'd is critical',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it('returns new status format when no query params are provided', async () => {
|
||||
await setupServer();
|
||||
const result = await supertest(httpSetup.server.listener).get('/api/status').expect(200);
|
||||
expect(result.body.status).toEqual(newFormat);
|
||||
expect(incrementUsageCounter).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns new status format when v8format=true is provided', async () => {
|
||||
await setupServer();
|
||||
const result = await supertest(httpSetup.server.listener)
|
||||
.get('/api/status?v8format=true')
|
||||
.expect(200);
|
||||
expect(result.body.status).toEqual({
|
||||
core: {
|
||||
elasticsearch: {
|
||||
level: 'available',
|
||||
summary: 'Service is working',
|
||||
},
|
||||
savedObjects: {
|
||||
level: 'available',
|
||||
summary: 'Service is working',
|
||||
},
|
||||
},
|
||||
overall: {
|
||||
level: 'available',
|
||||
summary: 'Service is working',
|
||||
},
|
||||
plugins: {
|
||||
a: {
|
||||
level: 'available',
|
||||
summary: 'a is available',
|
||||
},
|
||||
b: {
|
||||
level: 'degraded',
|
||||
summary: 'b is degraded',
|
||||
},
|
||||
c: {
|
||||
level: 'unavailable',
|
||||
summary: 'c is unavailable',
|
||||
},
|
||||
d: {
|
||||
level: 'critical',
|
||||
summary: 'd is critical',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result.body.status).toEqual(newFormat);
|
||||
expect(incrementUsageCounter).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns new status format when v7format=false is provided', async () => {
|
||||
await setupServer();
|
||||
const result = await supertest(httpSetup.server.listener)
|
||||
.get('/api/status?v7format=false')
|
||||
.expect(200);
|
||||
expect(result.body.status).toEqual(newFormat);
|
||||
expect(incrementUsageCounter).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid query parameters', () => {
|
||||
it('v8format=true and v7format=true', async () => {
|
||||
await setupServer();
|
||||
await supertest(httpSetup.server.listener)
|
||||
.get('/api/status?v8format=true&v7format=true')
|
||||
.expect(400);
|
||||
expect(incrementUsageCounter).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('v8format=true and v7format=false', async () => {
|
||||
await setupServer();
|
||||
await supertest(httpSetup.server.listener)
|
||||
.get('/api/status?v8format=true&v7format=false')
|
||||
.expect(400);
|
||||
expect(incrementUsageCounter).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('v8format=false and v7format=false', async () => {
|
||||
await setupServer();
|
||||
await supertest(httpSetup.server.listener)
|
||||
.get('/api/status?v8format=false&v7format=false')
|
||||
.expect(400);
|
||||
expect(incrementUsageCounter).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('v8format=false and v7format=true', async () => {
|
||||
await setupServer();
|
||||
await supertest(httpSetup.server.listener)
|
||||
.get('/api/status?v8format=false&v7format=true')
|
||||
.expect(400);
|
||||
expect(incrementUsageCounter).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ import { schema } from '@kbn/config-schema';
|
|||
|
||||
import { IRouter } from '../../http';
|
||||
import { MetricsServiceSetup } from '../../metrics';
|
||||
import type { CoreIncrementUsageCounter } from '../../core_usage_data/types';
|
||||
import { ServiceStatus, CoreStatus, ServiceStatusLevels } from '../types';
|
||||
import { PluginName } from '../../plugins';
|
||||
import { calculateLegacyStatus, LegacyStatusInfo } from '../legacy_status';
|
||||
|
@ -34,6 +35,7 @@ interface Deps {
|
|||
core$: Observable<CoreStatus>;
|
||||
plugins$: Observable<Record<PluginName, ServiceStatus>>;
|
||||
};
|
||||
incrementUsageCounter: CoreIncrementUsageCounter;
|
||||
}
|
||||
|
||||
interface StatusInfo {
|
||||
|
@ -47,7 +49,13 @@ interface StatusHttpBody extends Omit<StatusResponse, 'status'> {
|
|||
status: StatusInfo | LegacyStatusInfo;
|
||||
}
|
||||
|
||||
export const registerStatusRoute = ({ router, config, metrics, status }: Deps) => {
|
||||
export const registerStatusRoute = ({
|
||||
router,
|
||||
config,
|
||||
metrics,
|
||||
status,
|
||||
incrementUsageCounter,
|
||||
}: Deps) => {
|
||||
// Since the status.plugins$ observable is not subscribed to elsewhere, we need to subscribe it here to eagerly load
|
||||
// the plugins status when Kibana starts up so this endpoint responds quickly on first boot.
|
||||
const combinedStatus$ = new ReplaySubject<
|
||||
|
@ -63,9 +71,19 @@ export const registerStatusRoute = ({ router, config, metrics, status }: Deps) =
|
|||
tags: ['api'], // ensures that unauthenticated calls receive a 401 rather than a 302 redirect to login page
|
||||
},
|
||||
validate: {
|
||||
query: schema.object({
|
||||
v8format: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
query: schema.object(
|
||||
{
|
||||
v7format: schema.maybe(schema.boolean()),
|
||||
v8format: schema.maybe(schema.boolean()),
|
||||
},
|
||||
{
|
||||
validate: ({ v7format, v8format }) => {
|
||||
if (typeof v7format === 'boolean' && typeof v8format === 'boolean') {
|
||||
return `provide only one format option: v7format or v8format`;
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
|
@ -73,14 +91,17 @@ export const registerStatusRoute = ({ router, config, metrics, status }: Deps) =
|
|||
const versionWithoutSnapshot = version.replace(SNAPSHOT_POSTFIX, '');
|
||||
const [overall, core, plugins] = await combinedStatus$.pipe(first()).toPromise();
|
||||
|
||||
const { v8format = true, v7format = false } = req.query ?? {};
|
||||
|
||||
let statusInfo: StatusInfo | LegacyStatusInfo;
|
||||
if (req.query?.v8format) {
|
||||
if (!v7format && v8format) {
|
||||
statusInfo = {
|
||||
overall,
|
||||
core,
|
||||
plugins,
|
||||
};
|
||||
} else {
|
||||
incrementUsageCounter({ counterName: 'status_v7format' });
|
||||
statusInfo = calculateLegacyStatus({
|
||||
overall,
|
||||
core,
|
||||
|
|
|
@ -18,6 +18,7 @@ import { httpServiceMock } from '../http/http_service.mock';
|
|||
import { mockRouter, RouterMock } from '../http/router/router.mock';
|
||||
import { metricsServiceMock } from '../metrics/metrics_service.mock';
|
||||
import { configServiceMock } from '../config/mocks';
|
||||
import { coreUsageDataServiceMock } from '../core_usage_data/core_usage_data_service.mock';
|
||||
|
||||
expect.addSnapshotSerializer(ServiceStatusLevelSnapshotSerializer);
|
||||
|
||||
|
@ -51,6 +52,7 @@ describe('StatusService', () => {
|
|||
environment: environmentServiceMock.createSetupContract(),
|
||||
http: httpServiceMock.createInternalSetupContract(),
|
||||
metrics: metricsServiceMock.createInternalSetupContract(),
|
||||
coreUsageData: coreUsageDataServiceMock.createSetupContract(),
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -20,6 +20,7 @@ import { PluginName } from '../plugins';
|
|||
import { InternalMetricsServiceSetup } from '../metrics';
|
||||
import { registerStatusRoute } from './routes';
|
||||
import { InternalEnvironmentServiceSetup } from '../environment';
|
||||
import type { InternalCoreUsageDataSetup } from '../core_usage_data';
|
||||
|
||||
import { config, StatusConfigType } from './status_config';
|
||||
import { ServiceStatus, CoreStatus, InternalStatusServiceSetup } from './types';
|
||||
|
@ -38,6 +39,7 @@ interface SetupDeps {
|
|||
http: InternalHttpServiceSetup;
|
||||
metrics: InternalMetricsServiceSetup;
|
||||
savedObjects: Pick<InternalSavedObjectsServiceSetup, 'status$'>;
|
||||
coreUsageData: Pick<InternalCoreUsageDataSetup, 'incrementUsageCounter'>;
|
||||
}
|
||||
|
||||
export class StatusService implements CoreService<InternalStatusServiceSetup> {
|
||||
|
@ -61,6 +63,7 @@ export class StatusService implements CoreService<InternalStatusServiceSetup> {
|
|||
metrics,
|
||||
savedObjects,
|
||||
environment,
|
||||
coreUsageData,
|
||||
}: SetupDeps) {
|
||||
const statusConfig = await this.config$.pipe(take(1)).toPromise();
|
||||
const core$ = this.setupCoreStatus({ elasticsearch, savedObjects });
|
||||
|
@ -101,6 +104,7 @@ export class StatusService implements CoreService<InternalStatusServiceSetup> {
|
|||
plugins$: this.pluginsStatus.getAll$(),
|
||||
core$,
|
||||
},
|
||||
incrementUsageCounter: coreUsageData.incrementUsageCounter,
|
||||
};
|
||||
|
||||
const router = http.createRouter('');
|
||||
|
|
|
@ -42,6 +42,8 @@ describe('kibana_usage_collection', () => {
|
|||
|
||||
expect(pluginInstance.setup(coreSetup, { usageCollection })).toBe(undefined);
|
||||
|
||||
expect(coreSetup.coreUsageData.registerUsageCounter).toHaveBeenCalled();
|
||||
|
||||
await expect(
|
||||
Promise.all(
|
||||
usageCollectors.map(async (usageCollector) => {
|
||||
|
|
|
@ -73,6 +73,7 @@ export class KibanaUsageCollectionPlugin implements Plugin {
|
|||
public setup(coreSetup: CoreSetup, { usageCollection }: KibanaUsageCollectionPluginsDepsSetup) {
|
||||
usageCollection.createUsageCounter('uiCounters');
|
||||
this.eventLoopUsageCounter = usageCollection.createUsageCounter('eventLoop');
|
||||
coreSetup.coreUsageData.registerUsageCounter(usageCollection.createUsageCounter('core'));
|
||||
this.registerUsageCollectors(
|
||||
usageCollection,
|
||||
coreSetup,
|
||||
|
|
|
@ -25,9 +25,10 @@ export default function ({ getService }) {
|
|||
expect(body.version.build_number).to.be.a('number');
|
||||
|
||||
expect(body.status.overall).to.be.an('object');
|
||||
expect(body.status.overall.state).to.be('green');
|
||||
expect(body.status.overall.level).to.be('available');
|
||||
|
||||
expect(body.status.statuses).to.be.an('array');
|
||||
expect(body.status.core).to.be.an('object');
|
||||
expect(body.status.plugins).to.be.an('object');
|
||||
|
||||
expect(body.metrics.collection_interval_in_millis).to.be.a('number');
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
|
||||
const delay = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||
const getStatus = async (pluginName?: string) => {
|
||||
const resp = await supertest.get('/api/status?v8format=true');
|
||||
const resp = await supertest.get('/api/status');
|
||||
|
||||
if (pluginName) {
|
||||
return resp.body.status.plugins[pluginName];
|
||||
|
|
|
@ -18,7 +18,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const retry = getService('retry');
|
||||
|
||||
const getStatus = async (pluginName: string): Promise<ServiceStatusSerialized> => {
|
||||
const resp = await supertest.get('/api/status?v8format=true');
|
||||
const resp = await supertest.get('/api/status');
|
||||
|
||||
return resp.body.status.plugins[pluginName];
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue