Updated APM Indices endpoints to use the SavedObjectsClient from the legacy request context, and set the apm-indices schema object to be namspace-agnostic

- rename apm-telemetry save object mapping -> apm-services-telemetry (#49994)
- move saved object types and document IDs to constants file
- Updated APM Indices endpoints to use the SavedObjectsClient from the
  legacy request context, and set the apm-indices schema object to be
  namspace-agnostic.
This commit is contained in:
Oliver Gupte 2019-11-13 21:26:22 -08:00 committed by GitHub
parent bc7b7df00d
commit cd67addf15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 190 additions and 147 deletions

View file

@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
// APM Services telemetry
export const APM_SERVICES_TELEMETRY_SAVED_OBJECT_TYPE =
'apm-services-telemetry';
export const APM_SERVICES_TELEMETRY_SAVED_OBJECT_ID = 'apm-services-telemetry';
// APM indices
export const APM_INDICES_SAVED_OBJECT_TYPE = 'apm-indices';
export const APM_INDICES_SAVED_OBJECT_ID = 'apm-indices';

View file

@ -45,7 +45,10 @@ export const apm: LegacyPluginInitializer = kibana => {
},
hacks: ['plugins/apm/hacks/toggle_app_link_in_nav'],
savedObjectSchemas: {
'apm-telemetry': {
'apm-services-telemetry': {
isNamespaceAgnostic: true
},
'apm-indices': {
isNamespaceAgnostic: true
}
},

View file

@ -1,5 +1,5 @@
{
"apm-telemetry": {
"apm-services-telemetry": {
"properties": {
"has_any_services": {
"type": "boolean"

View file

@ -5,11 +5,11 @@
*/
import { SavedObjectAttributes } from 'src/core/server';
import { createApmTelementry, storeApmServicesTelemetry } from '../index';
import {
APM_TELEMETRY_DOC_ID,
createApmTelementry,
storeApmTelemetry
} from '../apm_telemetry';
APM_SERVICES_TELEMETRY_SAVED_OBJECT_TYPE,
APM_SERVICES_TELEMETRY_SAVED_OBJECT_ID
} from '../../../../common/apm_saved_object_constants';
describe('apm_telemetry', () => {
describe('createApmTelementry', () => {
@ -44,7 +44,7 @@ describe('apm_telemetry', () => {
});
});
describe('storeApmTelemetry', () => {
describe('storeApmServicesTelemetry', () => {
let server: any;
let apmTelemetry: SavedObjectAttributes;
let savedObjectsClientInstance: any;
@ -75,24 +75,24 @@ describe('apm_telemetry', () => {
});
it('should call savedObjectsClient create with the given ApmTelemetry object', () => {
storeApmTelemetry(server, apmTelemetry);
storeApmServicesTelemetry(server, apmTelemetry);
expect(savedObjectsClientInstance.create.mock.calls[0][1]).toBe(
apmTelemetry
);
});
it('should call savedObjectsClient create with the apm-telemetry document type and ID', () => {
storeApmTelemetry(server, apmTelemetry);
storeApmServicesTelemetry(server, apmTelemetry);
expect(savedObjectsClientInstance.create.mock.calls[0][0]).toBe(
'apm-telemetry'
APM_SERVICES_TELEMETRY_SAVED_OBJECT_TYPE
);
expect(savedObjectsClientInstance.create.mock.calls[0][2].id).toBe(
APM_TELEMETRY_DOC_ID
APM_SERVICES_TELEMETRY_SAVED_OBJECT_ID
);
});
it('should call savedObjectsClient create with overwrite: true', () => {
storeApmTelemetry(server, apmTelemetry);
storeApmServicesTelemetry(server, apmTelemetry);
expect(savedObjectsClientInstance.create.mock.calls[0][2].overwrite).toBe(
true
);

View file

@ -1,39 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Server } from 'hapi';
import { countBy } from 'lodash';
import { SavedObjectAttributes } from 'src/core/server';
import { isAgentName } from '../../../common/agent_name';
import { getSavedObjectsClient } from '../helpers/saved_objects_client';
export const APM_TELEMETRY_DOC_ID = 'apm-telemetry';
export function createApmTelementry(
agentNames: string[] = []
): SavedObjectAttributes {
const validAgentNames = agentNames.filter(isAgentName);
return {
has_any_services: validAgentNames.length > 0,
services_per_agent: countBy(validAgentNames)
};
}
export async function storeApmTelemetry(
server: Server,
apmTelemetry: SavedObjectAttributes
) {
try {
const savedObjectsClient = getSavedObjectsClient(server);
await savedObjectsClient.create('apm-telemetry', apmTelemetry, {
id: APM_TELEMETRY_DOC_ID,
overwrite: true
});
} catch (e) {
// eslint-disable-next-line no-console
console.error('Could not send APM telemetry:', e.message);
}
}

View file

@ -4,9 +4,77 @@
* you may not use this file except in compliance with the Elastic License.
*/
export {
storeApmTelemetry,
createApmTelementry,
APM_TELEMETRY_DOC_ID
} from './apm_telemetry';
export { makeApmUsageCollector } from './make_apm_usage_collector';
import { Server } from 'hapi';
import { countBy } from 'lodash';
import { SavedObjectAttributes } from 'src/core/server';
import { CoreSetup } from 'src/core/server';
import { isAgentName } from '../../../common/agent_name';
import { getInternalSavedObjectsClient } from '../helpers/saved_objects_client';
import {
APM_SERVICES_TELEMETRY_SAVED_OBJECT_TYPE,
APM_SERVICES_TELEMETRY_SAVED_OBJECT_ID
} from '../../../common/apm_saved_object_constants';
import { LegacySetup } from '../../new-platform/plugin';
export function createApmTelementry(
agentNames: string[] = []
): SavedObjectAttributes {
const validAgentNames = agentNames.filter(isAgentName);
return {
has_any_services: validAgentNames.length > 0,
services_per_agent: countBy(validAgentNames)
};
}
export async function storeApmServicesTelemetry(
server: Server,
apmTelemetry: SavedObjectAttributes
) {
try {
const internalSavedObjectsClient = getInternalSavedObjectsClient(server);
await internalSavedObjectsClient.create(
APM_SERVICES_TELEMETRY_SAVED_OBJECT_TYPE,
apmTelemetry,
{
id: APM_SERVICES_TELEMETRY_SAVED_OBJECT_ID,
overwrite: true
}
);
} catch (e) {
server.log(['error'], `Unable to save APM telemetry data: ${e.message}`);
}
}
interface LegacySetupWithUsageCollector extends LegacySetup {
server: LegacySetup['server'] & {
usage: {
collectorSet: {
makeUsageCollector: (options: unknown) => unknown;
register: (options: unknown) => unknown;
};
};
};
}
export function makeApmUsageCollector(
core: CoreSetup,
{ server }: LegacySetupWithUsageCollector
) {
const apmUsageCollector = server.usage.collectorSet.makeUsageCollector({
type: 'apm',
fetch: async () => {
const internalSavedObjectsClient = getInternalSavedObjectsClient(server);
try {
const apmTelemetrySavedObject = await internalSavedObjectsClient.get(
APM_SERVICES_TELEMETRY_SAVED_OBJECT_TYPE,
APM_SERVICES_TELEMETRY_SAVED_OBJECT_ID
);
return apmTelemetrySavedObject.attributes;
} catch (err) {
return createApmTelementry();
}
},
isReady: () => true
});
server.usage.collectorSet.register(apmUsageCollector);
}

View file

@ -1,44 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { CoreSetup } from 'src/core/server';
import { getSavedObjectsClient } from '../helpers/saved_objects_client';
import { APM_TELEMETRY_DOC_ID, createApmTelementry } from './apm_telemetry';
import { LegacySetup } from '../../new-platform/plugin';
export interface LegacySetupWithUsageCollector extends LegacySetup {
server: LegacySetup['server'] & {
usage: {
collectorSet: {
makeUsageCollector: (options: unknown) => unknown;
register: (options: unknown) => unknown;
};
};
};
}
export function makeApmUsageCollector(
core: CoreSetup,
{ server }: LegacySetupWithUsageCollector
) {
const apmUsageCollector = server.usage.collectorSet.makeUsageCollector({
type: 'apm',
fetch: async () => {
const savedObjectsClient = getSavedObjectsClient(server);
try {
const apmTelemetrySavedObject = await savedObjectsClient.get(
'apm-telemetry',
APM_TELEMETRY_DOC_ID
);
return apmTelemetrySavedObject.attributes;
} catch (err) {
return createApmTelementry();
}
},
isReady: () => true
});
server.usage.collectorSet.register(apmUsageCollector);
}

View file

@ -66,8 +66,12 @@ async function getParamsForSearchRequest(
apmOptions?: APMOptions
) {
const uiSettings = req.getUiSettingsService();
const { server } = req;
const [indices, includeFrozen] = await Promise.all([
getApmIndices(req.server),
getApmIndices({
config: server.config(),
savedObjectsClient: server.savedObjects.getScopedSavedObjectsClient(req)
}),
uiSettings.get('search:includeFrozen')
]);

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { getSavedObjectsClient } from './saved_objects_client';
import { getInternalSavedObjectsClient } from './saved_objects_client';
describe('saved_objects/client', () => {
describe('getSavedObjectsClient', () => {
@ -31,7 +31,7 @@ describe('saved_objects/client', () => {
});
it('should use internal user "admin"', () => {
getSavedObjectsClient(server);
getInternalSavedObjectsClient(server);
expect(server.plugins.elasticsearch.getCluster).toHaveBeenCalledWith(
'admin'
@ -39,7 +39,7 @@ describe('saved_objects/client', () => {
});
it('should call getSavedObjectsRepository with a cluster using the internal user context', () => {
getSavedObjectsClient(server);
getInternalSavedObjectsClient(server);
expect(
server.savedObjects.getSavedObjectsRepository
@ -47,9 +47,9 @@ describe('saved_objects/client', () => {
});
it('should return a SavedObjectsClient initialized with the saved objects internal repository', () => {
const result = getSavedObjectsClient(server);
const internalSavedObjectsClient = getInternalSavedObjectsClient(server);
expect(result).toBe(savedObjectsClientInstance);
expect(internalSavedObjectsClient).toBe(savedObjectsClientInstance);
expect(server.savedObjects.SavedObjectsClient).toHaveBeenCalledWith(
internalRepository
);

View file

@ -6,7 +6,10 @@
import { Server } from 'hapi';
export function getSavedObjectsClient(server: Server, clusterName = 'admin') {
export function getInternalSavedObjectsClient(
server: Server,
clusterName = 'admin'
) {
const { SavedObjectsClient, getSavedObjectsRepository } = server.savedObjects;
const { callWithInternalUser } = server.plugins.elasticsearch.getCluster(
clusterName

View file

@ -34,6 +34,9 @@ function getMockRequest() {
callWithInternalUser: callWithInternalUserSpy
})
}
},
savedObjects: {
getScopedSavedObjectsClient: () => ({ get: async () => false })
}
},
getUiSettingsService: () => ({ get: async () => false })

View file

@ -31,10 +31,13 @@ export type Setup = PromiseReturnType<typeof setupRequest>;
export async function setupRequest(req: Legacy.Request) {
const query = (req.query as unknown) as APMRequestQuery;
const { server } = req;
const savedObjectsClient = server.savedObjects.getScopedSavedObjectsClient(
req
);
const config = server.config();
const [uiFiltersES, indices] = await Promise.all([
decodeUiFilters(server, query.uiFilters),
getApmIndices(server)
getApmIndices({ config, savedObjectsClient })
]);
return {

View file

@ -4,18 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Server } from 'hapi';
import { getSavedObjectsClient } from '../helpers/saved_objects_client';
import { getInternalSavedObjectsClient } from '../helpers/saved_objects_client';
import apmIndexPattern from '../../../../../../../src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json';
export async function getAPMIndexPattern(server: Server) {
const config = server.config();
const apmIndexPatternTitle = config.get('apm_oss.indexPattern');
const savedObjectsClient = getSavedObjectsClient(server);
const internalSavedObjectsClient = getInternalSavedObjectsClient(server);
try {
return await savedObjectsClient.get('index-pattern', apmIndexPattern.id);
return await internalSavedObjectsClient.get(
'index-pattern',
apmIndexPattern.id
);
} catch (error) {
// if GET fails, then create a new index pattern saved object
return await savedObjectsClient.create(
return await internalSavedObjectsClient.create(
'index-pattern',
{
...apmIndexPattern.attributes,

View file

@ -8,13 +8,19 @@ import { CoreSetup } from 'src/core/server';
import { CallCluster } from '../../../../../../../../src/legacy/core_plugins/elasticsearch';
import { getApmIndices } from '../apm_indices/get_apm_indices';
import { LegacySetup } from '../../../new-platform/plugin';
import { getInternalSavedObjectsClient } from '../../helpers/saved_objects_client';
export async function createApmAgentConfigurationIndex(
core: CoreSetup,
{ server }: LegacySetup
) {
try {
const indices = await getApmIndices(server);
const config = server.config();
const internalSavedObjectsClient = getInternalSavedObjectsClient(server);
const indices = await getApmIndices({
savedObjectsClient: internalSavedObjectsClient,
config
});
const index = indices['apm_oss.apmAgentConfigurationIndex'];
const { callWithInternalUser } = server.plugins.elasticsearch.getCluster(
'admin'

View file

@ -4,12 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Server } from 'hapi';
import { merge } from 'lodash';
import { KibanaConfig } from 'src/legacy/server/kbn_server';
import { getSavedObjectsClient } from '../../helpers/saved_objects_client';
import { Setup } from '../../helpers/setup_request';
import { Server } from 'hapi';
import { PromiseReturnType } from '../../../../typings/common';
import {
APM_INDICES_SAVED_OBJECT_TYPE,
APM_INDICES_SAVED_OBJECT_ID
} from '../../../../common/apm_saved_object_constants';
export interface ApmIndicesConfig {
'apm_oss.sourcemapIndices': string;
@ -23,11 +25,13 @@ export interface ApmIndicesConfig {
export type ApmIndicesName = keyof ApmIndicesConfig;
export const APM_INDICES_SAVED_OBJECT_TYPE = 'apm-indices';
export const APM_INDICES_SAVED_OBJECT_ID = 'apm-indices';
export type ScopedSavedObjectsClient = ReturnType<
Server['savedObjects']['getScopedSavedObjectsClient']
>;
async function getApmIndicesSavedObject(server: Server) {
const savedObjectsClient = getSavedObjectsClient(server, 'data');
async function getApmIndicesSavedObject(
savedObjectsClient: ScopedSavedObjectsClient
) {
const apmIndices = await savedObjectsClient.get<Partial<ApmIndicesConfig>>(
APM_INDICES_SAVED_OBJECT_TYPE,
APM_INDICES_SAVED_OBJECT_ID
@ -53,13 +57,21 @@ function getApmIndicesConfig(config: KibanaConfig): ApmIndicesConfig {
};
}
export async function getApmIndices(server: Server) {
export async function getApmIndices({
savedObjectsClient,
config
}: {
savedObjectsClient: ScopedSavedObjectsClient;
config: KibanaConfig;
}) {
try {
const apmIndicesSavedObject = await getApmIndicesSavedObject(server);
const apmIndicesConfig = getApmIndicesConfig(server.config());
const apmIndicesSavedObject = await getApmIndicesSavedObject(
savedObjectsClient
);
const apmIndicesConfig = getApmIndicesConfig(config);
return merge({}, apmIndicesConfig, apmIndicesSavedObject);
} catch (error) {
return getApmIndicesConfig(server.config());
return getApmIndicesConfig(config);
}
}
@ -74,16 +86,15 @@ const APM_UI_INDICES: ApmIndicesName[] = [
];
export async function getApmIndexSettings({
setup,
server
config,
savedObjectsClient
}: {
setup: Setup;
server: Server;
config: KibanaConfig;
savedObjectsClient: ScopedSavedObjectsClient;
}) {
const { config } = setup;
let apmIndicesSavedObject: PromiseReturnType<typeof getApmIndicesSavedObject>;
try {
apmIndicesSavedObject = await getApmIndicesSavedObject(server);
apmIndicesSavedObject = await getApmIndicesSavedObject(savedObjectsClient);
} catch (error) {
if (error.output && error.output.statusCode === 404) {
apmIndicesSavedObject = {};

View file

@ -4,19 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Server } from 'hapi';
import { getSavedObjectsClient } from '../../helpers/saved_objects_client';
import { ApmIndicesConfig, ScopedSavedObjectsClient } from './get_apm_indices';
import {
ApmIndicesConfig,
APM_INDICES_SAVED_OBJECT_TYPE,
APM_INDICES_SAVED_OBJECT_ID
} from './get_apm_indices';
} from '../../../../common/apm_saved_object_constants';
export async function saveApmIndices(
server: Server,
savedObjectsClient: ScopedSavedObjectsClient,
apmIndicesSavedObject: Partial<ApmIndicesConfig>
) {
const savedObjectsClient = getSavedObjectsClient(server, 'data');
return await savedObjectsClient.create(
APM_INDICES_SAVED_OBJECT_TYPE,
apmIndicesSavedObject,

View file

@ -7,7 +7,6 @@
import { Server } from 'hapi';
import { CoreSetup } from 'src/core/server';
import { makeApmUsageCollector } from '../lib/apm_telemetry';
import { LegacySetupWithUsageCollector } from '../lib/apm_telemetry/make_apm_usage_collector';
import { createApmAgentConfigurationIndex } from '../lib/settings/agent_configuration/create_agent_config_index';
import { createApmApi } from '../routes/create_apm_api';
@ -19,6 +18,6 @@ export class Plugin {
public setup(core: CoreSetup, __LEGACY: LegacySetup) {
createApmApi().init(core, __LEGACY);
createApmAgentConfigurationIndex(core, __LEGACY);
makeApmUsageCollector(core, __LEGACY as LegacySetupWithUsageCollector);
makeApmUsageCollector(core, __LEGACY);
}
}

View file

@ -6,7 +6,10 @@
import * as t from 'io-ts';
import { AgentName } from '../../typings/es_schemas/ui/fields/Agent';
import { createApmTelementry, storeApmTelemetry } from '../lib/apm_telemetry';
import {
createApmTelementry,
storeApmServicesTelemetry
} from '../lib/apm_telemetry';
import { setupRequest } from '../lib/helpers/setup_request';
import { getServiceAgentName } from '../lib/services/get_service_agent_name';
import { getServices } from '../lib/services/get_services';
@ -30,7 +33,7 @@ export const servicesRoute = createRoute((core, { server }) => ({
({ agentName }) => agentName as AgentName
);
const apmTelemetry = createApmTelementry(agentNames);
storeApmTelemetry(server, apmTelemetry);
storeApmServicesTelemetry(server, apmTelemetry);
return services;
}

View file

@ -5,7 +5,6 @@
*/
import * as t from 'io-ts';
import { setupRequest } from '../../lib/helpers/setup_request';
import { createRoute } from '../create_route';
import {
getApmIndices,
@ -18,8 +17,11 @@ export const apmIndexSettingsRoute = createRoute((core, { server }) => ({
method: 'GET',
path: '/api/apm/settings/apm-index-settings',
handler: async req => {
const setup = await setupRequest(req);
return await getApmIndexSettings({ setup, server });
const config = server.config();
const savedObjectsClient = req.server.savedObjects.getScopedSavedObjectsClient(
req
);
return await getApmIndexSettings({ config, savedObjectsClient });
}
}));
@ -28,12 +30,16 @@ export const apmIndicesRoute = createRoute((core, { server }) => ({
method: 'GET',
path: '/api/apm/settings/apm-indices',
handler: async req => {
return await getApmIndices(server);
const config = server.config();
const savedObjectsClient = req.server.savedObjects.getScopedSavedObjectsClient(
req
);
return await getApmIndices({ config, savedObjectsClient });
}
}));
// save ui indices
export const saveApmIndicesRoute = createRoute((core, { server }) => ({
export const saveApmIndicesRoute = createRoute(() => ({
method: 'POST',
path: '/api/apm/settings/apm-indices/save',
params: {
@ -48,6 +54,9 @@ export const saveApmIndicesRoute = createRoute((core, { server }) => ({
})
},
handler: async (req, { body }) => {
return await saveApmIndices(server, body);
const savedObjectsClient = req.server.savedObjects.getScopedSavedObjectsClient(
req
);
return await saveApmIndices(savedObjectsClient, body);
}
}));