mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
[Telemetry] Use header-based versioned APIs instead of path-based (#159839)
This commit is contained in:
parent
b336a195e0
commit
0284cc158d
37 changed files with 779 additions and 452 deletions
|
@ -54,12 +54,12 @@ Once you set up the APM infrastructure, you can enable the APM agent and put {ki
|
|||
*Prerequisites* {kib} logs are configured to be in {ecs-ref}/ecs-reference.html[ECS JSON] format to include tracing identifiers.
|
||||
|
||||
Open {kib} Logs and search for an operation you are interested in.
|
||||
For example, suppose you want to investigate the response times for queries to the `/api/telemetry/v2/clusters/_stats` {kib} endpoint.
|
||||
For example, suppose you want to investigate the response times for queries to the `/internal/telemetry/clusters/_stats` {kib} endpoint.
|
||||
Open Kibana Logs and search for the HTTP server response for the endpoint. It looks similar to the following (some fields are omitted for brevity).
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"message":"POST /api/telemetry/v2/clusters/_stats 200 1014ms - 43.2KB",
|
||||
"message":"POST /internal/telemetry/clusters/_stats 200 1014ms - 43.2KB",
|
||||
"log":{"level":"DEBUG","logger":"http.server.response"},
|
||||
"trace":{"id":"9b99131a6f66587971ef085ef97dfd07"},
|
||||
"transaction":{"id":"d0c5bbf14f5febca"}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import { setupIntegrationEnvironment, TestEnvironmentUtils } from '../../test_utils';
|
||||
|
||||
describe('Files usage telemetry', () => {
|
||||
|
@ -45,7 +49,9 @@ describe('Files usage telemetry', () => {
|
|||
]);
|
||||
|
||||
const { body } = await request
|
||||
.post(root, '/api/telemetry/v2/clusters/_stats')
|
||||
.post(root, '/internal/telemetry/clusters/_stats')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true });
|
||||
|
||||
expect(body[0].stats.stack_stats.kibana.plugins.files).toMatchInlineSnapshot(`
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"@kbn/core-elasticsearch-server-mocks",
|
||||
"@kbn/core-saved-objects-server-mocks",
|
||||
"@kbn/logging",
|
||||
"@kbn/core-http-common",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -6,7 +6,49 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const BASE_INTERNAL_PATH = '/internal/telemetry';
|
||||
|
||||
export const INTERNAL_VERSION = { version: '2' };
|
||||
|
||||
/**
|
||||
* Fetch Telemetry Config
|
||||
* @public Kept public and path-based because we know other Elastic products fetch the opt-in status via this endpoint.
|
||||
*/
|
||||
export const FetchTelemetryConfigRoute = '/api/telemetry/v2/config';
|
||||
export const FetchTelemetryConfigRoutePathBasedV2 = '/api/telemetry/v2/config';
|
||||
|
||||
/**
|
||||
* Fetch Telemetry Config
|
||||
* @internal
|
||||
*/
|
||||
export const FetchTelemetryConfigRoute = `${BASE_INTERNAL_PATH}/config`;
|
||||
|
||||
/**
|
||||
* GET/PUT Last reported date for Snapshot telemetry
|
||||
* @internal
|
||||
*/
|
||||
export const LastReportedRoute = `${BASE_INTERNAL_PATH}/last_reported`;
|
||||
|
||||
/**
|
||||
* Set user has seen notice
|
||||
* @internal
|
||||
*/
|
||||
export const UserHasSeenNoticeRoute = `${BASE_INTERNAL_PATH}/userHasSeenNotice`;
|
||||
|
||||
/**
|
||||
* Set opt-in/out status
|
||||
* @internal
|
||||
*/
|
||||
export const OptInRoute = `${BASE_INTERNAL_PATH}/optIn`;
|
||||
|
||||
/**
|
||||
* Fetch the Snapshot telemetry report
|
||||
* @internal
|
||||
*/
|
||||
export const FetchSnapshotTelemetry = `${BASE_INTERNAL_PATH}/clusters/_stats`;
|
||||
|
||||
/**
|
||||
* Get Opt-in stats
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export const GetOptInStatsRoutePathBasedV2 = '/api/telemetry/v2/clusters/_opt_in_stats';
|
||||
|
|
|
@ -8,4 +8,5 @@
|
|||
|
||||
export * from './latest';
|
||||
|
||||
export * as v1 from './v2'; // Just so v1 can also be used (but for some reason telemetry endpoints have always been v2 :shrug:)
|
||||
export * as v2 from './v2';
|
||||
|
|
|
@ -24,7 +24,7 @@ import type { HomePublicPluginSetup } from '@kbn/home-plugin/public';
|
|||
import { ElasticV3BrowserShipper } from '@kbn/analytics-shippers-elastic-v3-browser';
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import { FetchTelemetryConfigRoute } from '../common/routes';
|
||||
import { FetchTelemetryConfigRoute, INTERNAL_VERSION } from '../common/routes';
|
||||
import type { v2 } from '../common/types';
|
||||
import { TelemetrySender, TelemetryService, TelemetryNotifications } from './services';
|
||||
import { renderWelcomeTelemetryNotice } from './render_welcome_telemetry_notice';
|
||||
|
@ -329,7 +329,7 @@ export class TelemetryPlugin
|
|||
*/
|
||||
private async fetchUpdatedConfig(http: HttpStart | HttpSetup): Promise<TelemetryPluginConfig> {
|
||||
const { allowChangingOptInStatus, optIn, sendUsageFrom, telemetryNotifyUserAboutOptInDefault } =
|
||||
await http.get<v2.FetchTelemetryConfigResponse>(FetchTelemetryConfigRoute);
|
||||
await http.get<v2.FetchTelemetryConfigResponse>(FetchTelemetryConfigRoute, INTERNAL_VERSION);
|
||||
|
||||
return {
|
||||
...this.config,
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
/* eslint-disable dot-notation */
|
||||
|
||||
import { mockTelemetryService } from '../mocks';
|
||||
import {
|
||||
FetchSnapshotTelemetry,
|
||||
INTERNAL_VERSION,
|
||||
OptInRoute,
|
||||
UserHasSeenNoticeRoute,
|
||||
} from '../../common/routes';
|
||||
|
||||
describe('TelemetryService', () => {
|
||||
describe('fetchTelemetry', () => {
|
||||
|
@ -17,7 +23,8 @@ describe('TelemetryService', () => {
|
|||
const telemetryService = mockTelemetryService();
|
||||
|
||||
await telemetryService.fetchTelemetry();
|
||||
expect(telemetryService['http'].post).toBeCalledWith('/api/telemetry/v2/clusters/_stats', {
|
||||
expect(telemetryService['http'].post).toBeCalledWith(FetchSnapshotTelemetry, {
|
||||
...INTERNAL_VERSION,
|
||||
body: JSON.stringify({ unencrypted: false, refreshCache: false }),
|
||||
});
|
||||
});
|
||||
|
@ -64,7 +71,8 @@ describe('TelemetryService', () => {
|
|||
const optedIn = true;
|
||||
await telemetryService.setOptIn(optedIn);
|
||||
|
||||
expect(telemetryService['http'].post).toBeCalledWith('/api/telemetry/v2/optIn', {
|
||||
expect(telemetryService['http'].post).toBeCalledWith(OptInRoute, {
|
||||
...INTERNAL_VERSION,
|
||||
body: JSON.stringify({ enabled: optedIn }),
|
||||
});
|
||||
});
|
||||
|
@ -77,7 +85,8 @@ describe('TelemetryService', () => {
|
|||
const optedIn = false;
|
||||
await telemetryService.setOptIn(optedIn);
|
||||
|
||||
expect(telemetryService['http'].post).toBeCalledWith('/api/telemetry/v2/optIn', {
|
||||
expect(telemetryService['http'].post).toBeCalledWith(OptInRoute, {
|
||||
...INTERNAL_VERSION,
|
||||
body: JSON.stringify({ enabled: optedIn }),
|
||||
});
|
||||
});
|
||||
|
@ -110,7 +119,7 @@ describe('TelemetryService', () => {
|
|||
config: { allowChangingOptInStatus: true },
|
||||
});
|
||||
telemetryService['http'].post = jest.fn().mockImplementation((url: string) => {
|
||||
if (url === '/api/telemetry/v2/optIn') {
|
||||
if (url === OptInRoute) {
|
||||
throw Error('failed to update opt in.');
|
||||
}
|
||||
});
|
||||
|
@ -203,7 +212,7 @@ describe('TelemetryService', () => {
|
|||
});
|
||||
|
||||
telemetryService['http'].put = jest.fn().mockImplementation((url: string) => {
|
||||
if (url === '/api/telemetry/v2/userHasSeenNotice') {
|
||||
if (url === UserHasSeenNoticeRoute) {
|
||||
throw Error('failed to update opt in.');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -8,11 +8,19 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { CoreSetup, CoreStart } from '@kbn/core/public';
|
||||
import {
|
||||
LastReportedRoute,
|
||||
INTERNAL_VERSION,
|
||||
OptInRoute,
|
||||
FetchSnapshotTelemetry,
|
||||
UserHasSeenNoticeRoute,
|
||||
} from '../../common/routes';
|
||||
import type { TelemetryPluginConfig } from '../plugin';
|
||||
import { getTelemetryChannelEndpoint } from '../../common/telemetry_config/get_telemetry_channel_endpoint';
|
||||
import { getTelemetryChannelEndpoint } from '../../common/telemetry_config';
|
||||
import type {
|
||||
UnencryptedTelemetryPayload,
|
||||
EncryptedTelemetryPayload,
|
||||
FetchLastReportedResponse,
|
||||
} from '../../common/types/latest';
|
||||
import { PAYLOAD_CONTENT_ENCODING } from '../../common/constants';
|
||||
|
||||
|
@ -93,8 +101,7 @@ export class TelemetryService {
|
|||
|
||||
/** Is the cluster allowed to change the opt-in/out status **/
|
||||
public getCanChangeOptInStatus = () => {
|
||||
const allowChangingOptInStatus = this.config.allowChangingOptInStatus;
|
||||
return allowChangingOptInStatus;
|
||||
return this.config.allowChangingOptInStatus;
|
||||
};
|
||||
|
||||
/** Retrieve the opt-in/out notification URL **/
|
||||
|
@ -156,17 +163,18 @@ export class TelemetryService {
|
|||
};
|
||||
|
||||
public fetchLastReported = async (): Promise<number | undefined> => {
|
||||
const response = await this.http.get<{ lastReported?: number }>(
|
||||
'/api/telemetry/v2/last_reported'
|
||||
const response = await this.http.get<FetchLastReportedResponse>(
|
||||
LastReportedRoute,
|
||||
INTERNAL_VERSION
|
||||
);
|
||||
return response?.lastReported;
|
||||
};
|
||||
|
||||
public updateLastReported = async (): Promise<number | undefined> => {
|
||||
return this.http.put('/api/telemetry/v2/last_reported');
|
||||
return this.http.put(LastReportedRoute);
|
||||
};
|
||||
|
||||
/** Fetches an unencrypted telemetry payload so we can show it to the user **/
|
||||
/** Fetches an unencrypted telemetry payload, so we can show it to the user **/
|
||||
public fetchExample = async (): Promise<UnencryptedTelemetryPayload> => {
|
||||
return await this.fetchTelemetry({ unencrypted: true, refreshCache: true });
|
||||
};
|
||||
|
@ -174,12 +182,14 @@ export class TelemetryService {
|
|||
/**
|
||||
* Fetches telemetry payload
|
||||
* @param unencrypted Default `false`. Whether the returned payload should be encrypted or not.
|
||||
* @param refreshCache Default `false`. Set to `true` to force the regeneration of the telemetry report.
|
||||
*/
|
||||
public fetchTelemetry = async <T = EncryptedTelemetryPayload | UnencryptedTelemetryPayload>({
|
||||
unencrypted = false,
|
||||
refreshCache = false,
|
||||
} = {}): Promise<T> => {
|
||||
return this.http.post('/api/telemetry/v2/clusters/_stats', {
|
||||
return this.http.post(FetchSnapshotTelemetry, {
|
||||
...INTERNAL_VERSION,
|
||||
body: JSON.stringify({ unencrypted, refreshCache }),
|
||||
});
|
||||
};
|
||||
|
@ -198,12 +208,10 @@ export class TelemetryService {
|
|||
try {
|
||||
// Report the option to the Kibana server to store the settings.
|
||||
// It returns the encrypted update to send to the telemetry cluster [{cluster_uuid, opt_in_status}]
|
||||
const optInStatusPayload = await this.http.post<EncryptedTelemetryPayload>(
|
||||
'/api/telemetry/v2/optIn',
|
||||
{
|
||||
body: JSON.stringify({ enabled: optedIn }),
|
||||
}
|
||||
);
|
||||
const optInStatusPayload = await this.http.post<EncryptedTelemetryPayload>(OptInRoute, {
|
||||
...INTERNAL_VERSION,
|
||||
body: JSON.stringify({ enabled: optedIn }),
|
||||
});
|
||||
if (this.reportOptInStatusChange) {
|
||||
// Use the response to report about the change to the remote telemetry cluster.
|
||||
// If it's opt-out, this will be the last communication to the remote service.
|
||||
|
@ -231,7 +239,7 @@ export class TelemetryService {
|
|||
*/
|
||||
public setUserHasSeenNotice = async (): Promise<void> => {
|
||||
try {
|
||||
await this.http.put('/api/telemetry/v2/userHasSeenNotice');
|
||||
await this.http.put(UserHasSeenNoticeRoute, INTERNAL_VERSION);
|
||||
this.userHasSeenOptedInNotice = true;
|
||||
} catch (error) {
|
||||
this.notifications.toasts.addError(error, {
|
||||
|
@ -248,7 +256,7 @@ export class TelemetryService {
|
|||
|
||||
/**
|
||||
* Pushes the encrypted payload [{cluster_uuid, opt_in_status}] to the remote telemetry service
|
||||
* @param optInPayload [{cluster_uuid, opt_in_status}] encrypted by the server into an array of strings
|
||||
* @param optInStatusPayload [{cluster_uuid, opt_in_status}] encrypted by the server into an array of strings
|
||||
*/
|
||||
private reportOptInStatus = async (
|
||||
optInStatusPayload: EncryptedTelemetryPayload
|
||||
|
|
|
@ -8,9 +8,14 @@
|
|||
|
||||
import { type Observable, firstValueFrom } from 'rxjs';
|
||||
import type { IRouter, SavedObjectsClient } from '@kbn/core/server';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { RequestHandler } from '@kbn/core-http-server';
|
||||
import type { TelemetryConfigType } from '../config';
|
||||
import { v2 } from '../../common/types';
|
||||
import { FetchTelemetryConfigRoute } from '../../common/routes';
|
||||
import {
|
||||
FetchTelemetryConfigRoutePathBasedV2,
|
||||
FetchTelemetryConfigRoute,
|
||||
} from '../../common/routes';
|
||||
import { getTelemetrySavedObject } from '../saved_objects';
|
||||
import {
|
||||
getNotifyUserAboutOptInDefault,
|
||||
|
@ -25,54 +30,74 @@ interface RegisterTelemetryConfigRouteOptions {
|
|||
currentKibanaVersion: string;
|
||||
savedObjectsInternalClient$: Observable<SavedObjectsClient>;
|
||||
}
|
||||
|
||||
export function registerTelemetryConfigRoutes({
|
||||
router,
|
||||
config$,
|
||||
currentKibanaVersion,
|
||||
savedObjectsInternalClient$,
|
||||
}: RegisterTelemetryConfigRouteOptions) {
|
||||
// GET to retrieve
|
||||
router.get(
|
||||
{
|
||||
path: FetchTelemetryConfigRoute,
|
||||
validate: false,
|
||||
const v2Handler: RequestHandler = async (context, req, res) => {
|
||||
const config = await firstValueFrom(config$);
|
||||
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||
const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsInternalClient);
|
||||
const allowChangingOptInStatus = getTelemetryAllowChangingOptInStatus({
|
||||
configTelemetryAllowChangingOptInStatus: config.allowChangingOptInStatus,
|
||||
telemetrySavedObject,
|
||||
});
|
||||
|
||||
const optIn = getTelemetryOptIn({
|
||||
configTelemetryOptIn: config.optIn,
|
||||
allowChangingOptInStatus,
|
||||
telemetrySavedObject,
|
||||
currentKibanaVersion,
|
||||
});
|
||||
|
||||
const sendUsageFrom = getTelemetrySendUsageFrom({
|
||||
configTelemetrySendUsageFrom: config.sendUsageFrom,
|
||||
telemetrySavedObject,
|
||||
});
|
||||
|
||||
const telemetryNotifyUserAboutOptInDefault = getNotifyUserAboutOptInDefault({
|
||||
telemetrySavedObject,
|
||||
allowChangingOptInStatus,
|
||||
configTelemetryOptIn: config.optIn,
|
||||
telemetryOptedIn: optIn,
|
||||
});
|
||||
|
||||
const body: v2.FetchTelemetryConfigResponse = {
|
||||
allowChangingOptInStatus,
|
||||
optIn,
|
||||
sendUsageFrom,
|
||||
telemetryNotifyUserAboutOptInDefault,
|
||||
};
|
||||
|
||||
return res.ok({ body });
|
||||
};
|
||||
|
||||
const v2Validations = {
|
||||
response: {
|
||||
200: {
|
||||
body: schema.object({
|
||||
allowChangingOptInStatus: schema.boolean(),
|
||||
optIn: schema.oneOf([schema.boolean(), schema.literal(null)]),
|
||||
sendUsageFrom: schema.oneOf([schema.literal('server'), schema.literal('browser')]),
|
||||
telemetryNotifyUserAboutOptInDefault: schema.boolean(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const config = await firstValueFrom(config$);
|
||||
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||
const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsInternalClient);
|
||||
const allowChangingOptInStatus = getTelemetryAllowChangingOptInStatus({
|
||||
configTelemetryAllowChangingOptInStatus: config.allowChangingOptInStatus,
|
||||
telemetrySavedObject,
|
||||
});
|
||||
};
|
||||
|
||||
const optIn = getTelemetryOptIn({
|
||||
configTelemetryOptIn: config.optIn,
|
||||
allowChangingOptInStatus,
|
||||
telemetrySavedObject,
|
||||
currentKibanaVersion,
|
||||
});
|
||||
// Register the internal versioned API
|
||||
router.versioned
|
||||
.get({ access: 'internal', path: FetchTelemetryConfigRoute })
|
||||
// Just because it used to be /v2/, we are creating identical v1 and v2.
|
||||
.addVersion({ version: '1', validate: v2Validations }, v2Handler)
|
||||
.addVersion({ version: '2', validate: v2Validations }, v2Handler);
|
||||
|
||||
const sendUsageFrom = getTelemetrySendUsageFrom({
|
||||
configTelemetrySendUsageFrom: config.sendUsageFrom,
|
||||
telemetrySavedObject,
|
||||
});
|
||||
|
||||
const telemetryNotifyUserAboutOptInDefault = getNotifyUserAboutOptInDefault({
|
||||
telemetrySavedObject,
|
||||
allowChangingOptInStatus,
|
||||
configTelemetryOptIn: config.optIn,
|
||||
telemetryOptedIn: optIn,
|
||||
});
|
||||
|
||||
const body: v2.FetchTelemetryConfigResponse = {
|
||||
allowChangingOptInStatus,
|
||||
optIn,
|
||||
sendUsageFrom,
|
||||
telemetryNotifyUserAboutOptInDefault,
|
||||
};
|
||||
|
||||
return res.ok({ body });
|
||||
}
|
||||
);
|
||||
// Register the deprecated public and path-based for BWC
|
||||
// as we know this one is used by other Elastic products to fetch the opt-in status.
|
||||
router.versioned
|
||||
.get({ access: 'public', path: FetchTelemetryConfigRoutePathBasedV2 })
|
||||
.addVersion({ version: '2023-10-31', validate: v2Validations }, v2Handler);
|
||||
}
|
||||
|
|
|
@ -6,9 +6,12 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import type { IRouter, SavedObjectsClient } from '@kbn/core/server';
|
||||
import type { Observable } from 'rxjs';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { RequestHandler } from '@kbn/core-http-server';
|
||||
import { LastReportedRoute } from '../../common/routes';
|
||||
import { v2 } from '../../common/types';
|
||||
import { getTelemetrySavedObject, updateTelemetrySavedObject } from '../saved_objects';
|
||||
|
||||
|
@ -17,38 +20,38 @@ export function registerTelemetryLastReported(
|
|||
savedObjectsInternalClient$: Observable<SavedObjectsClient>
|
||||
) {
|
||||
// GET to retrieve
|
||||
router.get(
|
||||
{
|
||||
path: '/api/telemetry/v2/last_reported',
|
||||
validate: false,
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||
const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsInternalClient);
|
||||
const v2GetValidations = {
|
||||
response: { 200: { body: schema.object({ lastReported: schema.maybe(schema.number()) }) } },
|
||||
};
|
||||
|
||||
const body: v2.FetchLastReportedResponse = {
|
||||
lastReported: telemetrySavedObject && telemetrySavedObject?.lastReported,
|
||||
};
|
||||
const v2GetHandler: RequestHandler = async (context, req, res) => {
|
||||
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||
const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsInternalClient);
|
||||
|
||||
return res.ok({
|
||||
body,
|
||||
});
|
||||
}
|
||||
);
|
||||
const body: v2.FetchLastReportedResponse = {
|
||||
lastReported: telemetrySavedObject && telemetrySavedObject?.lastReported,
|
||||
};
|
||||
return res.ok({ body });
|
||||
};
|
||||
|
||||
router.versioned
|
||||
.get({ access: 'internal', path: LastReportedRoute })
|
||||
// Just because it used to be /v2/, we are creating identical v1 and v2.
|
||||
.addVersion({ version: '1', validate: v2GetValidations }, v2GetHandler)
|
||||
.addVersion({ version: '2', validate: v2GetValidations }, v2GetHandler);
|
||||
|
||||
// PUT to update
|
||||
router.put(
|
||||
{
|
||||
path: '/api/telemetry/v2/last_reported',
|
||||
validate: false,
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||
await updateTelemetrySavedObject(savedObjectsInternalClient, {
|
||||
lastReported: Date.now(),
|
||||
});
|
||||
const v2PutHandler: RequestHandler = async (context, req, res) => {
|
||||
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||
await updateTelemetrySavedObject(savedObjectsInternalClient, {
|
||||
lastReported: Date.now(),
|
||||
});
|
||||
return res.ok();
|
||||
};
|
||||
|
||||
return res.ok();
|
||||
}
|
||||
);
|
||||
router.versioned
|
||||
.put({ access: 'internal', path: LastReportedRoute })
|
||||
// Just because it used to be /v2/, we are creating identical v1 and v2.
|
||||
.addVersion({ version: '1', validate: false }, v2PutHandler)
|
||||
.addVersion({ version: '2', validate: false }, v2PutHandler);
|
||||
}
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
import { firstValueFrom, type Observable } from 'rxjs';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import type { IRouter, Logger } from '@kbn/core/server';
|
||||
import { SavedObjectsErrorHelpers } from '@kbn/core/server';
|
||||
import { RequestHandlerContext, SavedObjectsErrorHelpers } from '@kbn/core/server';
|
||||
import type {
|
||||
StatsGetterConfig,
|
||||
TelemetryCollectionManagerPluginSetup,
|
||||
} from '@kbn/telemetry-collection-manager-plugin/server';
|
||||
import { v2 } from '../../common/types';
|
||||
import { RequestHandler } from '@kbn/core-http-server';
|
||||
import { OptInRoute } from '../../common/routes';
|
||||
import { OptInBody, v2 } from '../../common/types';
|
||||
import { sendTelemetryOptInStatus } from './telemetry_opt_in_stats';
|
||||
import {
|
||||
getTelemetrySavedObject,
|
||||
|
@ -41,78 +43,91 @@ export function registerTelemetryOptInRoutes({
|
|||
currentKibanaVersion,
|
||||
telemetryCollectionManager,
|
||||
}: RegisterOptInRoutesParams) {
|
||||
router.post(
|
||||
{
|
||||
path: '/api/telemetry/v2/optIn',
|
||||
validate: {
|
||||
body: schema.object({ enabled: schema.boolean() }),
|
||||
const v2Handler: RequestHandler<undefined, undefined, OptInBody, RequestHandlerContext> = async (
|
||||
context,
|
||||
req,
|
||||
res
|
||||
) => {
|
||||
const newOptInStatus = req.body.enabled;
|
||||
const soClient = (await context.core).savedObjects.getClient({
|
||||
includedHiddenTypes: [TELEMETRY_SAVED_OBJECT_TYPE],
|
||||
});
|
||||
const attributes: TelemetrySavedObject = {
|
||||
enabled: newOptInStatus,
|
||||
lastVersionChecked: currentKibanaVersion,
|
||||
};
|
||||
const config = await firstValueFrom(config$);
|
||||
|
||||
let telemetrySavedObject: TelemetrySavedObject | undefined;
|
||||
try {
|
||||
telemetrySavedObject = await getTelemetrySavedObject(soClient);
|
||||
} catch (err) {
|
||||
if (SavedObjectsErrorHelpers.isForbiddenError(err)) {
|
||||
// If we couldn't get the saved object due to lack of permissions,
|
||||
// we can assume the user won't be able to update it either
|
||||
return res.forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
const allowChangingOptInStatus = getTelemetryAllowChangingOptInStatus({
|
||||
configTelemetryAllowChangingOptInStatus: config.allowChangingOptInStatus,
|
||||
telemetrySavedObject,
|
||||
});
|
||||
if (!allowChangingOptInStatus) {
|
||||
return res.badRequest({
|
||||
body: JSON.stringify({ error: 'Not allowed to change Opt-in Status.' }),
|
||||
});
|
||||
}
|
||||
|
||||
const statsGetterConfig: StatsGetterConfig = {
|
||||
unencrypted: false,
|
||||
};
|
||||
|
||||
const optInStatus = await telemetryCollectionManager.getOptInStats(
|
||||
newOptInStatus,
|
||||
statsGetterConfig
|
||||
);
|
||||
|
||||
if (config.sendUsageFrom === 'server') {
|
||||
const { appendServerlessChannelsSuffix, sendUsageTo } = config;
|
||||
sendTelemetryOptInStatus(
|
||||
telemetryCollectionManager,
|
||||
{ appendServerlessChannelsSuffix, sendUsageTo, newOptInStatus, currentKibanaVersion },
|
||||
statsGetterConfig
|
||||
).catch((err) => {
|
||||
// The server is likely behind a firewall and can't reach the remote service
|
||||
logger.warn(
|
||||
`Failed to notify the telemetry endpoint about the opt-in selection. Possibly blocked by a firewall? - Error: ${err.message}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await updateTelemetrySavedObject(soClient, attributes);
|
||||
} catch (e) {
|
||||
if (SavedObjectsErrorHelpers.isForbiddenError(e)) {
|
||||
return res.forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
const body: v2.OptInResponse = optInStatus;
|
||||
return res.ok({ body });
|
||||
};
|
||||
|
||||
const v2Validations = {
|
||||
request: { body: schema.object({ enabled: schema.boolean() }) },
|
||||
response: {
|
||||
200: {
|
||||
body: schema.arrayOf(
|
||||
schema.object({ clusterUuid: schema.string(), stats: schema.string() })
|
||||
),
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const newOptInStatus = req.body.enabled;
|
||||
const soClient = (await context.core).savedObjects.getClient({
|
||||
includedHiddenTypes: [TELEMETRY_SAVED_OBJECT_TYPE],
|
||||
});
|
||||
const attributes: TelemetrySavedObject = {
|
||||
enabled: newOptInStatus,
|
||||
lastVersionChecked: currentKibanaVersion,
|
||||
};
|
||||
const config = await firstValueFrom(config$);
|
||||
};
|
||||
|
||||
let telemetrySavedObject: TelemetrySavedObject | undefined;
|
||||
try {
|
||||
telemetrySavedObject = await getTelemetrySavedObject(soClient);
|
||||
} catch (err) {
|
||||
if (SavedObjectsErrorHelpers.isForbiddenError(err)) {
|
||||
// If we couldn't get the saved object due to lack of permissions,
|
||||
// we can assume the user won't be able to update it either
|
||||
return res.forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
const allowChangingOptInStatus = getTelemetryAllowChangingOptInStatus({
|
||||
configTelemetryAllowChangingOptInStatus: config.allowChangingOptInStatus,
|
||||
telemetrySavedObject,
|
||||
});
|
||||
if (!allowChangingOptInStatus) {
|
||||
return res.badRequest({
|
||||
body: JSON.stringify({ error: 'Not allowed to change Opt-in Status.' }),
|
||||
});
|
||||
}
|
||||
|
||||
const statsGetterConfig: StatsGetterConfig = {
|
||||
unencrypted: false,
|
||||
};
|
||||
|
||||
const optInStatus = await telemetryCollectionManager.getOptInStats(
|
||||
newOptInStatus,
|
||||
statsGetterConfig
|
||||
);
|
||||
|
||||
if (config.sendUsageFrom === 'server') {
|
||||
const { appendServerlessChannelsSuffix, sendUsageTo } = config;
|
||||
sendTelemetryOptInStatus(
|
||||
telemetryCollectionManager,
|
||||
{ appendServerlessChannelsSuffix, sendUsageTo, newOptInStatus, currentKibanaVersion },
|
||||
statsGetterConfig
|
||||
).catch((err) => {
|
||||
// The server is likely behind a firewall and can't reach the remote service
|
||||
logger.warn(
|
||||
`Failed to notify the telemetry endpoint about the opt-in selection. Possibly blocked by a firewall? - Error: ${err.message}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await updateTelemetrySavedObject(soClient, attributes);
|
||||
} catch (e) {
|
||||
if (SavedObjectsErrorHelpers.isForbiddenError(e)) {
|
||||
return res.forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
const body: v2.OptInResponse = optInStatus;
|
||||
return res.ok({ body });
|
||||
}
|
||||
);
|
||||
router.versioned
|
||||
.post({ access: 'internal', path: OptInRoute })
|
||||
// Just because it used to be /v2/, we are creating identical v1 and v2.
|
||||
.addVersion({ version: '1', validate: v2Validations }, v2Handler)
|
||||
.addVersion({ version: '2', validate: v2Validations }, v2Handler);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import type {
|
|||
TelemetryCollectionManagerPluginSetup,
|
||||
StatsGetterConfig,
|
||||
} from '@kbn/telemetry-collection-manager-plugin/server';
|
||||
import { GetOptInStatsRoutePathBasedV2 } from '../../common/routes';
|
||||
import type { v2 } from '../../common/types';
|
||||
import { EncryptedTelemetryPayload, UnencryptedTelemetryPayload } from '../../common/types';
|
||||
import { getTelemetryChannelEndpoint } from '../../common/telemetry_config';
|
||||
|
@ -62,43 +63,64 @@ export function registerTelemetryOptInStatsRoutes(
|
|||
router: IRouter,
|
||||
telemetryCollectionManager: TelemetryCollectionManagerPluginSetup
|
||||
) {
|
||||
router.post(
|
||||
{
|
||||
path: '/api/telemetry/v2/clusters/_opt_in_stats',
|
||||
validate: {
|
||||
body: schema.object({
|
||||
enabled: schema.boolean(),
|
||||
unencrypted: schema.boolean({ defaultValue: true }),
|
||||
}),
|
||||
router.versioned
|
||||
.post({
|
||||
access: 'public', // It's not used across Kibana, and I didn't want to remove it in this PR just in case.
|
||||
path: GetOptInStatsRoutePathBasedV2,
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
version: '2023-10-31',
|
||||
validate: {
|
||||
request: {
|
||||
body: schema.object({
|
||||
enabled: schema.boolean(),
|
||||
unencrypted: schema.boolean({ defaultValue: true }),
|
||||
}),
|
||||
},
|
||||
response: {
|
||||
200: {
|
||||
body: schema.arrayOf(
|
||||
schema.object({
|
||||
clusterUuid: schema.string(),
|
||||
stats: schema.object({
|
||||
cluster_uuid: schema.string(),
|
||||
opt_in_status: schema.boolean(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
503: { body: schema.string() },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
try {
|
||||
const newOptInStatus = req.body.enabled;
|
||||
const unencrypted = req.body.unencrypted;
|
||||
async (context, req, res) => {
|
||||
try {
|
||||
const newOptInStatus = req.body.enabled;
|
||||
const unencrypted = req.body.unencrypted;
|
||||
|
||||
if (!(await telemetryCollectionManager.shouldGetTelemetry())) {
|
||||
// We probably won't reach here because there is a license check in the auth phase of the HTTP requests.
|
||||
// But let's keep it here should that changes at any point.
|
||||
return res.customError({
|
||||
statusCode: 503,
|
||||
body: `Can't fetch telemetry at the moment because some services are down. Check the /status page for more details.`,
|
||||
});
|
||||
if (!(await telemetryCollectionManager.shouldGetTelemetry())) {
|
||||
// We probably won't reach here because there is a license check in the auth phase of the HTTP requests.
|
||||
// But let's keep it here should that changes at any point.
|
||||
return res.customError({
|
||||
statusCode: 503,
|
||||
body: `Can't fetch telemetry at the moment because some services are down. Check the /status page for more details.`,
|
||||
});
|
||||
}
|
||||
|
||||
const statsGetterConfig: StatsGetterConfig = {
|
||||
unencrypted,
|
||||
};
|
||||
|
||||
const optInStatus = await telemetryCollectionManager.getOptInStats(
|
||||
newOptInStatus,
|
||||
statsGetterConfig
|
||||
);
|
||||
const body: v2.OptInStatsResponse = optInStatus;
|
||||
return res.ok({ body });
|
||||
} catch (err) {
|
||||
return res.ok({ body: [] });
|
||||
}
|
||||
|
||||
const statsGetterConfig: StatsGetterConfig = {
|
||||
unencrypted,
|
||||
};
|
||||
|
||||
const optInStatus = await telemetryCollectionManager.getOptInStats(
|
||||
newOptInStatus,
|
||||
statsGetterConfig
|
||||
);
|
||||
const body: v2.OptInStatsResponse = optInStatus;
|
||||
return res.ok({ body });
|
||||
} catch (err) {
|
||||
return res.ok({ body: [] });
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ async function runRequest(
|
|||
mockRouter: IRouter<RequestHandlerContext>,
|
||||
body?: { unencrypted?: boolean; refreshCache?: boolean }
|
||||
) {
|
||||
expect(mockRouter.post).toBeCalled();
|
||||
const [, handler] = (mockRouter.post as jest.Mock).mock.calls[0];
|
||||
expect(mockRouter.versioned.post).toBeCalled();
|
||||
const [, handler] = (mockRouter.versioned.post as jest.Mock).mock.results[0].value.addVersion.mock
|
||||
.calls[0];
|
||||
const mockResponse = httpServerMock.createResponseFactory();
|
||||
const mockRequest = httpServerMock.createKibanaRequest({ body });
|
||||
await handler(null, mockRequest, mockResponse);
|
||||
|
@ -49,10 +50,10 @@ describe('registerTelemetryUsageStatsRoutes', () => {
|
|||
describe('clusters/_stats POST route', () => {
|
||||
it('registers _stats POST route and accepts body configs', () => {
|
||||
registerTelemetryUsageStatsRoutes(mockRouter, telemetryCollectionManager, true, getSecurity);
|
||||
expect(mockRouter.post).toBeCalledTimes(1);
|
||||
const [routeConfig, handler] = (mockRouter.post as jest.Mock).mock.calls[0];
|
||||
expect(routeConfig.path).toMatchInlineSnapshot(`"/api/telemetry/v2/clusters/_stats"`);
|
||||
expect(Object.keys(routeConfig.validate.body.props)).toEqual(['unencrypted', 'refreshCache']);
|
||||
expect(mockRouter.versioned.post).toBeCalledTimes(1);
|
||||
const [routeConfig, handler] = (mockRouter.versioned.post as jest.Mock).mock.results[0].value
|
||||
.addVersion.mock.calls[0];
|
||||
expect(routeConfig.version).toMatchInlineSnapshot(`"1"`);
|
||||
expect(handler).toBeInstanceOf(Function);
|
||||
});
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@ import type {
|
|||
StatsGetterConfig,
|
||||
} from '@kbn/telemetry-collection-manager-plugin/server';
|
||||
import type { SecurityPluginStart } from '@kbn/security-plugin/server';
|
||||
import { v2 } from '../../common/types';
|
||||
import { RequestHandler } from '@kbn/core-http-server';
|
||||
import { FetchSnapshotTelemetry } from '../../common/routes';
|
||||
import { UsageStatsBody, v2 } from '../../common/types';
|
||||
|
||||
export type SecurityGetter = () => SecurityPluginStart | undefined;
|
||||
|
||||
|
@ -23,64 +25,75 @@ export function registerTelemetryUsageStatsRoutes(
|
|||
isDev: boolean,
|
||||
getSecurity: SecurityGetter
|
||||
) {
|
||||
router.post(
|
||||
{
|
||||
path: '/api/telemetry/v2/clusters/_stats',
|
||||
validate: {
|
||||
body: schema.object({
|
||||
unencrypted: schema.boolean({ defaultValue: false }),
|
||||
refreshCache: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const { unencrypted, refreshCache } = req.body;
|
||||
const v2Handler: RequestHandler<undefined, undefined, UsageStatsBody> = async (
|
||||
context,
|
||||
req,
|
||||
res
|
||||
) => {
|
||||
const { unencrypted, refreshCache } = req.body;
|
||||
|
||||
if (!(await telemetryCollectionManager.shouldGetTelemetry())) {
|
||||
// We probably won't reach here because there is a license check in the auth phase of the HTTP requests.
|
||||
// But let's keep it here should that changes at any point.
|
||||
return res.customError({
|
||||
statusCode: 503,
|
||||
body: `Can't fetch telemetry at the moment because some services are down. Check the /status page for more details.`,
|
||||
});
|
||||
}
|
||||
if (!(await telemetryCollectionManager.shouldGetTelemetry())) {
|
||||
// We probably won't reach here because there is a license check in the auth phase of the HTTP requests.
|
||||
// But let's keep it here should that changes at any point.
|
||||
return res.customError({
|
||||
statusCode: 503,
|
||||
body: `Can't fetch telemetry at the moment because some services are down. Check the /status page for more details.`,
|
||||
});
|
||||
}
|
||||
|
||||
const security = getSecurity();
|
||||
// We need to check useRbacForRequest to figure out if ES has security enabled before making the privileges check
|
||||
if (security && unencrypted && security.authz.mode.useRbacForRequest(req)) {
|
||||
// Normally we would use `options: { tags: ['access:decryptedTelemetry'] }` in the route definition to check authorization for an
|
||||
// API action, however, we want to check this conditionally based on the `unencrypted` parameter. In this case we need to use the
|
||||
// security API directly to check privileges for this action. Note that the 'decryptedTelemetry' API privilege string is only
|
||||
// granted to users that have "Global All" or "Global Read" privileges in Kibana.
|
||||
const { checkPrivilegesWithRequest, actions } = security.authz;
|
||||
const privileges = { kibana: actions.api.get('decryptedTelemetry') };
|
||||
const { hasAllRequested } = await checkPrivilegesWithRequest(req).globally(privileges);
|
||||
if (!hasAllRequested) {
|
||||
return res.forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const statsConfig: StatsGetterConfig = {
|
||||
unencrypted,
|
||||
refreshCache: unencrypted || refreshCache,
|
||||
};
|
||||
|
||||
const body: v2.UnencryptedTelemetryPayload = await telemetryCollectionManager.getStats(
|
||||
statsConfig
|
||||
);
|
||||
return res.ok({ body });
|
||||
} catch (err) {
|
||||
if (isDev) {
|
||||
// don't ignore errors when running in dev mode
|
||||
throw err;
|
||||
}
|
||||
if (unencrypted && err.status === 403) {
|
||||
return res.forbidden();
|
||||
}
|
||||
// ignore errors and return empty set
|
||||
return res.ok({ body: [] });
|
||||
const security = getSecurity();
|
||||
// We need to check useRbacForRequest to figure out if ES has security enabled before making the privileges check
|
||||
if (security && unencrypted && security.authz.mode.useRbacForRequest(req)) {
|
||||
// Normally we would use `options: { tags: ['access:decryptedTelemetry'] }` in the route definition to check authorization for an
|
||||
// API action, however, we want to check this conditionally based on the `unencrypted` parameter. In this case we need to use the
|
||||
// security API directly to check privileges for this action. Note that the 'decryptedTelemetry' API privilege string is only
|
||||
// granted to users that have "Global All" or "Global Read" privileges in Kibana.
|
||||
const { checkPrivilegesWithRequest, actions } = security.authz;
|
||||
const privileges = { kibana: actions.api.get('decryptedTelemetry') };
|
||||
const { hasAllRequested } = await checkPrivilegesWithRequest(req).globally(privileges);
|
||||
if (!hasAllRequested) {
|
||||
return res.forbidden();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
const statsConfig: StatsGetterConfig = {
|
||||
unencrypted,
|
||||
refreshCache: unencrypted || refreshCache,
|
||||
};
|
||||
|
||||
const body: v2.UnencryptedTelemetryPayload = await telemetryCollectionManager.getStats(
|
||||
statsConfig
|
||||
);
|
||||
return res.ok({ body });
|
||||
} catch (err) {
|
||||
if (isDev) {
|
||||
// don't ignore errors when running in dev mode
|
||||
throw err;
|
||||
}
|
||||
if (unencrypted && err.status === 403) {
|
||||
return res.forbidden();
|
||||
}
|
||||
// ignore errors and return empty set
|
||||
return res.ok({ body: [] });
|
||||
}
|
||||
};
|
||||
|
||||
const v2Validations = {
|
||||
request: {
|
||||
body: schema.object({
|
||||
unencrypted: schema.boolean({ defaultValue: false }),
|
||||
refreshCache: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
router.versioned
|
||||
.post({
|
||||
access: 'internal',
|
||||
path: FetchSnapshotTelemetry,
|
||||
})
|
||||
// Just because it used to be /v2/, we are creating identical v1 and v2.
|
||||
.addVersion({ version: '1', validate: v2Validations }, v2Handler)
|
||||
.addVersion({ version: '2', validate: v2Validations }, v2Handler);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
*/
|
||||
|
||||
import type { IRouter } from '@kbn/core/server';
|
||||
import { RequestHandler } from '@kbn/core-http-server';
|
||||
import { RequestHandlerContext } from '@kbn/core/server';
|
||||
import { UserHasSeenNoticeRoute } from '../../common/routes';
|
||||
import { TELEMETRY_SAVED_OBJECT_TYPE } from '../saved_objects';
|
||||
import { v2 } from '../../common/types';
|
||||
import {
|
||||
|
@ -16,38 +19,42 @@ import {
|
|||
} from '../saved_objects';
|
||||
|
||||
export function registerTelemetryUserHasSeenNotice(router: IRouter, currentKibanaVersion: string) {
|
||||
router.put(
|
||||
{
|
||||
path: '/api/telemetry/v2/userHasSeenNotice',
|
||||
validate: false,
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const soClient = (await context.core).savedObjects.getClient({
|
||||
includedHiddenTypes: [TELEMETRY_SAVED_OBJECT_TYPE],
|
||||
});
|
||||
const telemetrySavedObject = await getTelemetrySavedObject(soClient);
|
||||
const v2Handler: RequestHandler<undefined, undefined, undefined, RequestHandlerContext> = async (
|
||||
context,
|
||||
req,
|
||||
res
|
||||
) => {
|
||||
const soClient = (await context.core).savedObjects.getClient({
|
||||
includedHiddenTypes: [TELEMETRY_SAVED_OBJECT_TYPE],
|
||||
});
|
||||
const telemetrySavedObject = await getTelemetrySavedObject(soClient);
|
||||
|
||||
// update the object with a flag stating that the opt-in notice has been seen
|
||||
const updatedAttributes: TelemetrySavedObjectAttributes = {
|
||||
...telemetrySavedObject,
|
||||
userHasSeenNotice: true,
|
||||
// We need to store that the user was notified in this version.
|
||||
// Otherwise, it'll continuously show the banner if previously opted-out.
|
||||
lastVersionChecked: currentKibanaVersion,
|
||||
};
|
||||
await updateTelemetrySavedObject(soClient, updatedAttributes);
|
||||
// update the object with a flag stating that the opt-in notice has been seen
|
||||
const updatedAttributes: TelemetrySavedObjectAttributes = {
|
||||
...telemetrySavedObject,
|
||||
userHasSeenNotice: true,
|
||||
// We need to store that the user was notified in this version.
|
||||
// Otherwise, it'll continuously show the banner if previously opted-out.
|
||||
lastVersionChecked: currentKibanaVersion,
|
||||
};
|
||||
await updateTelemetrySavedObject(soClient, updatedAttributes);
|
||||
|
||||
const body: v2.Telemetry = {
|
||||
allowChangingOptInStatus: updatedAttributes.allowChangingOptInStatus,
|
||||
enabled: updatedAttributes.enabled,
|
||||
lastReported: updatedAttributes.lastReported,
|
||||
lastVersionChecked: updatedAttributes.lastVersionChecked,
|
||||
reportFailureCount: updatedAttributes.reportFailureCount,
|
||||
reportFailureVersion: updatedAttributes.reportFailureVersion,
|
||||
sendUsageFrom: updatedAttributes.sendUsageFrom,
|
||||
userHasSeenNotice: updatedAttributes.userHasSeenNotice,
|
||||
};
|
||||
return res.ok({ body });
|
||||
}
|
||||
);
|
||||
const body: v2.Telemetry = {
|
||||
allowChangingOptInStatus: updatedAttributes.allowChangingOptInStatus,
|
||||
enabled: updatedAttributes.enabled,
|
||||
lastReported: updatedAttributes.lastReported,
|
||||
lastVersionChecked: updatedAttributes.lastVersionChecked,
|
||||
reportFailureCount: updatedAttributes.reportFailureCount,
|
||||
reportFailureVersion: updatedAttributes.reportFailureVersion,
|
||||
sendUsageFrom: updatedAttributes.sendUsageFrom,
|
||||
userHasSeenNotice: updatedAttributes.userHasSeenNotice,
|
||||
};
|
||||
return res.ok({ body });
|
||||
};
|
||||
|
||||
router.versioned
|
||||
.put({ access: 'internal', path: UserHasSeenNoticeRoute })
|
||||
// Just because it used to be /v2/, we are creating identical v1 and v2.
|
||||
.addVersion({ version: '1', validate: false }, v2Handler)
|
||||
.addVersion({ version: '2', validate: false }, v2Handler);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
"@kbn/std",
|
||||
"@kbn/core-http-browser-mocks",
|
||||
"@kbn/core-http-browser",
|
||||
"@kbn/core-http-server",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -11,6 +11,10 @@ import expect from '@kbn/expect';
|
|||
import SuperTest from 'supertest';
|
||||
import type { KbnClient } from '@kbn/test';
|
||||
import type { TelemetrySavedObjectAttributes } from '@kbn/telemetry-plugin/server/saved_objects';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function optInTest({ getService }: FtrProviderContext) {
|
||||
|
@ -18,7 +22,7 @@ export default function optInTest({ getService }: FtrProviderContext) {
|
|||
const kibanaServer = getService('kibanaServer');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('/api/telemetry/v2/optIn API', () => {
|
||||
describe('/internal/telemetry/optIn API', () => {
|
||||
let defaultAttributes: TelemetrySavedObjectAttributes;
|
||||
let kibanaVersion: string;
|
||||
before(async () => {
|
||||
|
@ -88,8 +92,10 @@ async function postTelemetryV2OptIn(
|
|||
statusCode: number
|
||||
): Promise<any> {
|
||||
const { body } = await supertest
|
||||
.post('/api/telemetry/v2/optIn')
|
||||
.post('/internal/telemetry/optIn')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ enabled: value })
|
||||
.expect(statusCode);
|
||||
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
*/
|
||||
|
||||
import { AxiosError } from 'axios';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
const TELEMETRY_SO_TYPE = 'telemetry';
|
||||
|
@ -16,110 +20,146 @@ export default function telemetryConfigTest({ getService }: FtrProviderContext)
|
|||
const kbnClient = getService('kibanaServer');
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('/api/telemetry/v2/config API Telemetry config', () => {
|
||||
before(async () => {
|
||||
try {
|
||||
await kbnClient.savedObjects.delete({ type: TELEMETRY_SO_TYPE, id: TELEMETRY_SO_ID });
|
||||
} catch (err) {
|
||||
const is404Error = err instanceof AxiosError && err.response?.status === 404;
|
||||
if (!is404Error) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('GET should get the default config', async () => {
|
||||
await supertest.get('/api/telemetry/v2/config').set('kbn-xsrf', 'xxx').expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: null, // the config.js for this FTR sets it to `false`, we are bound to ask again.
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false, // it's not opted-in by default (that's what this flag is about)
|
||||
});
|
||||
});
|
||||
|
||||
it('GET should get `true` when opted-in', async () => {
|
||||
// Opt-in
|
||||
await supertest
|
||||
.post('/api/telemetry/v2/optIn')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ enabled: true })
|
||||
.expect(200);
|
||||
|
||||
await supertest.get('/api/telemetry/v2/config').set('kbn-xsrf', 'xxx').expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: true,
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('GET should get false when opted-out', async () => {
|
||||
// Opt-in
|
||||
await supertest
|
||||
.post('/api/telemetry/v2/optIn')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ enabled: false })
|
||||
.expect(200);
|
||||
|
||||
await supertest.get('/api/telemetry/v2/config').set('kbn-xsrf', 'xxx').expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: false,
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false,
|
||||
});
|
||||
});
|
||||
|
||||
describe('From a previous version', function () {
|
||||
this.tags(['skipCloud']);
|
||||
|
||||
// Get current values
|
||||
let attributes: Record<string, unknown>;
|
||||
let currentVersion: string;
|
||||
let previousMinor: string;
|
||||
|
||||
before(async () => {
|
||||
[{ attributes }, currentVersion] = await Promise.all([
|
||||
kbnClient.savedObjects.get({ type: TELEMETRY_SO_TYPE, id: TELEMETRY_SO_ID }),
|
||||
kbnClient.version.get(),
|
||||
]);
|
||||
|
||||
const [major, minor, patch] = currentVersion.match(/^(\d+)\.(\d+)\.(\d+)/)!.map(parseInt);
|
||||
previousMinor = `${minor === 0 ? major - 1 : major}.${
|
||||
minor === 0 ? minor : minor - 1
|
||||
}.${patch}`;
|
||||
});
|
||||
|
||||
it('GET should get `true` when opted-in in the current version', async () => {
|
||||
// Opt-in from a previous version
|
||||
await kbnClient.savedObjects.create({
|
||||
overwrite: true,
|
||||
type: TELEMETRY_SO_TYPE,
|
||||
id: TELEMETRY_SO_ID,
|
||||
attributes: { ...attributes, enabled: true, lastVersionChecked: previousMinor },
|
||||
describe('API Telemetry config', () => {
|
||||
['/api/telemetry/v2/config', '/internal/telemetry/config'].forEach((api) => {
|
||||
describe(`GET ${api}`, () => {
|
||||
const apiVersion = api === '/api/telemetry/v2/config' ? '2023-10-31' : '2';
|
||||
before(async () => {
|
||||
try {
|
||||
await kbnClient.savedObjects.delete({ type: TELEMETRY_SO_TYPE, id: TELEMETRY_SO_ID });
|
||||
} catch (err) {
|
||||
const is404Error = err instanceof AxiosError && err.response?.status === 404;
|
||||
if (!is404Error) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await supertest.get('/api/telemetry/v2/config').set('kbn-xsrf', 'xxx').expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: true,
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('GET should get `null` when opted-out in a previous version', async () => {
|
||||
// Opt-out from previous version
|
||||
await kbnClient.savedObjects.create({
|
||||
overwrite: true,
|
||||
type: TELEMETRY_SO_TYPE,
|
||||
id: TELEMETRY_SO_ID,
|
||||
attributes: { ...attributes, enabled: false, lastVersionChecked: previousMinor },
|
||||
it('GET should get the default config', async () => {
|
||||
await supertest
|
||||
.get(api)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, apiVersion)
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: null, // the config.js for this FTR sets it to `false`, we are bound to ask again.
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false, // it's not opted-in by default (that's what this flag is about)
|
||||
});
|
||||
});
|
||||
|
||||
await supertest.get('/api/telemetry/v2/config').set('kbn-xsrf', 'xxx').expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: null,
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false,
|
||||
it('GET should get `true` when opted-in', async () => {
|
||||
// Opt-in
|
||||
await supertest
|
||||
.post('/internal/telemetry/optIn')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ enabled: true })
|
||||
.expect(200);
|
||||
|
||||
await supertest
|
||||
.get(api)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, apiVersion)
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: true,
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('GET should get false when opted-out', async () => {
|
||||
// Opt-in
|
||||
await supertest
|
||||
.post('/internal/telemetry/optIn')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ enabled: false })
|
||||
.expect(200);
|
||||
|
||||
await supertest
|
||||
.get(api)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, apiVersion)
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: false,
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false,
|
||||
});
|
||||
});
|
||||
|
||||
describe('From a previous version', function () {
|
||||
this.tags(['skipCloud']);
|
||||
|
||||
// Get current values
|
||||
let attributes: Record<string, unknown>;
|
||||
let currentVersion: string;
|
||||
let previousMinor: string;
|
||||
|
||||
before(async () => {
|
||||
[{ attributes }, currentVersion] = await Promise.all([
|
||||
kbnClient.savedObjects.get({ type: TELEMETRY_SO_TYPE, id: TELEMETRY_SO_ID }),
|
||||
kbnClient.version.get(),
|
||||
]);
|
||||
|
||||
const [major, minor, patch] = currentVersion
|
||||
.match(/^(\d+)\.(\d+)\.(\d+)/)!
|
||||
.map(parseInt);
|
||||
previousMinor = `${minor === 0 ? major - 1 : major}.${
|
||||
minor === 0 ? minor : minor - 1
|
||||
}.${patch}`;
|
||||
});
|
||||
|
||||
it('GET should get `true` when opted-in in the current version', async () => {
|
||||
// Opt-in from a previous version
|
||||
await kbnClient.savedObjects.create({
|
||||
overwrite: true,
|
||||
type: TELEMETRY_SO_TYPE,
|
||||
id: TELEMETRY_SO_ID,
|
||||
attributes: { ...attributes, enabled: true, lastVersionChecked: previousMinor },
|
||||
});
|
||||
|
||||
await supertest
|
||||
.get(api)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, apiVersion)
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: true,
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('GET should get `null` when opted-out in a previous version', async () => {
|
||||
// Opt-out from previous version
|
||||
await kbnClient.savedObjects.create({
|
||||
overwrite: true,
|
||||
type: TELEMETRY_SO_TYPE,
|
||||
id: TELEMETRY_SO_ID,
|
||||
attributes: { ...attributes, enabled: false, lastVersionChecked: previousMinor },
|
||||
});
|
||||
|
||||
await supertest
|
||||
.get(api)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, apiVersion)
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200, {
|
||||
allowChangingOptInStatus: true,
|
||||
optIn: null,
|
||||
sendUsageFrom: 'server',
|
||||
telemetryNotifyUserAboutOptInDefault: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,23 +7,37 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function optInTest({ getService }: FtrProviderContext) {
|
||||
const client = getService('kibanaServer');
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('/api/telemetry/v2/last_reported API Telemetry lastReported', () => {
|
||||
describe('/internal/telemetry/last_reported API Telemetry lastReported', () => {
|
||||
before(async () => {
|
||||
await client.savedObjects.delete({ type: 'telemetry', id: 'telemetry' });
|
||||
});
|
||||
|
||||
it('GET should return undefined when there is no stored telemetry.lastReported value', async () => {
|
||||
await supertest.get('/api/telemetry/v2/last_reported').set('kbn-xsrf', 'xxx').expect(200, {});
|
||||
await supertest
|
||||
.get('/internal/telemetry/last_reported')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200, {});
|
||||
});
|
||||
|
||||
it('PUT should update telemetry.lastReported to now', async () => {
|
||||
await supertest.put('/api/telemetry/v2/last_reported').set('kbn-xsrf', 'xxx').expect(200);
|
||||
await supertest
|
||||
.put('/internal/telemetry/last_reported')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200);
|
||||
|
||||
const {
|
||||
attributes: { lastReported },
|
||||
|
@ -46,8 +60,10 @@ export default function optInTest({ getService }: FtrProviderContext) {
|
|||
expect(lastReported).to.be.a('number');
|
||||
|
||||
await supertest
|
||||
.get('/api/telemetry/v2/last_reported')
|
||||
.get('/internal/telemetry/last_reported')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200, { lastReported });
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,17 +7,26 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function optInTest({ getService }: FtrProviderContext) {
|
||||
const client = getService('kibanaServer');
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('/api/telemetry/v2/userHasSeenNotice API Telemetry User has seen OptIn Notice', () => {
|
||||
describe('/internal/telemetry/userHasSeenNotice API Telemetry User has seen OptIn Notice', () => {
|
||||
it('should update telemetry setting field via PUT', async () => {
|
||||
await client.savedObjects.delete({ type: 'telemetry', id: 'telemetry' });
|
||||
|
||||
await supertest.put('/api/telemetry/v2/userHasSeenNotice').set('kbn-xsrf', 'xxx').expect(200);
|
||||
await supertest
|
||||
.put('/internal/telemetry/userHasSeenNotice')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.expect(200);
|
||||
|
||||
const {
|
||||
attributes: { userHasSeenNotice },
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
import expect from '@kbn/expect';
|
||||
import { KBN_SCREENSHOT_MODE_ENABLED_KEY } from '@kbn/screenshot-mode-plugin/public';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
const TELEMETRY_SO_TYPE = 'telemetry';
|
||||
|
@ -83,8 +87,10 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
|
||||
it('does not show the banner if opted-in', async () => {
|
||||
await supertest
|
||||
.post('/api/telemetry/v2/optIn')
|
||||
.post('/internal/telemetry/optIn')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ enabled: true })
|
||||
.expect(200);
|
||||
|
||||
|
@ -95,8 +101,10 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
|
||||
it('does not show the banner if opted-out in this version', async () => {
|
||||
await supertest
|
||||
.post('/api/telemetry/v2/optIn')
|
||||
.post('/internal/telemetry/optIn')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ enabled: false })
|
||||
.expect(200);
|
||||
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
export const name = 'telemetry';
|
||||
export const description = 'Get the clusters stats from the Kibana server';
|
||||
export const method = 'POST';
|
||||
export const path = '/api/telemetry/v2/clusters/_stats';
|
||||
export const path = '/internal/telemetry/clusters/_stats';
|
||||
|
||||
export const body = { unencrypted: true, refreshCache: true };
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
import expect from '@kbn/expect';
|
||||
import { SuperTest } from 'supertest';
|
||||
import { CSV_QUOTE_VALUES_SETTING } from '@kbn/share-plugin/common/constants';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export default function featureControlsTests({ getService }: FtrProviderContext) {
|
||||
|
@ -64,9 +68,11 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
|
|||
const basePath = spaceId ? `/s/${spaceId}` : '';
|
||||
|
||||
return await supertest
|
||||
.post(`${basePath}/api/telemetry/v2/optIn`)
|
||||
.post(`${basePath}/internal/telemetry/optIn`)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ enabled: true })
|
||||
.then((response: any) => ({ error: undefined, response }))
|
||||
.catch((error: any) => ({ error, response: undefined }));
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
import expect from '@kbn/expect';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
|
@ -17,7 +21,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const {
|
||||
body: [{ stats: apiResponse }],
|
||||
} = await supertest
|
||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
||||
.post(`/internal/telemetry/clusters/_stats`)
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({
|
||||
unencrypted: true,
|
||||
|
|
|
@ -21,6 +21,10 @@ import type {
|
|||
CacheDetails,
|
||||
} from '@kbn/telemetry-collection-manager-plugin/server/types';
|
||||
import { assertTelemetryPayload } from '@kbn/telemetry-tools';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import basicClusterFixture from './fixtures/basiccluster.json';
|
||||
import multiClusterFixture from './fixtures/multicluster.json';
|
||||
import type { SecurityService } from '../../../../../test/common/services/security/security';
|
||||
|
@ -97,7 +101,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const esSupertest = getService('esSupertest');
|
||||
const security = getService('security');
|
||||
|
||||
describe('/api/telemetry/v2/clusters/_stats', () => {
|
||||
describe('/internal/telemetry/clusters/_stats', () => {
|
||||
const timestamp = new Date().toISOString();
|
||||
describe('monitoring/multicluster', () => {
|
||||
let localXPack: Record<string, unknown>;
|
||||
|
@ -112,8 +116,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await updateMonitoringDates(esSupertest, fromTimestamp, toTimestamp, timestamp);
|
||||
|
||||
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true, refreshCache: true })
|
||||
.expect(200);
|
||||
|
||||
|
@ -167,8 +173,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
after(() => esArchiver.unload(archive));
|
||||
it('should load non-expiring basic cluster', async () => {
|
||||
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true, refreshCache: true })
|
||||
.expect(200);
|
||||
|
||||
|
@ -193,8 +201,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await updateMonitoringDates(esSupertest, fromTimestamp, toTimestamp, timestamp);
|
||||
// hit the endpoint to cache results
|
||||
await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true, refreshCache: true })
|
||||
.expect(200);
|
||||
});
|
||||
|
@ -204,8 +214,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
it('returns non-cached results when unencrypted', async () => {
|
||||
const now = Date.now();
|
||||
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true })
|
||||
.expect(200);
|
||||
|
||||
|
@ -224,8 +236,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
it('grabs a fresh copy on refresh', async () => {
|
||||
const now = Date.now();
|
||||
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true, refreshCache: true })
|
||||
.expect(200);
|
||||
|
||||
|
@ -243,16 +257,20 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
describe('superadmin user', () => {
|
||||
it('should return unencrypted telemetry for the admin user', async () => {
|
||||
await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true })
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('should return encrypted telemetry for the admin user', async () => {
|
||||
await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: false })
|
||||
.expect(200);
|
||||
});
|
||||
|
@ -281,18 +299,22 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
it('should return encrypted telemetry for the global-read user', async () => {
|
||||
await supertestWithoutAuth
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.auth(globalReadOnlyUser, password(globalReadOnlyUser))
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: false })
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('should return unencrypted telemetry for the global-read user', async () => {
|
||||
await supertestWithoutAuth
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.auth(globalReadOnlyUser, password(globalReadOnlyUser))
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true })
|
||||
.expect(200);
|
||||
});
|
||||
|
@ -330,18 +352,22 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
it('should return encrypted telemetry for the read-only user', async () => {
|
||||
await supertestWithoutAuth
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.auth(noGlobalUser, password(noGlobalUser))
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: false })
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('should return 403 when the read-only user requests unencrypted telemetry', async () => {
|
||||
await supertestWithoutAuth
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.auth(noGlobalUser, password(noGlobalUser))
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true })
|
||||
.expect(403);
|
||||
});
|
||||
|
|
|
@ -12,6 +12,10 @@ import ossPluginsTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_plugins.
|
|||
import xpackRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_root.json';
|
||||
import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json';
|
||||
import { assertTelemetryPayload } from '@kbn/telemetry-tools';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import { flatKeys } from '../../../../../test/api_integration/apis/telemetry/utils';
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
|
@ -31,7 +35,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const supertest = getService('supertest');
|
||||
const es = getService('es');
|
||||
|
||||
describe('/api/telemetry/v2/clusters/_stats with monitoring disabled', () => {
|
||||
describe('/internal/telemetry/clusters/_stats with monitoring disabled', () => {
|
||||
let stats: Record<string, any>;
|
||||
|
||||
before('disable monitoring and pull local stats', async () => {
|
||||
|
@ -39,8 +43,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await new Promise((r) => setTimeout(r, 1000));
|
||||
|
||||
const { body } = await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true, refreshCache: true })
|
||||
.expect(200);
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
*/
|
||||
|
||||
import { UsageStatsPayload } from '@kbn/telemetry-collection-manager-plugin/server';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import { FtrProviderContext } from '../ftr_provider_context';
|
||||
|
||||
export interface UsageStatsPayloadTestFriendly extends UsageStatsPayload {
|
||||
|
@ -29,9 +33,10 @@ export function UsageAPIProvider({ getService }: FtrProviderContext) {
|
|||
refreshCache?: boolean;
|
||||
}): Promise<Array<{ clusterUuid: string; stats: UsageStatsPayloadTestFriendly | string }>> {
|
||||
const { body } = await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('x-elastic-internal-origin', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ refreshCache: true, ...payload })
|
||||
.expect(200);
|
||||
return body;
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import { data, MockTelemetryFindings } from './data';
|
||||
import type { FtrProviderContext } from '../ftr_provider_context';
|
||||
|
||||
|
@ -67,7 +70,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const {
|
||||
body: [{ stats: apiResponse }],
|
||||
} = await supertest
|
||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
||||
.post(`/internal/telemetry/clusters/_stats`)
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({
|
||||
unencrypted: true,
|
||||
|
@ -119,8 +124,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const {
|
||||
body: [{ stats: apiResponse }],
|
||||
} = await supertest
|
||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
||||
.post(`/internal/telemetry/clusters/_stats`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({
|
||||
unencrypted: true,
|
||||
refreshCache: true,
|
||||
|
@ -164,8 +171,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const {
|
||||
body: [{ stats: apiResponse }],
|
||||
} = await supertest
|
||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
||||
.post(`/internal/telemetry/clusters/_stats`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({
|
||||
unencrypted: true,
|
||||
refreshCache: true,
|
||||
|
@ -240,8 +249,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const {
|
||||
body: [{ stats: apiResponse }],
|
||||
} = await supertest
|
||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
||||
.post(`/internal/telemetry/clusters/_stats`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({
|
||||
unencrypted: true,
|
||||
refreshCache: true,
|
||||
|
@ -294,8 +305,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const {
|
||||
body: [{ stats: apiResponse }],
|
||||
} = await supertest
|
||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
||||
.post(`/internal/telemetry/clusters/_stats`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({
|
||||
unencrypted: true,
|
||||
refreshCache: true,
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import type SuperTest from 'supertest';
|
||||
import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
|
||||
import { getStatsUrl } from './get_stats_url';
|
||||
import { getDetectionMetricsFromBody } from './get_detection_metrics_from_body';
|
||||
|
@ -24,6 +28,8 @@ export const getStats = async (
|
|||
const response = await supertest
|
||||
.post(getStatsUrl())
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true, refreshCache: true });
|
||||
if (response.status !== 200) {
|
||||
log.error(
|
||||
|
|
|
@ -8,4 +8,4 @@
|
|||
/**
|
||||
* Cluster stats URL. Replace this with any from kibana core if there is ever a constant there for this.
|
||||
*/
|
||||
export const getStatsUrl = (): string => '/api/telemetry/v2/clusters/_stats';
|
||||
export const getStatsUrl = (): string => '/internal/telemetry/clusters/_stats';
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../api_integration/ftr_provider_context';
|
||||
import { skipIfNoDockerRegistry, generateAgent } from '../helpers';
|
||||
|
@ -124,8 +128,10 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const {
|
||||
body: [{ stats: apiResponse }],
|
||||
} = await supertest
|
||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
||||
.post(`/internal/telemetry/clusters/_stats`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({
|
||||
unencrypted: true,
|
||||
refreshCache: true,
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import { DATES } from './constants';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
@ -133,8 +137,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
await logsUi.logStreamPage.getStreamEntries();
|
||||
|
||||
const [{ stats }] = await supertest
|
||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
||||
.post(`/internal/telemetry/clusters/_stats`)
|
||||
.set(COMMON_REQUEST_HEADERS)
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.set('Accept', 'application/json')
|
||||
.send({
|
||||
unencrypted: true,
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
import expect from '@kbn/expect';
|
||||
import type { FtrProviderContext } from '../ftr_provider_context';
|
||||
import { assertLogContains, isExecutionContextLog, ANY } from '../test_utils';
|
||||
|
@ -111,8 +115,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
it('propagates context for Telemetry collection', async () => {
|
||||
await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: false })
|
||||
.expect(200);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"journeyName": "POST /api/telemetry/v2/clusters/_stats - 1600 dataviews",
|
||||
"journeyName": "POST /internal/telemetry/clusters/_stats - 1600 dataviews",
|
||||
"scalabilitySetup": {
|
||||
"warmup": [
|
||||
{
|
||||
|
@ -30,13 +30,15 @@
|
|||
{
|
||||
"http": {
|
||||
"method": "POST",
|
||||
"path": "/api/telemetry/v2/clusters/_stats",
|
||||
"path": "/internal/telemetry/clusters/_stats",
|
||||
"body": "{}",
|
||||
"headers": {
|
||||
"Cookie": "",
|
||||
"Kbn-Version": "",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Content-Type": "application/json"
|
||||
"Content-Type": "application/json",
|
||||
"elastic-api-version": "2",
|
||||
"x-elastic-internal-origin": "kibana"
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"journeyName": "POST /api/telemetry/v2/clusters/_stats",
|
||||
"journeyName": "POST /internal/telemetry/clusters/_stats",
|
||||
"scalabilitySetup": {
|
||||
"warmup": [
|
||||
{
|
||||
|
@ -28,13 +28,15 @@
|
|||
{
|
||||
"http": {
|
||||
"method": "POST",
|
||||
"path": "/api/telemetry/v2/clusters/_stats",
|
||||
"path": "/internal/telemetry/clusters/_stats",
|
||||
"body": "{}",
|
||||
"headers": {
|
||||
"Cookie": "",
|
||||
"Kbn-Version": "",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Content-Type": "application/json"
|
||||
"Content-Type": "application/json",
|
||||
"elastic-api-version": "2",
|
||||
"x-elastic-internal-origin": "kibana"
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"journeyName": "POST /api/telemetry/v2/clusters/_stats - no cache - 1600 dataviews",
|
||||
"journeyName": "POST /internal/telemetry/clusters/_stats - no cache - 1600 dataviews",
|
||||
"scalabilitySetup": {
|
||||
"responseTimeThreshold": {
|
||||
"threshold1": 1000,
|
||||
|
@ -35,13 +35,15 @@
|
|||
{
|
||||
"http": {
|
||||
"method": "POST",
|
||||
"path": "/api/telemetry/v2/clusters/_stats",
|
||||
"path": "/internal/telemetry/clusters/_stats",
|
||||
"body": "{ \"refreshCache\": true }",
|
||||
"headers": {
|
||||
"Cookie": "",
|
||||
"Kbn-Version": "",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Content-Type": "application/json"
|
||||
"Content-Type": "application/json",
|
||||
"elastic-api-version": "2",
|
||||
"x-elastic-internal-origin": "kibana"
|
||||
},
|
||||
"timeout": 240000,
|
||||
"statusCode": 200
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"journeyName": "POST /api/telemetry/v2/clusters/_stats - no cache",
|
||||
"journeyName": "POST /internal/telemetry/clusters/_stats - no cache",
|
||||
"scalabilitySetup": {
|
||||
"responseTimeThreshold": {
|
||||
"threshold1": 1000,
|
||||
|
@ -33,13 +33,15 @@
|
|||
{
|
||||
"http": {
|
||||
"method": "POST",
|
||||
"path": "/api/telemetry/v2/clusters/_stats",
|
||||
"path": "/internal/telemetry/clusters/_stats",
|
||||
"body": "{ \"refreshCache\": true }",
|
||||
"headers": {
|
||||
"Cookie": "",
|
||||
"Kbn-Version": "",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Content-Type": "application/json"
|
||||
"Content-Type": "application/json",
|
||||
"elastic-api-version": "2",
|
||||
"x-elastic-internal-origin": "kibana"
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue