Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
17c0619
add data views rest usage counters
mattkime Jan 16, 2022
2c65102
add data views rest usage counters
mattkime Jan 16, 2022
abf76d6
simplify code
mattkime Jan 17, 2022
c6bf8be
simplify code
mattkime Jan 17, 2022
6bfeffe
Merge branch 'main' into data_views_rest_usage_counters
kibanamachine Jan 18, 2022
20472b2
Merge branch 'main' into data_views_rest_usage_counters
mattkime Jan 19, 2022
081161d
simplify imports and registration of routes
mattkime Jan 19, 2022
18b693b
simplify imports and registration of routes
mattkime Jan 19, 2022
791a4e6
test telemetry
mattkime Jan 19, 2022
b2f0949
try moving telemetry check earlier
mattkime Jan 19, 2022
0a89f9d
use saved object to check usage collection
mattkime Jan 20, 2022
68cb8dd
include method in counter name
mattkime Jan 20, 2022
969b72b
include method in counter name
mattkime Jan 20, 2022
4df8211
fix test
mattkime Jan 20, 2022
a27d171
move to unit tests
mattkime Jan 21, 2022
9fa4a62
partial progress on factoring out code for unit tests
mattkime Jan 24, 2022
8083953
Merge branch 'main' into data_views_rest_usage_counters
mattkime Jan 24, 2022
18eaa84
partial progress, getting there
mattkime Jan 25, 2022
a8965f0
partial progress, getting there
mattkime Jan 25, 2022
1ae61a2
fix routing
mattkime Jan 26, 2022
edf0018
restore nullable to field updates api
mattkime Jan 26, 2022
6b8ecc0
Merge branch 'main' into data_views_rest_usage_counters
mattkime Jan 27, 2022
3800d9f
revert integration test changes
mattkime Jan 27, 2022
5305e7d
refactor some code, add some tests, work in progress
mattkime Jan 27, 2022
3648ebd
rename files
mattkime Jan 27, 2022
4b2491c
fix update data view
mattkime Jan 27, 2022
3dc34d4
refactor to simplify some conditional code
mattkime Jan 27, 2022
03378cb
refactor to simplify some conditional code
mattkime Jan 27, 2022
196b427
add jest tests
mattkime Jan 27, 2022
51f0f66
clean up mocks
mattkime Jan 27, 2022
dcd8cbc
Merge branch 'main' into data_views_rest_usage_counters
kibanamachine Jan 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/plugins/data_views/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ export const DATA_VIEW_SAVED_OBJECT_TYPE = 'index-pattern';
*/

export const INDEX_PATTERN_SAVED_OBJECT_TYPE = DATA_VIEW_SAVED_OBJECT_TYPE;

export const PLUGIN_NAME = 'DataViews';
2 changes: 2 additions & 0 deletions src/plugins/data_views/server/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ export const SPECIFIC_SCRIPTED_FIELD_PATH_LEGACY = `${SCRIPTED_FIELD_PATH_LEGACY
export const SERVICE_KEY = 'data_view';
export const SERVICE_KEY_LEGACY = 'index_pattern';
export type SERVICE_KEY_TYPE = typeof SERVICE_KEY | typeof SERVICE_KEY_LEGACY;

export const CREATE_DATA_VIEW_COUNTER_NAME = `POST ${DATA_VIEW_PATH}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

seems like this isn't used

17 changes: 17 additions & 0 deletions src/plugins/data_views/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,27 @@
* Side Public License, v 1.
*/

import { DataViewsService } from 'src/plugins/data_views/common';

export function createIndexPatternsStartMock() {
const dataViewsServiceFactory = jest.fn().mockResolvedValue({ get: jest.fn() });
return {
indexPatternsServiceFactory: dataViewsServiceFactory,
dataViewsServiceFactory,
};
}

export const dataViewsService = {
find: jest.fn((search) => [{ id: search, title: search }]),
ensureDefaultIndexPattern: jest.fn(),
ensureDefaultDataView: jest.fn().mockReturnValue(Promise.resolve({})),
get: jest.fn().mockReturnValue(Promise.resolve({})),
clearCache: jest.fn(),
createAndSave: jest.fn(),
setDefault: jest.fn(),
delete: jest.fn(),
hasUserDataView: jest.fn(),
getDefaultId: jest.fn(),
updateSavedObject: jest.fn(),
refreshFields: jest.fn(),
} as unknown as jest.Mocked<DataViewsService>;
3 changes: 2 additions & 1 deletion src/plugins/data_views/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ export class DataViewsServerPlugin
) {
core.savedObjects.registerType(dataViewSavedObjectType);
core.capabilities.registerProvider(capabilitiesProvider);
const dataViewRestCounter = usageCollection?.createUsageCounter('dataViewsRestApi');

registerRoutes(core.http, core.getStartServices);
registerRoutes(core.http, core.getStartServices, dataViewRestCounter);

Copy link
Contributor

Choose a reason for hiding this comment

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

@mattkime what do you think of accessing the path pattern at the http service level? Dreaming here:

    http.registerOnPreResponse((req, res, t) => {
      //                                                                      t.matchedRoute does not exist
      usageCollection?.incrementCounter({ counterName: `${req.route.method} ${t.matchedRoute.path}` });
      return t.next();
    });

I'm not sure how common this need is (or what other things that might address). If you agree though perhaps we can suggest it to core. I may also be misunderstanding when onPreResponse is occurring.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jloleysens thats an interesting idea - I'll talk to core about it

expressions.registerFunction(getIndexPatternLoad({ getStartServices: core.getStartServices }));
registerIndexPatternsUsageCollector(core.getStartServices, usageCollection);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { createDataView } from './create_data_view';
import { dataViewsService } from '../mocks';
import { getUsageCollection } from './test_utils';

describe('create data view', () => {
it('call usageCollection', () => {
const usageCollection = getUsageCollection();
createDataView({
dataViewsService,
spec: {},
counterName: 'POST /path',
usageCollection,
});
expect(usageCollection.incrementCounter).toBeCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* Side Public License, v 1.
*/

import { UsageCounter } from 'src/plugins/usage_collection/server';
import { schema } from '@kbn/config-schema';
import { DataViewSpec } from 'src/plugins/data_views/common';
import { DataViewSpec, DataViewsService } from 'src/plugins/data_views/common';
import { handleErrors } from './util/handle_errors';
import {
fieldSpecSchema,
Expand All @@ -23,6 +24,27 @@ import {
SERVICE_KEY_LEGACY,
} from '../constants';

interface CreateDataViewArgs {
dataViewsService: DataViewsService;
usageCollection?: UsageCounter;
spec: DataViewSpec;
override?: boolean;
refreshFields?: boolean;
counterName: string;
}

export const createDataView = async ({
dataViewsService,
usageCollection,
spec,
override,
refreshFields,
counterName,
}: CreateDataViewArgs) => {
usageCollection?.incrementCounter({ counterName });
return dataViewsService.createAndSave(spec, override, !refreshFields);
};

const indexPatternSpecSchema = schema.object({
title: schema.string(),
version: schema.maybe(schema.string()),
Expand Down Expand Up @@ -59,7 +81,8 @@ const registerCreateDataViewRouteFactory =
getStartServices: StartServicesAccessor<
DataViewsServerPluginStartDependencies,
DataViewsServerPluginStart
>
>,
usageCollection?: UsageCounter
) => {
router.post(
{
Expand All @@ -79,7 +102,8 @@ const registerCreateDataViewRouteFactory =
const savedObjectsClient = ctx.core.savedObjects.client;
const elasticsearchClient = ctx.core.elasticsearch.client.asCurrentUser;
const [, , { dataViewsServiceFactory }] = await getStartServices();
const indexPatternsService = await dataViewsServiceFactory(

const dataViewsService = await dataViewsServiceFactory(
savedObjectsClient,
elasticsearchClient,
req
Expand All @@ -88,19 +112,22 @@ const registerCreateDataViewRouteFactory =

const spec = serviceKey === SERVICE_KEY ? body.data_view : body.index_pattern;

const indexPattern = await indexPatternsService.createAndSave(
spec as DataViewSpec,
body.override,
!body.refresh_fields
);
const dataView = await createDataView({
dataViewsService,
usageCollection,
spec: spec as DataViewSpec,
override: body.override,
refreshFields: body.refresh_fields,
counterName: `${req.route.method} ${path}`,
});

return res.ok({
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
[serviceKey]: indexPattern.toSpec(),
}),
body: {
[serviceKey]: dataView.toSpec(),
},
});
})
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { setDefault, getDefault } from './default_data_view';
import { dataViewsService } from '../mocks';
import { getUsageCollection } from './test_utils';

describe('default data view', () => {
it('set - calls usageCollection', () => {
const usageCollection = getUsageCollection();
setDefault({
dataViewsService,
counterName: 'POST /path',
usageCollection,
newDefaultId: '1',
force: false,
});
expect(usageCollection.incrementCounter).toBeCalledTimes(1);
});

it('get - calls usageCollection', () => {
const usageCollection = getUsageCollection();
getDefault({
dataViewsService,
counterName: 'GET /path',
usageCollection,
});
expect(usageCollection.incrementCounter).toBeCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,57 @@
* Side Public License, v 1.
*/

import { UsageCounter } from 'src/plugins/usage_collection/server';
import { schema } from '@kbn/config-schema';
import { DataViewsService } from 'src/plugins/data_views/common';
import { IRouter, StartServicesAccessor } from '../../../../core/server';
import type { DataViewsServerPluginStartDependencies, DataViewsServerPluginStart } from '../types';
import { handleErrors } from './util/handle_errors';
import { SERVICE_PATH, SERVICE_PATH_LEGACY, SERVICE_KEY, SERVICE_KEY_LEGACY } from '../constants';

interface GetDefaultArgs {
dataViewsService: DataViewsService;
usageCollection?: UsageCounter;
counterName: string;
}

export const getDefault = async ({
dataViewsService,
usageCollection,
counterName,
}: GetDefaultArgs) => {
usageCollection?.incrementCounter({ counterName });
return dataViewsService.getDefaultId();
};

interface SetDefaultArgs {
dataViewsService: DataViewsService;
usageCollection?: UsageCounter;
counterName: string;
newDefaultId: string;
force: boolean;
}

export const setDefault = async ({
dataViewsService,
usageCollection,
counterName,
newDefaultId,
force,
}: SetDefaultArgs) => {
usageCollection?.incrementCounter({ counterName });
return dataViewsService.setDefault(newDefaultId, force);
};

const manageDefaultIndexPatternRoutesFactory =
(path: string, serviceKey: string) =>
(
router: IRouter,
getStartServices: StartServicesAccessor<
DataViewsServerPluginStartDependencies,
DataViewsServerPluginStart
>
>,
usageCollection?: UsageCounter
) => {
router.get(
{
Expand All @@ -30,17 +67,21 @@ const manageDefaultIndexPatternRoutesFactory =
const savedObjectsClient = ctx.core.savedObjects.client;
const elasticsearchClient = ctx.core.elasticsearch.client.asCurrentUser;
const [, , { dataViewsServiceFactory }] = await getStartServices();
const indexPatternsService = await dataViewsServiceFactory(
const dataViewsService = await dataViewsServiceFactory(
savedObjectsClient,
elasticsearchClient,
req
);

const defaultIndexPatternId = await indexPatternsService.getDefaultId();
const id = await getDefault({
dataViewsService,
usageCollection,
counterName: `${req.route.method} ${path}`,
});

return res.ok({
body: {
[`${serviceKey}_id`]: defaultIndexPatternId,
[`${serviceKey}_id`]: id,
},
});
})
Expand All @@ -65,7 +106,7 @@ const manageDefaultIndexPatternRoutesFactory =
const savedObjectsClient = ctx.core.savedObjects.client;
const elasticsearchClient = ctx.core.elasticsearch.client.asCurrentUser;
const [, , { dataViewsServiceFactory }] = await getStartServices();
const indexPatternsService = await dataViewsServiceFactory(
const dataViewsService = await dataViewsServiceFactory(
savedObjectsClient,
elasticsearchClient,
req
Expand All @@ -74,7 +115,13 @@ const manageDefaultIndexPatternRoutesFactory =
const newDefaultId = req.body[`${serviceKey}_id`] as string;
const force = req.body.force as boolean;

await indexPatternsService.setDefault(newDefaultId, force);
await setDefault({
dataViewsService,
usageCollection,
counterName: `${req.route.method} ${path}`,
newDefaultId,
force,
});

return res.ok({
body: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { deleteDataView } from './delete_data_view';
import { dataViewsService } from '../mocks';
import { getUsageCollection } from './test_utils';

describe('delete data view', () => {
it('call usageCollection', () => {
const usageCollection = getUsageCollection();
deleteDataView({
dataViewsService,
counterName: 'DELETE /path',
usageCollection,
id: '1',
});
expect(usageCollection.incrementCounter).toBeCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,40 @@
* Side Public License, v 1.
*/

import { UsageCounter } from 'src/plugins/usage_collection/server';
import { schema } from '@kbn/config-schema';
import { DataViewsService } from 'src/plugins/data_views/common';
import { handleErrors } from './util/handle_errors';
import { IRouter, StartServicesAccessor } from '../../../../core/server';
import type { DataViewsServerPluginStartDependencies, DataViewsServerPluginStart } from '../types';
import { SPECIFIC_DATA_VIEW_PATH, SPECIFIC_DATA_VIEW_PATH_LEGACY } from '../constants';

interface DeleteDataViewArgs {
dataViewsService: DataViewsService;
usageCollection?: UsageCounter;
counterName: string;
id: string;
}

export const deleteDataView = async ({
dataViewsService,
usageCollection,
counterName,
id,
}: DeleteDataViewArgs) => {
usageCollection?.incrementCounter({ counterName });
return dataViewsService.delete(id);
};

const deleteIndexPatternRouteFactory =
(path: string) =>
(
router: IRouter,
getStartServices: StartServicesAccessor<
DataViewsServerPluginStartDependencies,
DataViewsServerPluginStart
>
>,
usageCollection?: UsageCounter
) => {
router.delete(
{
Expand All @@ -41,14 +61,19 @@ const deleteIndexPatternRouteFactory =
const savedObjectsClient = ctx.core.savedObjects.client;
const elasticsearchClient = ctx.core.elasticsearch.client.asCurrentUser;
const [, , { dataViewsServiceFactory }] = await getStartServices();
const indexPatternsService = await dataViewsServiceFactory(
const dataViewsService = await dataViewsServiceFactory(
savedObjectsClient,
elasticsearchClient,
req
);
const id = req.params.id;

await indexPatternsService.delete(id);
await deleteDataView({
dataViewsService,
usageCollection,
counterName: `${req.route.method} ${path}`,
id,
});

return res.ok({
headers: {
Expand Down
Loading