mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51: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.
|
*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.
|
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).
|
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]
|
[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"},
|
"log":{"level":"DEBUG","logger":"http.server.response"},
|
||||||
"trace":{"id":"9b99131a6f66587971ef085ef97dfd07"},
|
"trace":{"id":"9b99131a6f66587971ef085ef97dfd07"},
|
||||||
"transaction":{"id":"d0c5bbf14f5febca"}
|
"transaction":{"id":"d0c5bbf14f5febca"}
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
* Side Public License, v 1.
|
* 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';
|
import { setupIntegrationEnvironment, TestEnvironmentUtils } from '../../test_utils';
|
||||||
|
|
||||||
describe('Files usage telemetry', () => {
|
describe('Files usage telemetry', () => {
|
||||||
|
@ -45,7 +49,9 @@ describe('Files usage telemetry', () => {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const { body } = await request
|
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 });
|
.send({ unencrypted: true });
|
||||||
|
|
||||||
expect(body[0].stats.stack_stats.kibana.plugins.files).toMatchInlineSnapshot(`
|
expect(body[0].stats.stack_stats.kibana.plugins.files).toMatchInlineSnapshot(`
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"@kbn/core-elasticsearch-server-mocks",
|
"@kbn/core-elasticsearch-server-mocks",
|
||||||
"@kbn/core-saved-objects-server-mocks",
|
"@kbn/core-saved-objects-server-mocks",
|
||||||
"@kbn/logging",
|
"@kbn/logging",
|
||||||
|
"@kbn/core-http-common",
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"target/**/*",
|
"target/**/*",
|
||||||
|
|
|
@ -6,7 +6,49 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const BASE_INTERNAL_PATH = '/internal/telemetry';
|
||||||
|
|
||||||
|
export const INTERNAL_VERSION = { version: '2' };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch Telemetry Config
|
* 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 * 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';
|
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 { ElasticV3BrowserShipper } from '@kbn/analytics-shippers-elastic-v3-browser';
|
||||||
|
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { FetchTelemetryConfigRoute } from '../common/routes';
|
import { FetchTelemetryConfigRoute, INTERNAL_VERSION } from '../common/routes';
|
||||||
import type { v2 } from '../common/types';
|
import type { v2 } from '../common/types';
|
||||||
import { TelemetrySender, TelemetryService, TelemetryNotifications } from './services';
|
import { TelemetrySender, TelemetryService, TelemetryNotifications } from './services';
|
||||||
import { renderWelcomeTelemetryNotice } from './render_welcome_telemetry_notice';
|
import { renderWelcomeTelemetryNotice } from './render_welcome_telemetry_notice';
|
||||||
|
@ -329,7 +329,7 @@ export class TelemetryPlugin
|
||||||
*/
|
*/
|
||||||
private async fetchUpdatedConfig(http: HttpStart | HttpSetup): Promise<TelemetryPluginConfig> {
|
private async fetchUpdatedConfig(http: HttpStart | HttpSetup): Promise<TelemetryPluginConfig> {
|
||||||
const { allowChangingOptInStatus, optIn, sendUsageFrom, telemetryNotifyUserAboutOptInDefault } =
|
const { allowChangingOptInStatus, optIn, sendUsageFrom, telemetryNotifyUserAboutOptInDefault } =
|
||||||
await http.get<v2.FetchTelemetryConfigResponse>(FetchTelemetryConfigRoute);
|
await http.get<v2.FetchTelemetryConfigResponse>(FetchTelemetryConfigRoute, INTERNAL_VERSION);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...this.config,
|
...this.config,
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
/* eslint-disable dot-notation */
|
/* eslint-disable dot-notation */
|
||||||
|
|
||||||
import { mockTelemetryService } from '../mocks';
|
import { mockTelemetryService } from '../mocks';
|
||||||
|
import {
|
||||||
|
FetchSnapshotTelemetry,
|
||||||
|
INTERNAL_VERSION,
|
||||||
|
OptInRoute,
|
||||||
|
UserHasSeenNoticeRoute,
|
||||||
|
} from '../../common/routes';
|
||||||
|
|
||||||
describe('TelemetryService', () => {
|
describe('TelemetryService', () => {
|
||||||
describe('fetchTelemetry', () => {
|
describe('fetchTelemetry', () => {
|
||||||
|
@ -17,7 +23,8 @@ describe('TelemetryService', () => {
|
||||||
const telemetryService = mockTelemetryService();
|
const telemetryService = mockTelemetryService();
|
||||||
|
|
||||||
await telemetryService.fetchTelemetry();
|
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 }),
|
body: JSON.stringify({ unencrypted: false, refreshCache: false }),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -64,7 +71,8 @@ describe('TelemetryService', () => {
|
||||||
const optedIn = true;
|
const optedIn = true;
|
||||||
await telemetryService.setOptIn(optedIn);
|
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 }),
|
body: JSON.stringify({ enabled: optedIn }),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -77,7 +85,8 @@ describe('TelemetryService', () => {
|
||||||
const optedIn = false;
|
const optedIn = false;
|
||||||
await telemetryService.setOptIn(optedIn);
|
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 }),
|
body: JSON.stringify({ enabled: optedIn }),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -110,7 +119,7 @@ describe('TelemetryService', () => {
|
||||||
config: { allowChangingOptInStatus: true },
|
config: { allowChangingOptInStatus: true },
|
||||||
});
|
});
|
||||||
telemetryService['http'].post = jest.fn().mockImplementation((url: string) => {
|
telemetryService['http'].post = jest.fn().mockImplementation((url: string) => {
|
||||||
if (url === '/api/telemetry/v2/optIn') {
|
if (url === OptInRoute) {
|
||||||
throw Error('failed to update opt in.');
|
throw Error('failed to update opt in.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -203,7 +212,7 @@ describe('TelemetryService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
telemetryService['http'].put = jest.fn().mockImplementation((url: string) => {
|
telemetryService['http'].put = jest.fn().mockImplementation((url: string) => {
|
||||||
if (url === '/api/telemetry/v2/userHasSeenNotice') {
|
if (url === UserHasSeenNoticeRoute) {
|
||||||
throw Error('failed to update opt in.');
|
throw Error('failed to update opt in.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,11 +8,19 @@
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import type { CoreSetup, CoreStart } from '@kbn/core/public';
|
import type { CoreSetup, CoreStart } from '@kbn/core/public';
|
||||||
|
import {
|
||||||
|
LastReportedRoute,
|
||||||
|
INTERNAL_VERSION,
|
||||||
|
OptInRoute,
|
||||||
|
FetchSnapshotTelemetry,
|
||||||
|
UserHasSeenNoticeRoute,
|
||||||
|
} from '../../common/routes';
|
||||||
import type { TelemetryPluginConfig } from '../plugin';
|
import type { TelemetryPluginConfig } from '../plugin';
|
||||||
import { getTelemetryChannelEndpoint } from '../../common/telemetry_config/get_telemetry_channel_endpoint';
|
import { getTelemetryChannelEndpoint } from '../../common/telemetry_config';
|
||||||
import type {
|
import type {
|
||||||
UnencryptedTelemetryPayload,
|
UnencryptedTelemetryPayload,
|
||||||
EncryptedTelemetryPayload,
|
EncryptedTelemetryPayload,
|
||||||
|
FetchLastReportedResponse,
|
||||||
} from '../../common/types/latest';
|
} from '../../common/types/latest';
|
||||||
import { PAYLOAD_CONTENT_ENCODING } from '../../common/constants';
|
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 **/
|
/** Is the cluster allowed to change the opt-in/out status **/
|
||||||
public getCanChangeOptInStatus = () => {
|
public getCanChangeOptInStatus = () => {
|
||||||
const allowChangingOptInStatus = this.config.allowChangingOptInStatus;
|
return this.config.allowChangingOptInStatus;
|
||||||
return allowChangingOptInStatus;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Retrieve the opt-in/out notification URL **/
|
/** Retrieve the opt-in/out notification URL **/
|
||||||
|
@ -156,17 +163,18 @@ export class TelemetryService {
|
||||||
};
|
};
|
||||||
|
|
||||||
public fetchLastReported = async (): Promise<number | undefined> => {
|
public fetchLastReported = async (): Promise<number | undefined> => {
|
||||||
const response = await this.http.get<{ lastReported?: number }>(
|
const response = await this.http.get<FetchLastReportedResponse>(
|
||||||
'/api/telemetry/v2/last_reported'
|
LastReportedRoute,
|
||||||
|
INTERNAL_VERSION
|
||||||
);
|
);
|
||||||
return response?.lastReported;
|
return response?.lastReported;
|
||||||
};
|
};
|
||||||
|
|
||||||
public updateLastReported = async (): Promise<number | undefined> => {
|
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> => {
|
public fetchExample = async (): Promise<UnencryptedTelemetryPayload> => {
|
||||||
return await this.fetchTelemetry({ unencrypted: true, refreshCache: true });
|
return await this.fetchTelemetry({ unencrypted: true, refreshCache: true });
|
||||||
};
|
};
|
||||||
|
@ -174,12 +182,14 @@ export class TelemetryService {
|
||||||
/**
|
/**
|
||||||
* Fetches telemetry payload
|
* Fetches telemetry payload
|
||||||
* @param unencrypted Default `false`. Whether the returned payload should be encrypted or not.
|
* @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>({
|
public fetchTelemetry = async <T = EncryptedTelemetryPayload | UnencryptedTelemetryPayload>({
|
||||||
unencrypted = false,
|
unencrypted = false,
|
||||||
refreshCache = false,
|
refreshCache = false,
|
||||||
} = {}): Promise<T> => {
|
} = {}): Promise<T> => {
|
||||||
return this.http.post('/api/telemetry/v2/clusters/_stats', {
|
return this.http.post(FetchSnapshotTelemetry, {
|
||||||
|
...INTERNAL_VERSION,
|
||||||
body: JSON.stringify({ unencrypted, refreshCache }),
|
body: JSON.stringify({ unencrypted, refreshCache }),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -198,12 +208,10 @@ export class TelemetryService {
|
||||||
try {
|
try {
|
||||||
// Report the option to the Kibana server to store the settings.
|
// 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}]
|
// It returns the encrypted update to send to the telemetry cluster [{cluster_uuid, opt_in_status}]
|
||||||
const optInStatusPayload = await this.http.post<EncryptedTelemetryPayload>(
|
const optInStatusPayload = await this.http.post<EncryptedTelemetryPayload>(OptInRoute, {
|
||||||
'/api/telemetry/v2/optIn',
|
...INTERNAL_VERSION,
|
||||||
{
|
body: JSON.stringify({ enabled: optedIn }),
|
||||||
body: JSON.stringify({ enabled: optedIn }),
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
if (this.reportOptInStatusChange) {
|
if (this.reportOptInStatusChange) {
|
||||||
// Use the response to report about the change to the remote telemetry cluster.
|
// 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.
|
// 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> => {
|
public setUserHasSeenNotice = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
await this.http.put('/api/telemetry/v2/userHasSeenNotice');
|
await this.http.put(UserHasSeenNoticeRoute, INTERNAL_VERSION);
|
||||||
this.userHasSeenOptedInNotice = true;
|
this.userHasSeenOptedInNotice = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.notifications.toasts.addError(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
|
* 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 (
|
private reportOptInStatus = async (
|
||||||
optInStatusPayload: EncryptedTelemetryPayload
|
optInStatusPayload: EncryptedTelemetryPayload
|
||||||
|
|
|
@ -8,9 +8,14 @@
|
||||||
|
|
||||||
import { type Observable, firstValueFrom } from 'rxjs';
|
import { type Observable, firstValueFrom } from 'rxjs';
|
||||||
import type { IRouter, SavedObjectsClient } from '@kbn/core/server';
|
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 type { TelemetryConfigType } from '../config';
|
||||||
import { v2 } from '../../common/types';
|
import { v2 } from '../../common/types';
|
||||||
import { FetchTelemetryConfigRoute } from '../../common/routes';
|
import {
|
||||||
|
FetchTelemetryConfigRoutePathBasedV2,
|
||||||
|
FetchTelemetryConfigRoute,
|
||||||
|
} from '../../common/routes';
|
||||||
import { getTelemetrySavedObject } from '../saved_objects';
|
import { getTelemetrySavedObject } from '../saved_objects';
|
||||||
import {
|
import {
|
||||||
getNotifyUserAboutOptInDefault,
|
getNotifyUserAboutOptInDefault,
|
||||||
|
@ -25,54 +30,74 @@ interface RegisterTelemetryConfigRouteOptions {
|
||||||
currentKibanaVersion: string;
|
currentKibanaVersion: string;
|
||||||
savedObjectsInternalClient$: Observable<SavedObjectsClient>;
|
savedObjectsInternalClient$: Observable<SavedObjectsClient>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerTelemetryConfigRoutes({
|
export function registerTelemetryConfigRoutes({
|
||||||
router,
|
router,
|
||||||
config$,
|
config$,
|
||||||
currentKibanaVersion,
|
currentKibanaVersion,
|
||||||
savedObjectsInternalClient$,
|
savedObjectsInternalClient$,
|
||||||
}: RegisterTelemetryConfigRouteOptions) {
|
}: RegisterTelemetryConfigRouteOptions) {
|
||||||
// GET to retrieve
|
const v2Handler: RequestHandler = async (context, req, res) => {
|
||||||
router.get(
|
const config = await firstValueFrom(config$);
|
||||||
{
|
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||||
path: FetchTelemetryConfigRoute,
|
const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsInternalClient);
|
||||||
validate: false,
|
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({
|
// Register the internal versioned API
|
||||||
configTelemetryOptIn: config.optIn,
|
router.versioned
|
||||||
allowChangingOptInStatus,
|
.get({ access: 'internal', path: FetchTelemetryConfigRoute })
|
||||||
telemetrySavedObject,
|
// Just because it used to be /v2/, we are creating identical v1 and v2.
|
||||||
currentKibanaVersion,
|
.addVersion({ version: '1', validate: v2Validations }, v2Handler)
|
||||||
});
|
.addVersion({ version: '2', validate: v2Validations }, v2Handler);
|
||||||
|
|
||||||
const sendUsageFrom = getTelemetrySendUsageFrom({
|
// Register the deprecated public and path-based for BWC
|
||||||
configTelemetrySendUsageFrom: config.sendUsageFrom,
|
// as we know this one is used by other Elastic products to fetch the opt-in status.
|
||||||
telemetrySavedObject,
|
router.versioned
|
||||||
});
|
.get({ access: 'public', path: FetchTelemetryConfigRoutePathBasedV2 })
|
||||||
|
.addVersion({ version: '2023-10-31', validate: v2Validations }, v2Handler);
|
||||||
const telemetryNotifyUserAboutOptInDefault = getNotifyUserAboutOptInDefault({
|
|
||||||
telemetrySavedObject,
|
|
||||||
allowChangingOptInStatus,
|
|
||||||
configTelemetryOptIn: config.optIn,
|
|
||||||
telemetryOptedIn: optIn,
|
|
||||||
});
|
|
||||||
|
|
||||||
const body: v2.FetchTelemetryConfigResponse = {
|
|
||||||
allowChangingOptInStatus,
|
|
||||||
optIn,
|
|
||||||
sendUsageFrom,
|
|
||||||
telemetryNotifyUserAboutOptInDefault,
|
|
||||||
};
|
|
||||||
|
|
||||||
return res.ok({ body });
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,12 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { schema } from '@kbn/config-schema';
|
||||||
import type { IRouter, SavedObjectsClient } from '@kbn/core/server';
|
import type { IRouter, SavedObjectsClient } from '@kbn/core/server';
|
||||||
import type { Observable } from 'rxjs';
|
import type { Observable } from 'rxjs';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
import { RequestHandler } from '@kbn/core-http-server';
|
||||||
|
import { LastReportedRoute } from '../../common/routes';
|
||||||
import { v2 } from '../../common/types';
|
import { v2 } from '../../common/types';
|
||||||
import { getTelemetrySavedObject, updateTelemetrySavedObject } from '../saved_objects';
|
import { getTelemetrySavedObject, updateTelemetrySavedObject } from '../saved_objects';
|
||||||
|
|
||||||
|
@ -17,38 +20,38 @@ export function registerTelemetryLastReported(
|
||||||
savedObjectsInternalClient$: Observable<SavedObjectsClient>
|
savedObjectsInternalClient$: Observable<SavedObjectsClient>
|
||||||
) {
|
) {
|
||||||
// GET to retrieve
|
// GET to retrieve
|
||||||
router.get(
|
const v2GetValidations = {
|
||||||
{
|
response: { 200: { body: schema.object({ lastReported: schema.maybe(schema.number()) }) } },
|
||||||
path: '/api/telemetry/v2/last_reported',
|
};
|
||||||
validate: false,
|
|
||||||
},
|
|
||||||
async (context, req, res) => {
|
|
||||||
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
|
||||||
const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsInternalClient);
|
|
||||||
|
|
||||||
const body: v2.FetchLastReportedResponse = {
|
const v2GetHandler: RequestHandler = async (context, req, res) => {
|
||||||
lastReported: telemetrySavedObject && telemetrySavedObject?.lastReported,
|
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||||
};
|
const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsInternalClient);
|
||||||
|
|
||||||
return res.ok({
|
const body: v2.FetchLastReportedResponse = {
|
||||||
body,
|
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
|
// PUT to update
|
||||||
router.put(
|
const v2PutHandler: RequestHandler = async (context, req, res) => {
|
||||||
{
|
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
||||||
path: '/api/telemetry/v2/last_reported',
|
await updateTelemetrySavedObject(savedObjectsInternalClient, {
|
||||||
validate: false,
|
lastReported: Date.now(),
|
||||||
},
|
});
|
||||||
async (context, req, res) => {
|
return res.ok();
|
||||||
const savedObjectsInternalClient = await firstValueFrom(savedObjectsInternalClient$);
|
};
|
||||||
await updateTelemetrySavedObject(savedObjectsInternalClient, {
|
|
||||||
lastReported: Date.now(),
|
|
||||||
});
|
|
||||||
|
|
||||||
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 { firstValueFrom, type Observable } from 'rxjs';
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import type { IRouter, Logger } from '@kbn/core/server';
|
import type { IRouter, Logger } from '@kbn/core/server';
|
||||||
import { SavedObjectsErrorHelpers } from '@kbn/core/server';
|
import { RequestHandlerContext, SavedObjectsErrorHelpers } from '@kbn/core/server';
|
||||||
import type {
|
import type {
|
||||||
StatsGetterConfig,
|
StatsGetterConfig,
|
||||||
TelemetryCollectionManagerPluginSetup,
|
TelemetryCollectionManagerPluginSetup,
|
||||||
} from '@kbn/telemetry-collection-manager-plugin/server';
|
} 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 { sendTelemetryOptInStatus } from './telemetry_opt_in_stats';
|
||||||
import {
|
import {
|
||||||
getTelemetrySavedObject,
|
getTelemetrySavedObject,
|
||||||
|
@ -41,78 +43,91 @@ export function registerTelemetryOptInRoutes({
|
||||||
currentKibanaVersion,
|
currentKibanaVersion,
|
||||||
telemetryCollectionManager,
|
telemetryCollectionManager,
|
||||||
}: RegisterOptInRoutesParams) {
|
}: RegisterOptInRoutesParams) {
|
||||||
router.post(
|
const v2Handler: RequestHandler<undefined, undefined, OptInBody, RequestHandlerContext> = async (
|
||||||
{
|
context,
|
||||||
path: '/api/telemetry/v2/optIn',
|
req,
|
||||||
validate: {
|
res
|
||||||
body: schema.object({ enabled: schema.boolean() }),
|
) => {
|
||||||
|
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;
|
router.versioned
|
||||||
try {
|
.post({ access: 'internal', path: OptInRoute })
|
||||||
telemetrySavedObject = await getTelemetrySavedObject(soClient);
|
// Just because it used to be /v2/, we are creating identical v1 and v2.
|
||||||
} catch (err) {
|
.addVersion({ version: '1', validate: v2Validations }, v2Handler)
|
||||||
if (SavedObjectsErrorHelpers.isForbiddenError(err)) {
|
.addVersion({ version: '2', validate: v2Validations }, v2Handler);
|
||||||
// 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 });
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import type {
|
||||||
TelemetryCollectionManagerPluginSetup,
|
TelemetryCollectionManagerPluginSetup,
|
||||||
StatsGetterConfig,
|
StatsGetterConfig,
|
||||||
} from '@kbn/telemetry-collection-manager-plugin/server';
|
} from '@kbn/telemetry-collection-manager-plugin/server';
|
||||||
|
import { GetOptInStatsRoutePathBasedV2 } from '../../common/routes';
|
||||||
import type { v2 } from '../../common/types';
|
import type { v2 } from '../../common/types';
|
||||||
import { EncryptedTelemetryPayload, UnencryptedTelemetryPayload } from '../../common/types';
|
import { EncryptedTelemetryPayload, UnencryptedTelemetryPayload } from '../../common/types';
|
||||||
import { getTelemetryChannelEndpoint } from '../../common/telemetry_config';
|
import { getTelemetryChannelEndpoint } from '../../common/telemetry_config';
|
||||||
|
@ -62,43 +63,64 @@ export function registerTelemetryOptInStatsRoutes(
|
||||||
router: IRouter,
|
router: IRouter,
|
||||||
telemetryCollectionManager: TelemetryCollectionManagerPluginSetup
|
telemetryCollectionManager: TelemetryCollectionManagerPluginSetup
|
||||||
) {
|
) {
|
||||||
router.post(
|
router.versioned
|
||||||
{
|
.post({
|
||||||
path: '/api/telemetry/v2/clusters/_opt_in_stats',
|
access: 'public', // It's not used across Kibana, and I didn't want to remove it in this PR just in case.
|
||||||
validate: {
|
path: GetOptInStatsRoutePathBasedV2,
|
||||||
body: schema.object({
|
})
|
||||||
enabled: schema.boolean(),
|
.addVersion(
|
||||||
unencrypted: schema.boolean({ defaultValue: true }),
|
{
|
||||||
}),
|
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) => {
|
||||||
async (context, req, res) => {
|
try {
|
||||||
try {
|
const newOptInStatus = req.body.enabled;
|
||||||
const newOptInStatus = req.body.enabled;
|
const unencrypted = req.body.unencrypted;
|
||||||
const unencrypted = req.body.unencrypted;
|
|
||||||
|
|
||||||
if (!(await telemetryCollectionManager.shouldGetTelemetry())) {
|
if (!(await telemetryCollectionManager.shouldGetTelemetry())) {
|
||||||
// We probably won't reach here because there is a license check in the auth phase of the HTTP requests.
|
// 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.
|
// But let's keep it here should that changes at any point.
|
||||||
return res.customError({
|
return res.customError({
|
||||||
statusCode: 503,
|
statusCode: 503,
|
||||||
body: `Can't fetch telemetry at the moment because some services are down. Check the /status page for more details.`,
|
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>,
|
mockRouter: IRouter<RequestHandlerContext>,
|
||||||
body?: { unencrypted?: boolean; refreshCache?: boolean }
|
body?: { unencrypted?: boolean; refreshCache?: boolean }
|
||||||
) {
|
) {
|
||||||
expect(mockRouter.post).toBeCalled();
|
expect(mockRouter.versioned.post).toBeCalled();
|
||||||
const [, handler] = (mockRouter.post as jest.Mock).mock.calls[0];
|
const [, handler] = (mockRouter.versioned.post as jest.Mock).mock.results[0].value.addVersion.mock
|
||||||
|
.calls[0];
|
||||||
const mockResponse = httpServerMock.createResponseFactory();
|
const mockResponse = httpServerMock.createResponseFactory();
|
||||||
const mockRequest = httpServerMock.createKibanaRequest({ body });
|
const mockRequest = httpServerMock.createKibanaRequest({ body });
|
||||||
await handler(null, mockRequest, mockResponse);
|
await handler(null, mockRequest, mockResponse);
|
||||||
|
@ -49,10 +50,10 @@ describe('registerTelemetryUsageStatsRoutes', () => {
|
||||||
describe('clusters/_stats POST route', () => {
|
describe('clusters/_stats POST route', () => {
|
||||||
it('registers _stats POST route and accepts body configs', () => {
|
it('registers _stats POST route and accepts body configs', () => {
|
||||||
registerTelemetryUsageStatsRoutes(mockRouter, telemetryCollectionManager, true, getSecurity);
|
registerTelemetryUsageStatsRoutes(mockRouter, telemetryCollectionManager, true, getSecurity);
|
||||||
expect(mockRouter.post).toBeCalledTimes(1);
|
expect(mockRouter.versioned.post).toBeCalledTimes(1);
|
||||||
const [routeConfig, handler] = (mockRouter.post as jest.Mock).mock.calls[0];
|
const [routeConfig, handler] = (mockRouter.versioned.post as jest.Mock).mock.results[0].value
|
||||||
expect(routeConfig.path).toMatchInlineSnapshot(`"/api/telemetry/v2/clusters/_stats"`);
|
.addVersion.mock.calls[0];
|
||||||
expect(Object.keys(routeConfig.validate.body.props)).toEqual(['unencrypted', 'refreshCache']);
|
expect(routeConfig.version).toMatchInlineSnapshot(`"1"`);
|
||||||
expect(handler).toBeInstanceOf(Function);
|
expect(handler).toBeInstanceOf(Function);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,9 @@ import type {
|
||||||
StatsGetterConfig,
|
StatsGetterConfig,
|
||||||
} from '@kbn/telemetry-collection-manager-plugin/server';
|
} from '@kbn/telemetry-collection-manager-plugin/server';
|
||||||
import type { SecurityPluginStart } from '@kbn/security-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;
|
export type SecurityGetter = () => SecurityPluginStart | undefined;
|
||||||
|
|
||||||
|
@ -23,64 +25,75 @@ export function registerTelemetryUsageStatsRoutes(
|
||||||
isDev: boolean,
|
isDev: boolean,
|
||||||
getSecurity: SecurityGetter
|
getSecurity: SecurityGetter
|
||||||
) {
|
) {
|
||||||
router.post(
|
const v2Handler: RequestHandler<undefined, undefined, UsageStatsBody> = async (
|
||||||
{
|
context,
|
||||||
path: '/api/telemetry/v2/clusters/_stats',
|
req,
|
||||||
validate: {
|
res
|
||||||
body: schema.object({
|
) => {
|
||||||
unencrypted: schema.boolean({ defaultValue: false }),
|
const { unencrypted, refreshCache } = req.body;
|
||||||
refreshCache: schema.boolean({ defaultValue: false }),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
async (context, req, res) => {
|
|
||||||
const { unencrypted, refreshCache } = req.body;
|
|
||||||
|
|
||||||
if (!(await telemetryCollectionManager.shouldGetTelemetry())) {
|
if (!(await telemetryCollectionManager.shouldGetTelemetry())) {
|
||||||
// We probably won't reach here because there is a license check in the auth phase of the HTTP requests.
|
// 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.
|
// But let's keep it here should that changes at any point.
|
||||||
return res.customError({
|
return res.customError({
|
||||||
statusCode: 503,
|
statusCode: 503,
|
||||||
body: `Can't fetch telemetry at the moment because some services are down. Check the /status page for more details.`,
|
body: `Can't fetch telemetry at the moment because some services are down. Check the /status page for more details.`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const security = getSecurity();
|
const security = getSecurity();
|
||||||
// We need to check useRbacForRequest to figure out if ES has security enabled before making the privileges check
|
// 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)) {
|
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
|
// 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
|
// 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
|
// 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.
|
// granted to users that have "Global All" or "Global Read" privileges in Kibana.
|
||||||
const { checkPrivilegesWithRequest, actions } = security.authz;
|
const { checkPrivilegesWithRequest, actions } = security.authz;
|
||||||
const privileges = { kibana: actions.api.get('decryptedTelemetry') };
|
const privileges = { kibana: actions.api.get('decryptedTelemetry') };
|
||||||
const { hasAllRequested } = await checkPrivilegesWithRequest(req).globally(privileges);
|
const { hasAllRequested } = await checkPrivilegesWithRequest(req).globally(privileges);
|
||||||
if (!hasAllRequested) {
|
if (!hasAllRequested) {
|
||||||
return res.forbidden();
|
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: [] });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
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 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 { TELEMETRY_SAVED_OBJECT_TYPE } from '../saved_objects';
|
||||||
import { v2 } from '../../common/types';
|
import { v2 } from '../../common/types';
|
||||||
import {
|
import {
|
||||||
|
@ -16,38 +19,42 @@ import {
|
||||||
} from '../saved_objects';
|
} from '../saved_objects';
|
||||||
|
|
||||||
export function registerTelemetryUserHasSeenNotice(router: IRouter, currentKibanaVersion: string) {
|
export function registerTelemetryUserHasSeenNotice(router: IRouter, currentKibanaVersion: string) {
|
||||||
router.put(
|
const v2Handler: RequestHandler<undefined, undefined, undefined, RequestHandlerContext> = async (
|
||||||
{
|
context,
|
||||||
path: '/api/telemetry/v2/userHasSeenNotice',
|
req,
|
||||||
validate: false,
|
res
|
||||||
},
|
) => {
|
||||||
async (context, req, res) => {
|
const soClient = (await context.core).savedObjects.getClient({
|
||||||
const soClient = (await context.core).savedObjects.getClient({
|
includedHiddenTypes: [TELEMETRY_SAVED_OBJECT_TYPE],
|
||||||
includedHiddenTypes: [TELEMETRY_SAVED_OBJECT_TYPE],
|
});
|
||||||
});
|
const telemetrySavedObject = await getTelemetrySavedObject(soClient);
|
||||||
const telemetrySavedObject = await getTelemetrySavedObject(soClient);
|
|
||||||
|
|
||||||
// update the object with a flag stating that the opt-in notice has been seen
|
// update the object with a flag stating that the opt-in notice has been seen
|
||||||
const updatedAttributes: TelemetrySavedObjectAttributes = {
|
const updatedAttributes: TelemetrySavedObjectAttributes = {
|
||||||
...telemetrySavedObject,
|
...telemetrySavedObject,
|
||||||
userHasSeenNotice: true,
|
userHasSeenNotice: true,
|
||||||
// We need to store that the user was notified in this version.
|
// We need to store that the user was notified in this version.
|
||||||
// Otherwise, it'll continuously show the banner if previously opted-out.
|
// Otherwise, it'll continuously show the banner if previously opted-out.
|
||||||
lastVersionChecked: currentKibanaVersion,
|
lastVersionChecked: currentKibanaVersion,
|
||||||
};
|
};
|
||||||
await updateTelemetrySavedObject(soClient, updatedAttributes);
|
await updateTelemetrySavedObject(soClient, updatedAttributes);
|
||||||
|
|
||||||
const body: v2.Telemetry = {
|
const body: v2.Telemetry = {
|
||||||
allowChangingOptInStatus: updatedAttributes.allowChangingOptInStatus,
|
allowChangingOptInStatus: updatedAttributes.allowChangingOptInStatus,
|
||||||
enabled: updatedAttributes.enabled,
|
enabled: updatedAttributes.enabled,
|
||||||
lastReported: updatedAttributes.lastReported,
|
lastReported: updatedAttributes.lastReported,
|
||||||
lastVersionChecked: updatedAttributes.lastVersionChecked,
|
lastVersionChecked: updatedAttributes.lastVersionChecked,
|
||||||
reportFailureCount: updatedAttributes.reportFailureCount,
|
reportFailureCount: updatedAttributes.reportFailureCount,
|
||||||
reportFailureVersion: updatedAttributes.reportFailureVersion,
|
reportFailureVersion: updatedAttributes.reportFailureVersion,
|
||||||
sendUsageFrom: updatedAttributes.sendUsageFrom,
|
sendUsageFrom: updatedAttributes.sendUsageFrom,
|
||||||
userHasSeenNotice: updatedAttributes.userHasSeenNotice,
|
userHasSeenNotice: updatedAttributes.userHasSeenNotice,
|
||||||
};
|
};
|
||||||
return res.ok({ body });
|
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/std",
|
||||||
"@kbn/core-http-browser-mocks",
|
"@kbn/core-http-browser-mocks",
|
||||||
"@kbn/core-http-browser",
|
"@kbn/core-http-browser",
|
||||||
|
"@kbn/core-http-server",
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"target/**/*",
|
"target/**/*",
|
||||||
|
|
|
@ -11,6 +11,10 @@ import expect from '@kbn/expect';
|
||||||
import SuperTest from 'supertest';
|
import SuperTest from 'supertest';
|
||||||
import type { KbnClient } from '@kbn/test';
|
import type { KbnClient } from '@kbn/test';
|
||||||
import type { TelemetrySavedObjectAttributes } from '@kbn/telemetry-plugin/server/saved_objects';
|
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';
|
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
export default function optInTest({ getService }: FtrProviderContext) {
|
export default function optInTest({ getService }: FtrProviderContext) {
|
||||||
|
@ -18,7 +22,7 @@ export default function optInTest({ getService }: FtrProviderContext) {
|
||||||
const kibanaServer = getService('kibanaServer');
|
const kibanaServer = getService('kibanaServer');
|
||||||
const esArchiver = getService('esArchiver');
|
const esArchiver = getService('esArchiver');
|
||||||
|
|
||||||
describe('/api/telemetry/v2/optIn API', () => {
|
describe('/internal/telemetry/optIn API', () => {
|
||||||
let defaultAttributes: TelemetrySavedObjectAttributes;
|
let defaultAttributes: TelemetrySavedObjectAttributes;
|
||||||
let kibanaVersion: string;
|
let kibanaVersion: string;
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
@ -88,8 +92,10 @@ async function postTelemetryV2OptIn(
|
||||||
statusCode: number
|
statusCode: number
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const { body } = await supertest
|
const { body } = await supertest
|
||||||
.post('/api/telemetry/v2/optIn')
|
.post('/internal/telemetry/optIn')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ enabled: value })
|
.send({ enabled: value })
|
||||||
.expect(statusCode);
|
.expect(statusCode);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AxiosError } from 'axios';
|
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';
|
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
const TELEMETRY_SO_TYPE = 'telemetry';
|
const TELEMETRY_SO_TYPE = 'telemetry';
|
||||||
|
@ -16,110 +20,146 @@ export default function telemetryConfigTest({ getService }: FtrProviderContext)
|
||||||
const kbnClient = getService('kibanaServer');
|
const kbnClient = getService('kibanaServer');
|
||||||
const supertest = getService('supertest');
|
const supertest = getService('supertest');
|
||||||
|
|
||||||
describe('/api/telemetry/v2/config API Telemetry config', () => {
|
describe('API Telemetry config', () => {
|
||||||
before(async () => {
|
['/api/telemetry/v2/config', '/internal/telemetry/config'].forEach((api) => {
|
||||||
try {
|
describe(`GET ${api}`, () => {
|
||||||
await kbnClient.savedObjects.delete({ type: TELEMETRY_SO_TYPE, id: TELEMETRY_SO_ID });
|
const apiVersion = api === '/api/telemetry/v2/config' ? '2023-10-31' : '2';
|
||||||
} catch (err) {
|
before(async () => {
|
||||||
const is404Error = err instanceof AxiosError && err.response?.status === 404;
|
try {
|
||||||
if (!is404Error) {
|
await kbnClient.savedObjects.delete({ type: TELEMETRY_SO_TYPE, id: TELEMETRY_SO_ID });
|
||||||
throw err;
|
} 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 },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await supertest.get('/api/telemetry/v2/config').set('kbn-xsrf', 'xxx').expect(200, {
|
it('GET should get the default config', async () => {
|
||||||
allowChangingOptInStatus: true,
|
await supertest
|
||||||
optIn: true,
|
.get(api)
|
||||||
sendUsageFrom: 'server',
|
.set('kbn-xsrf', 'xxx')
|
||||||
telemetryNotifyUserAboutOptInDefault: false,
|
.set(ELASTIC_HTTP_VERSION_HEADER, apiVersion)
|
||||||
});
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
});
|
.expect(200, {
|
||||||
|
allowChangingOptInStatus: true,
|
||||||
it('GET should get `null` when opted-out in a previous version', async () => {
|
optIn: null, // the config.js for this FTR sets it to `false`, we are bound to ask again.
|
||||||
// Opt-out from previous version
|
sendUsageFrom: 'server',
|
||||||
await kbnClient.savedObjects.create({
|
telemetryNotifyUserAboutOptInDefault: false, // it's not opted-in by default (that's what this flag is about)
|
||||||
overwrite: true,
|
});
|
||||||
type: TELEMETRY_SO_TYPE,
|
|
||||||
id: TELEMETRY_SO_ID,
|
|
||||||
attributes: { ...attributes, enabled: false, lastVersionChecked: previousMinor },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await supertest.get('/api/telemetry/v2/config').set('kbn-xsrf', 'xxx').expect(200, {
|
it('GET should get `true` when opted-in', async () => {
|
||||||
allowChangingOptInStatus: true,
|
// Opt-in
|
||||||
optIn: null,
|
await supertest
|
||||||
sendUsageFrom: 'server',
|
.post('/internal/telemetry/optIn')
|
||||||
telemetryNotifyUserAboutOptInDefault: false,
|
.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 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';
|
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
export default function optInTest({ getService }: FtrProviderContext) {
|
export default function optInTest({ getService }: FtrProviderContext) {
|
||||||
const client = getService('kibanaServer');
|
const client = getService('kibanaServer');
|
||||||
const supertest = getService('supertest');
|
const supertest = getService('supertest');
|
||||||
|
|
||||||
describe('/api/telemetry/v2/last_reported API Telemetry lastReported', () => {
|
describe('/internal/telemetry/last_reported API Telemetry lastReported', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await client.savedObjects.delete({ type: 'telemetry', id: 'telemetry' });
|
await client.savedObjects.delete({ type: 'telemetry', id: 'telemetry' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GET should return undefined when there is no stored telemetry.lastReported value', async () => {
|
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 () => {
|
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 {
|
const {
|
||||||
attributes: { lastReported },
|
attributes: { lastReported },
|
||||||
|
@ -46,8 +60,10 @@ export default function optInTest({ getService }: FtrProviderContext) {
|
||||||
expect(lastReported).to.be.a('number');
|
expect(lastReported).to.be.a('number');
|
||||||
|
|
||||||
await supertest
|
await supertest
|
||||||
.get('/api/telemetry/v2/last_reported')
|
.get('/internal/telemetry/last_reported')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.expect(200, { lastReported });
|
.expect(200, { lastReported });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,17 +7,26 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
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';
|
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
export default function optInTest({ getService }: FtrProviderContext) {
|
export default function optInTest({ getService }: FtrProviderContext) {
|
||||||
const client = getService('kibanaServer');
|
const client = getService('kibanaServer');
|
||||||
const supertest = getService('supertest');
|
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 () => {
|
it('should update telemetry setting field via PUT', async () => {
|
||||||
await client.savedObjects.delete({ type: 'telemetry', id: 'telemetry' });
|
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 {
|
const {
|
||||||
attributes: { userHasSeenNotice },
|
attributes: { userHasSeenNotice },
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { KBN_SCREENSHOT_MODE_ENABLED_KEY } from '@kbn/screenshot-mode-plugin/public';
|
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';
|
import { PluginFunctionalProviderContext } from '../../services';
|
||||||
|
|
||||||
const TELEMETRY_SO_TYPE = 'telemetry';
|
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 () => {
|
it('does not show the banner if opted-in', async () => {
|
||||||
await supertest
|
await supertest
|
||||||
.post('/api/telemetry/v2/optIn')
|
.post('/internal/telemetry/optIn')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ enabled: true })
|
.send({ enabled: true })
|
||||||
.expect(200);
|
.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 () => {
|
it('does not show the banner if opted-out in this version', async () => {
|
||||||
await supertest
|
await supertest
|
||||||
.post('/api/telemetry/v2/optIn')
|
.post('/internal/telemetry/optIn')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ enabled: false })
|
.send({ enabled: false })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,6 @@
|
||||||
export const name = 'telemetry';
|
export const name = 'telemetry';
|
||||||
export const description = 'Get the clusters stats from the Kibana server';
|
export const description = 'Get the clusters stats from the Kibana server';
|
||||||
export const method = 'POST';
|
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 };
|
export const body = { unencrypted: true, refreshCache: true };
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { SuperTest } from 'supertest';
|
import { SuperTest } from 'supertest';
|
||||||
import { CSV_QUOTE_VALUES_SETTING } from '@kbn/share-plugin/common/constants';
|
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';
|
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
|
|
||||||
export default function featureControlsTests({ getService }: FtrProviderContext) {
|
export default function featureControlsTests({ getService }: FtrProviderContext) {
|
||||||
|
@ -64,9 +68,11 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
|
||||||
const basePath = spaceId ? `/s/${spaceId}` : '';
|
const basePath = spaceId ? `/s/${spaceId}` : '';
|
||||||
|
|
||||||
return await supertest
|
return await supertest
|
||||||
.post(`${basePath}/api/telemetry/v2/optIn`)
|
.post(`${basePath}/internal/telemetry/optIn`)
|
||||||
.auth(username, password)
|
.auth(username, password)
|
||||||
.set('kbn-xsrf', 'foo')
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ enabled: true })
|
.send({ enabled: true })
|
||||||
.then((response: any) => ({ error: undefined, response }))
|
.then((response: any) => ({ error: undefined, response }))
|
||||||
.catch((error: any) => ({ error, response: undefined }));
|
.catch((error: any) => ({ error, response: undefined }));
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { estypes } from '@elastic/elasticsearch';
|
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';
|
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
export default function ({ getService }: FtrProviderContext) {
|
export default function ({ getService }: FtrProviderContext) {
|
||||||
|
@ -17,7 +21,9 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
const {
|
const {
|
||||||
body: [{ stats: apiResponse }],
|
body: [{ stats: apiResponse }],
|
||||||
} = await supertest
|
} = 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')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
.send({
|
.send({
|
||||||
unencrypted: true,
|
unencrypted: true,
|
||||||
|
|
|
@ -21,6 +21,10 @@ import type {
|
||||||
CacheDetails,
|
CacheDetails,
|
||||||
} from '@kbn/telemetry-collection-manager-plugin/server/types';
|
} from '@kbn/telemetry-collection-manager-plugin/server/types';
|
||||||
import { assertTelemetryPayload } from '@kbn/telemetry-tools';
|
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 basicClusterFixture from './fixtures/basiccluster.json';
|
||||||
import multiClusterFixture from './fixtures/multicluster.json';
|
import multiClusterFixture from './fixtures/multicluster.json';
|
||||||
import type { SecurityService } from '../../../../../test/common/services/security/security';
|
import type { SecurityService } from '../../../../../test/common/services/security/security';
|
||||||
|
@ -97,7 +101,7 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
const esSupertest = getService('esSupertest');
|
const esSupertest = getService('esSupertest');
|
||||||
const security = getService('security');
|
const security = getService('security');
|
||||||
|
|
||||||
describe('/api/telemetry/v2/clusters/_stats', () => {
|
describe('/internal/telemetry/clusters/_stats', () => {
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = new Date().toISOString();
|
||||||
describe('monitoring/multicluster', () => {
|
describe('monitoring/multicluster', () => {
|
||||||
let localXPack: Record<string, unknown>;
|
let localXPack: Record<string, unknown>;
|
||||||
|
@ -112,8 +116,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
await updateMonitoringDates(esSupertest, fromTimestamp, toTimestamp, timestamp);
|
await updateMonitoringDates(esSupertest, fromTimestamp, toTimestamp, timestamp);
|
||||||
|
|
||||||
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true, refreshCache: true })
|
.send({ unencrypted: true, refreshCache: true })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
|
@ -167,8 +173,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
after(() => esArchiver.unload(archive));
|
after(() => esArchiver.unload(archive));
|
||||||
it('should load non-expiring basic cluster', async () => {
|
it('should load non-expiring basic cluster', async () => {
|
||||||
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true, refreshCache: true })
|
.send({ unencrypted: true, refreshCache: true })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
|
@ -193,8 +201,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
await updateMonitoringDates(esSupertest, fromTimestamp, toTimestamp, timestamp);
|
await updateMonitoringDates(esSupertest, fromTimestamp, toTimestamp, timestamp);
|
||||||
// hit the endpoint to cache results
|
// hit the endpoint to cache results
|
||||||
await supertest
|
await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true, refreshCache: true })
|
.send({ unencrypted: true, refreshCache: true })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
@ -204,8 +214,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
it('returns non-cached results when unencrypted', async () => {
|
it('returns non-cached results when unencrypted', async () => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true })
|
.send({ unencrypted: true })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
|
@ -224,8 +236,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
it('grabs a fresh copy on refresh', async () => {
|
it('grabs a fresh copy on refresh', async () => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
const { body }: { body: UnencryptedTelemetryPayload } = await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true, refreshCache: true })
|
.send({ unencrypted: true, refreshCache: true })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
|
@ -243,16 +257,20 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
describe('superadmin user', () => {
|
describe('superadmin user', () => {
|
||||||
it('should return unencrypted telemetry for the admin user', async () => {
|
it('should return unencrypted telemetry for the admin user', async () => {
|
||||||
await supertest
|
await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true })
|
.send({ unencrypted: true })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return encrypted telemetry for the admin user', async () => {
|
it('should return encrypted telemetry for the admin user', async () => {
|
||||||
await supertest
|
await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: false })
|
.send({ unencrypted: false })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
@ -281,18 +299,22 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
|
|
||||||
it('should return encrypted telemetry for the global-read user', async () => {
|
it('should return encrypted telemetry for the global-read user', async () => {
|
||||||
await supertestWithoutAuth
|
await supertestWithoutAuth
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.auth(globalReadOnlyUser, password(globalReadOnlyUser))
|
.auth(globalReadOnlyUser, password(globalReadOnlyUser))
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: false })
|
.send({ unencrypted: false })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return unencrypted telemetry for the global-read user', async () => {
|
it('should return unencrypted telemetry for the global-read user', async () => {
|
||||||
await supertestWithoutAuth
|
await supertestWithoutAuth
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.auth(globalReadOnlyUser, password(globalReadOnlyUser))
|
.auth(globalReadOnlyUser, password(globalReadOnlyUser))
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true })
|
.send({ unencrypted: true })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
@ -330,18 +352,22 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
|
|
||||||
it('should return encrypted telemetry for the read-only user', async () => {
|
it('should return encrypted telemetry for the read-only user', async () => {
|
||||||
await supertestWithoutAuth
|
await supertestWithoutAuth
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.auth(noGlobalUser, password(noGlobalUser))
|
.auth(noGlobalUser, password(noGlobalUser))
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: false })
|
.send({ unencrypted: false })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return 403 when the read-only user requests unencrypted telemetry', async () => {
|
it('should return 403 when the read-only user requests unencrypted telemetry', async () => {
|
||||||
await supertestWithoutAuth
|
await supertestWithoutAuth
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.auth(noGlobalUser, password(noGlobalUser))
|
.auth(noGlobalUser, password(noGlobalUser))
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true })
|
.send({ unencrypted: true })
|
||||||
.expect(403);
|
.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 xpackRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_root.json';
|
||||||
import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json';
|
import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json';
|
||||||
import { assertTelemetryPayload } from '@kbn/telemetry-tools';
|
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 { flatKeys } from '../../../../../test/api_integration/apis/telemetry/utils';
|
||||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
|
@ -31,7 +35,7 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
const supertest = getService('supertest');
|
const supertest = getService('supertest');
|
||||||
const es = getService('es');
|
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>;
|
let stats: Record<string, any>;
|
||||||
|
|
||||||
before('disable monitoring and pull local stats', async () => {
|
before('disable monitoring and pull local stats', async () => {
|
||||||
|
@ -39,8 +43,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
await new Promise((r) => setTimeout(r, 1000));
|
await new Promise((r) => setTimeout(r, 1000));
|
||||||
|
|
||||||
const { body } = await supertest
|
const { body } = await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true, refreshCache: true })
|
.send({ unencrypted: true, refreshCache: true })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { UsageStatsPayload } from '@kbn/telemetry-collection-manager-plugin/server';
|
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';
|
import { FtrProviderContext } from '../ftr_provider_context';
|
||||||
|
|
||||||
export interface UsageStatsPayloadTestFriendly extends UsageStatsPayload {
|
export interface UsageStatsPayloadTestFriendly extends UsageStatsPayload {
|
||||||
|
@ -29,9 +33,10 @@ export function UsageAPIProvider({ getService }: FtrProviderContext) {
|
||||||
refreshCache?: boolean;
|
refreshCache?: boolean;
|
||||||
}): Promise<Array<{ clusterUuid: string; stats: UsageStatsPayloadTestFriendly | string }>> {
|
}): Promise<Array<{ clusterUuid: string; stats: UsageStatsPayloadTestFriendly | string }>> {
|
||||||
const { body } = await supertest
|
const { body } = await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'xxx')
|
.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 })
|
.send({ refreshCache: true, ...payload })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
return body;
|
return body;
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
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 { data, MockTelemetryFindings } from './data';
|
||||||
import type { FtrProviderContext } from '../ftr_provider_context';
|
import type { FtrProviderContext } from '../ftr_provider_context';
|
||||||
|
|
||||||
|
@ -67,7 +70,9 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
const {
|
const {
|
||||||
body: [{ stats: apiResponse }],
|
body: [{ stats: apiResponse }],
|
||||||
} = await supertest
|
} = 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')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
.send({
|
.send({
|
||||||
unencrypted: true,
|
unencrypted: true,
|
||||||
|
@ -119,8 +124,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
const {
|
const {
|
||||||
body: [{ stats: apiResponse }],
|
body: [{ stats: apiResponse }],
|
||||||
} = await supertest
|
} = await supertest
|
||||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
.post(`/internal/telemetry/clusters/_stats`)
|
||||||
.set('kbn-xsrf', 'xxxx')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({
|
.send({
|
||||||
unencrypted: true,
|
unencrypted: true,
|
||||||
refreshCache: true,
|
refreshCache: true,
|
||||||
|
@ -164,8 +171,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
const {
|
const {
|
||||||
body: [{ stats: apiResponse }],
|
body: [{ stats: apiResponse }],
|
||||||
} = await supertest
|
} = await supertest
|
||||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
.post(`/internal/telemetry/clusters/_stats`)
|
||||||
.set('kbn-xsrf', 'xxxx')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({
|
.send({
|
||||||
unencrypted: true,
|
unencrypted: true,
|
||||||
refreshCache: true,
|
refreshCache: true,
|
||||||
|
@ -240,8 +249,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
const {
|
const {
|
||||||
body: [{ stats: apiResponse }],
|
body: [{ stats: apiResponse }],
|
||||||
} = await supertest
|
} = await supertest
|
||||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
.post(`/internal/telemetry/clusters/_stats`)
|
||||||
.set('kbn-xsrf', 'xxxx')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({
|
.send({
|
||||||
unencrypted: true,
|
unencrypted: true,
|
||||||
refreshCache: true,
|
refreshCache: true,
|
||||||
|
@ -294,8 +305,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
const {
|
const {
|
||||||
body: [{ stats: apiResponse }],
|
body: [{ stats: apiResponse }],
|
||||||
} = await supertest
|
} = await supertest
|
||||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
.post(`/internal/telemetry/clusters/_stats`)
|
||||||
.set('kbn-xsrf', 'xxxx')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({
|
.send({
|
||||||
unencrypted: true,
|
unencrypted: true,
|
||||||
refreshCache: true,
|
refreshCache: true,
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
import type { ToolingLog } from '@kbn/tooling-log';
|
import type { ToolingLog } from '@kbn/tooling-log';
|
||||||
import type SuperTest from 'supertest';
|
import type SuperTest from 'supertest';
|
||||||
import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types';
|
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 { getStatsUrl } from './get_stats_url';
|
||||||
import { getDetectionMetricsFromBody } from './get_detection_metrics_from_body';
|
import { getDetectionMetricsFromBody } from './get_detection_metrics_from_body';
|
||||||
|
@ -24,6 +28,8 @@ export const getStats = async (
|
||||||
const response = await supertest
|
const response = await supertest
|
||||||
.post(getStatsUrl())
|
.post(getStatsUrl())
|
||||||
.set('kbn-xsrf', 'true')
|
.set('kbn-xsrf', 'true')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: true, refreshCache: true });
|
.send({ unencrypted: true, refreshCache: true });
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
log.error(
|
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.
|
* 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.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
ELASTIC_HTTP_VERSION_HEADER,
|
||||||
|
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||||
|
} from '@kbn/core-http-common';
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { FtrProviderContext } from '../../api_integration/ftr_provider_context';
|
import { FtrProviderContext } from '../../api_integration/ftr_provider_context';
|
||||||
import { skipIfNoDockerRegistry, generateAgent } from '../helpers';
|
import { skipIfNoDockerRegistry, generateAgent } from '../helpers';
|
||||||
|
@ -124,8 +128,10 @@ export default function (providerContext: FtrProviderContext) {
|
||||||
const {
|
const {
|
||||||
body: [{ stats: apiResponse }],
|
body: [{ stats: apiResponse }],
|
||||||
} = await supertest
|
} = await supertest
|
||||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
.post(`/internal/telemetry/clusters/_stats`)
|
||||||
.set('kbn-xsrf', 'xxxx')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({
|
.send({
|
||||||
unencrypted: true,
|
unencrypted: true,
|
||||||
refreshCache: true,
|
refreshCache: true,
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
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 { DATES } from './constants';
|
||||||
|
|
||||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
@ -133,8 +137,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
await logsUi.logStreamPage.getStreamEntries();
|
await logsUi.logStreamPage.getStreamEntries();
|
||||||
|
|
||||||
const [{ stats }] = await supertest
|
const [{ stats }] = await supertest
|
||||||
.post(`/api/telemetry/v2/clusters/_stats`)
|
.post(`/internal/telemetry/clusters/_stats`)
|
||||||
.set(COMMON_REQUEST_HEADERS)
|
.set(COMMON_REQUEST_HEADERS)
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.set('Accept', 'application/json')
|
.set('Accept', 'application/json')
|
||||||
.send({
|
.send({
|
||||||
unencrypted: true,
|
unencrypted: true,
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
ELASTIC_HTTP_VERSION_HEADER,
|
||||||
|
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||||
|
} from '@kbn/core-http-common';
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import type { FtrProviderContext } from '../ftr_provider_context';
|
import type { FtrProviderContext } from '../ftr_provider_context';
|
||||||
import { assertLogContains, isExecutionContextLog, ANY } from '../test_utils';
|
import { assertLogContains, isExecutionContextLog, ANY } from '../test_utils';
|
||||||
|
@ -111,8 +115,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
|
|
||||||
it('propagates context for Telemetry collection', async () => {
|
it('propagates context for Telemetry collection', async () => {
|
||||||
await supertest
|
await supertest
|
||||||
.post('/api/telemetry/v2/clusters/_stats')
|
.post('/internal/telemetry/clusters/_stats')
|
||||||
.set('kbn-xsrf', 'true')
|
.set('kbn-xsrf', 'true')
|
||||||
|
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||||
|
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||||
.send({ unencrypted: false })
|
.send({ unencrypted: false })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"journeyName": "POST /api/telemetry/v2/clusters/_stats - 1600 dataviews",
|
"journeyName": "POST /internal/telemetry/clusters/_stats - 1600 dataviews",
|
||||||
"scalabilitySetup": {
|
"scalabilitySetup": {
|
||||||
"warmup": [
|
"warmup": [
|
||||||
{
|
{
|
||||||
|
@ -30,13 +30,15 @@
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"path": "/api/telemetry/v2/clusters/_stats",
|
"path": "/internal/telemetry/clusters/_stats",
|
||||||
"body": "{}",
|
"body": "{}",
|
||||||
"headers": {
|
"headers": {
|
||||||
"Cookie": "",
|
"Cookie": "",
|
||||||
"Kbn-Version": "",
|
"Kbn-Version": "",
|
||||||
"Accept-Encoding": "gzip, deflate, br",
|
"Accept-Encoding": "gzip, deflate, br",
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
|
"elastic-api-version": "2",
|
||||||
|
"x-elastic-internal-origin": "kibana"
|
||||||
},
|
},
|
||||||
"statusCode": 200
|
"statusCode": 200
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"journeyName": "POST /api/telemetry/v2/clusters/_stats",
|
"journeyName": "POST /internal/telemetry/clusters/_stats",
|
||||||
"scalabilitySetup": {
|
"scalabilitySetup": {
|
||||||
"warmup": [
|
"warmup": [
|
||||||
{
|
{
|
||||||
|
@ -28,13 +28,15 @@
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"path": "/api/telemetry/v2/clusters/_stats",
|
"path": "/internal/telemetry/clusters/_stats",
|
||||||
"body": "{}",
|
"body": "{}",
|
||||||
"headers": {
|
"headers": {
|
||||||
"Cookie": "",
|
"Cookie": "",
|
||||||
"Kbn-Version": "",
|
"Kbn-Version": "",
|
||||||
"Accept-Encoding": "gzip, deflate, br",
|
"Accept-Encoding": "gzip, deflate, br",
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
|
"elastic-api-version": "2",
|
||||||
|
"x-elastic-internal-origin": "kibana"
|
||||||
},
|
},
|
||||||
"statusCode": 200
|
"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": {
|
"scalabilitySetup": {
|
||||||
"responseTimeThreshold": {
|
"responseTimeThreshold": {
|
||||||
"threshold1": 1000,
|
"threshold1": 1000,
|
||||||
|
@ -35,13 +35,15 @@
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"path": "/api/telemetry/v2/clusters/_stats",
|
"path": "/internal/telemetry/clusters/_stats",
|
||||||
"body": "{ \"refreshCache\": true }",
|
"body": "{ \"refreshCache\": true }",
|
||||||
"headers": {
|
"headers": {
|
||||||
"Cookie": "",
|
"Cookie": "",
|
||||||
"Kbn-Version": "",
|
"Kbn-Version": "",
|
||||||
"Accept-Encoding": "gzip, deflate, br",
|
"Accept-Encoding": "gzip, deflate, br",
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
|
"elastic-api-version": "2",
|
||||||
|
"x-elastic-internal-origin": "kibana"
|
||||||
},
|
},
|
||||||
"timeout": 240000,
|
"timeout": 240000,
|
||||||
"statusCode": 200
|
"statusCode": 200
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"journeyName": "POST /api/telemetry/v2/clusters/_stats - no cache",
|
"journeyName": "POST /internal/telemetry/clusters/_stats - no cache",
|
||||||
"scalabilitySetup": {
|
"scalabilitySetup": {
|
||||||
"responseTimeThreshold": {
|
"responseTimeThreshold": {
|
||||||
"threshold1": 1000,
|
"threshold1": 1000,
|
||||||
|
@ -33,13 +33,15 @@
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"path": "/api/telemetry/v2/clusters/_stats",
|
"path": "/internal/telemetry/clusters/_stats",
|
||||||
"body": "{ \"refreshCache\": true }",
|
"body": "{ \"refreshCache\": true }",
|
||||||
"headers": {
|
"headers": {
|
||||||
"Cookie": "",
|
"Cookie": "",
|
||||||
"Kbn-Version": "",
|
"Kbn-Version": "",
|
||||||
"Accept-Encoding": "gzip, deflate, br",
|
"Accept-Encoding": "gzip, deflate, br",
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
|
"elastic-api-version": "2",
|
||||||
|
"x-elastic-internal-origin": "kibana"
|
||||||
},
|
},
|
||||||
"statusCode": 200
|
"statusCode": 200
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue