legacy dashboards import/export API: deprecation logs and usage data (#111283)

* Move legacy dashboards API to core and adds usage data

* More legacy_export plugin removal

* Log a warning for deprecated dashboard import/export API

* Review comments
This commit is contained in:
Rudolf Meijering 2021-09-08 22:15:52 +02:00 committed by GitHub
parent dda09b6b39
commit 5464af6923
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 565 additions and 136 deletions

1
.github/CODEOWNERS vendored
View file

@ -250,7 +250,6 @@
/src/plugins/kibana_overview/ @elastic/kibana-core
/x-pack/plugins/global_search_bar/ @elastic/kibana-core
#CC# /src/core/server/csp/ @elastic/kibana-core
#CC# /src/plugins/legacy_export/ @elastic/kibana-core
#CC# /src/plugins/xpack_legacy/ @elastic/kibana-core
#CC# /src/plugins/saved_objects/ @elastic/kibana-core
#CC# /x-pack/plugins/cloud/ @elastic/kibana-core

View file

@ -172,10 +172,6 @@ in Kibana, e.g. visualizations. It has the form of a flyout panel.
|Utilities for building Kibana plugins.
|{kib-repo}blob/{branch}/src/plugins/legacy_export/README.md[legacyExport]
|The legacyExport plugin adds support for the legacy saved objects export format.
|{kib-repo}blob/{branch}/src/plugins/management/README.md[management]
|This plugins contains the "Stack Management" page framework. It offers navigation and an API
to link individual managment section into it. This plugin does not contain any individual

View file

@ -51,14 +51,6 @@ Calls to the API endpoints require different operations. To interact with the {k
* *DELETE* - Removes the information.
For example, the following `curl` command exports a dashboard:
[source,sh]
--------------------------------------------
curl -X POST api/kibana/dashboards/export?dashboard=942dcef0-b2cd-11e8-ad8e-85441f0c2e5c
--------------------------------------------
// KIBANA
[float]
[[api-request-headers]]
=== Request headers

View file

@ -23,6 +23,8 @@ const createUsageStatsClientMock = () =>
incrementSavedObjectsImport: jest.fn().mockResolvedValue(null),
incrementSavedObjectsResolveImportErrors: jest.fn().mockResolvedValue(null),
incrementSavedObjectsExport: jest.fn().mockResolvedValue(null),
incrementLegacyDashboardsImport: jest.fn().mockResolvedValue(null),
incrementLegacyDashboardsExport: jest.fn().mockResolvedValue(null),
} as unknown) as jest.Mocked<CoreUsageStatsClient>);
export const coreUsageStatsClientMock = {

View file

@ -25,6 +25,8 @@ import {
IMPORT_STATS_PREFIX,
RESOLVE_IMPORT_STATS_PREFIX,
EXPORT_STATS_PREFIX,
LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX,
LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX,
} from './core_usage_stats_client';
import { CoreUsageStatsClient } from '.';
import { DEFAULT_NAMESPACE_STRING } from '../saved_objects/service/lib/utils';
@ -1007,4 +1009,114 @@ describe('CoreUsageStatsClient', () => {
);
});
});
describe('#incrementLegacyDashboardsImport', () => {
it('does not throw an error if repository incrementCounter operation fails', async () => {
const { usageStatsClient, repositoryMock } = setup();
repositoryMock.incrementCounter.mockRejectedValue(new Error('Oh no!'));
const request = httpServerMock.createKibanaRequest();
await expect(
usageStatsClient.incrementLegacyDashboardsImport({
request,
} as IncrementSavedObjectsExportOptions)
).resolves.toBeUndefined();
expect(repositoryMock.incrementCounter).toHaveBeenCalled();
});
it('handles the default namespace string and first party request appropriately', async () => {
const { usageStatsClient, repositoryMock } = setup(DEFAULT_NAMESPACE_STRING);
const request = httpServerMock.createKibanaRequest({ headers: firstPartyRequestHeaders });
await usageStatsClient.incrementLegacyDashboardsImport({
request,
} as IncrementSavedObjectsExportOptions);
expect(repositoryMock.incrementCounter).toHaveBeenCalledTimes(1);
expect(repositoryMock.incrementCounter).toHaveBeenCalledWith(
CORE_USAGE_STATS_TYPE,
CORE_USAGE_STATS_ID,
[
`${LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX}.total`,
`${LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX}.namespace.default.total`,
`${LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX}.namespace.default.kibanaRequest.yes`,
],
incrementOptions
);
});
it('handles a non-default space and and third party request appropriately', async () => {
const { usageStatsClient, repositoryMock } = setup('foo');
const request = httpServerMock.createKibanaRequest();
await usageStatsClient.incrementLegacyDashboardsImport({
request,
} as IncrementSavedObjectsExportOptions);
expect(repositoryMock.incrementCounter).toHaveBeenCalledTimes(1);
expect(repositoryMock.incrementCounter).toHaveBeenCalledWith(
CORE_USAGE_STATS_TYPE,
CORE_USAGE_STATS_ID,
[
`${LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX}.total`,
`${LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX}.namespace.custom.total`,
`${LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX}.namespace.custom.kibanaRequest.no`,
],
incrementOptions
);
});
});
describe('#incrementLegacyDashboardsExport', () => {
it('does not throw an error if repository incrementCounter operation fails', async () => {
const { usageStatsClient, repositoryMock } = setup();
repositoryMock.incrementCounter.mockRejectedValue(new Error('Oh no!'));
const request = httpServerMock.createKibanaRequest();
await expect(
usageStatsClient.incrementLegacyDashboardsExport({
request,
} as IncrementSavedObjectsExportOptions)
).resolves.toBeUndefined();
expect(repositoryMock.incrementCounter).toHaveBeenCalled();
});
it('handles the default namespace string and first party request appropriately', async () => {
const { usageStatsClient, repositoryMock } = setup(DEFAULT_NAMESPACE_STRING);
const request = httpServerMock.createKibanaRequest({ headers: firstPartyRequestHeaders });
await usageStatsClient.incrementLegacyDashboardsExport({
request,
} as IncrementSavedObjectsExportOptions);
expect(repositoryMock.incrementCounter).toHaveBeenCalledTimes(1);
expect(repositoryMock.incrementCounter).toHaveBeenCalledWith(
CORE_USAGE_STATS_TYPE,
CORE_USAGE_STATS_ID,
[
`${LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX}.total`,
`${LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX}.namespace.default.total`,
`${LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX}.namespace.default.kibanaRequest.yes`,
],
incrementOptions
);
});
it('handles a non-default space and and third party request appropriately', async () => {
const { usageStatsClient, repositoryMock } = setup('foo');
const request = httpServerMock.createKibanaRequest();
await usageStatsClient.incrementLegacyDashboardsExport({
request,
} as IncrementSavedObjectsExportOptions);
expect(repositoryMock.incrementCounter).toHaveBeenCalledTimes(1);
expect(repositoryMock.incrementCounter).toHaveBeenCalledWith(
CORE_USAGE_STATS_TYPE,
CORE_USAGE_STATS_ID,
[
`${LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX}.total`,
`${LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX}.namespace.custom.total`,
`${LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX}.namespace.custom.kibanaRequest.no`,
],
incrementOptions
);
});
});
});

View file

@ -45,6 +45,9 @@ export const UPDATE_STATS_PREFIX = 'apiCalls.savedObjectsUpdate';
export const IMPORT_STATS_PREFIX = 'apiCalls.savedObjectsImport';
export const RESOLVE_IMPORT_STATS_PREFIX = 'apiCalls.savedObjectsResolveImportErrors';
export const EXPORT_STATS_PREFIX = 'apiCalls.savedObjectsExport';
export const LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX = 'apiCalls.legacyDashboardImport';
export const LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX = 'apiCalls.legacyDashboardExport';
export const REPOSITORY_RESOLVE_OUTCOME_STATS = {
EXACT_MATCH: 'savedObjectsRepository.resolvedOutcome.exactMatch',
ALIAS_MATCH: 'savedObjectsRepository.resolvedOutcome.aliasMatch',
@ -73,6 +76,8 @@ const ALL_COUNTER_FIELDS = [
`${RESOLVE_IMPORT_STATS_PREFIX}.createNewCopiesEnabled.yes`,
`${RESOLVE_IMPORT_STATS_PREFIX}.createNewCopiesEnabled.no`,
...getFieldsForCounter(EXPORT_STATS_PREFIX),
...getFieldsForCounter(LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX),
...getFieldsForCounter(LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX),
`${EXPORT_STATS_PREFIX}.allTypesSelected.yes`,
`${EXPORT_STATS_PREFIX}.allTypesSelected.no`,
// Saved Objects Repository counters; these are included here for stats collection, but are incremented in the repository itself
@ -170,6 +175,14 @@ export class CoreUsageStatsClient {
await this.updateUsageStats(counterFieldNames, EXPORT_STATS_PREFIX, options);
}
public async incrementLegacyDashboardsImport(options: BaseIncrementOptions) {
await this.updateUsageStats([], LEGACY_DASHBOARDS_IMPORT_STATS_PREFIX, options);
}
public async incrementLegacyDashboardsExport(options: BaseIncrementOptions) {
await this.updateUsageStats([], LEGACY_DASHBOARDS_EXPORT_STATS_PREFIX, options);
}
private async updateUsageStats(
counterFieldNames: string[],
prefix: string,

View file

@ -110,6 +110,21 @@ export interface CoreUsageStats {
'apiCalls.savedObjectsExport.namespace.custom.kibanaRequest.no'?: number;
'apiCalls.savedObjectsExport.allTypesSelected.yes'?: number;
'apiCalls.savedObjectsExport.allTypesSelected.no'?: number;
// Legacy Dashboard Import/Export API
'apiCalls.legacyDashboardExport.total'?: number;
'apiCalls.legacyDashboardExport.namespace.default.total'?: number;
'apiCalls.legacyDashboardExport.namespace.default.kibanaRequest.yes'?: number;
'apiCalls.legacyDashboardExport.namespace.default.kibanaRequest.no'?: number;
'apiCalls.legacyDashboardExport.namespace.custom.total'?: number;
'apiCalls.legacyDashboardExport.namespace.custom.kibanaRequest.yes'?: number;
'apiCalls.legacyDashboardExport.namespace.custom.kibanaRequest.no'?: number;
'apiCalls.legacyDashboardImport.total'?: number;
'apiCalls.legacyDashboardImport.namespace.default.total'?: number;
'apiCalls.legacyDashboardImport.namespace.default.kibanaRequest.yes'?: number;
'apiCalls.legacyDashboardImport.namespace.default.kibanaRequest.no'?: number;
'apiCalls.legacyDashboardImport.namespace.custom.total'?: number;
'apiCalls.legacyDashboardImport.namespace.custom.kibanaRequest.yes'?: number;
'apiCalls.legacyDashboardImport.namespace.custom.kibanaRequest.no'?: number;
// Saved Objects Repository counters
'savedObjectsRepository.resolvedOutcome.exactMatch'?: number;
'savedObjectsRepository.resolvedOutcome.aliasMatch'?: number;

View file

@ -24,6 +24,8 @@ import { registerExportRoute } from './export';
import { registerImportRoute } from './import';
import { registerResolveImportErrorsRoute } from './resolve_import_errors';
import { registerMigrateRoute } from './migrate';
import { registerLegacyImportRoute } from './legacy_import_export/import';
import { registerLegacyExportRoute } from './legacy_import_export/export';
export function registerRoutes({
http,
@ -31,12 +33,14 @@ export function registerRoutes({
logger,
config,
migratorPromise,
kibanaVersion,
}: {
http: InternalHttpServiceSetup;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
config: SavedObjectConfig;
migratorPromise: Promise<IKibanaMigrator>;
kibanaVersion: string;
}) {
const router = http.createRouter('/api/saved_objects/');
@ -53,6 +57,14 @@ export function registerRoutes({
registerImportRoute(router, { config, coreUsageData });
registerResolveImportErrorsRoute(router, { config, coreUsageData });
const legacyRouter = http.createRouter('');
registerLegacyImportRoute(legacyRouter, {
maxImportPayloadBytes: config.maxImportPayloadBytes,
coreUsageData,
logger,
});
registerLegacyExportRoute(legacyRouter, { kibanaVersion, coreUsageData, logger });
const internalRouter = http.createRouter('/internal/saved_objects/');
registerMigrateRoute(internalRouter, migratorPromise);

View file

@ -8,10 +8,18 @@
import moment from 'moment';
import { schema } from '@kbn/config-schema';
import { IRouter } from 'src/core/server';
import { exportDashboards } from '../lib';
import { InternalCoreUsageDataSetup } from 'src/core/server/core_usage_data';
import { IRouter, Logger } from '../../..';
import { exportDashboards } from './lib';
export const registerExportRoute = (router: IRouter, kibanaVersion: string) => {
export const registerLegacyExportRoute = (
router: IRouter,
{
kibanaVersion,
coreUsageData,
logger,
}: { kibanaVersion: string; coreUsageData: InternalCoreUsageDataSetup; logger: Logger }
) => {
router.get(
{
path: '/api/kibana/dashboards/export',
@ -25,9 +33,16 @@ export const registerExportRoute = (router: IRouter, kibanaVersion: string) => {
},
},
async (ctx, req, res) => {
logger.warn(
"The export dashboard API '/api/kibana/dashboards/export' is deprecated. Use the saved objects export objects API '/api/saved_objects/_export' instead."
);
const ids = Array.isArray(req.query.dashboard) ? req.query.dashboard : [req.query.dashboard];
const { client } = ctx.core.savedObjects;
const usageStatsClient = coreUsageData.getClient();
usageStatsClient.incrementLegacyDashboardsExport({ request: req }).catch(() => {});
const exported = await exportDashboards(ids, client, kibanaVersion);
const filename = `kibana-dashboards.${moment.utc().format('YYYY-MM-DD-HH-mm-ss')}.json`;
const body = JSON.stringify(exported, null, ' ');

View file

@ -7,10 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter, SavedObject } from 'src/core/server';
import { importDashboards } from '../lib';
import { IRouter, Logger, SavedObject } from '../../..';
import { InternalCoreUsageDataSetup } from '../../../core_usage_data';
import { importDashboards } from './lib';
export const registerImportRoute = (router: IRouter, maxImportPayloadBytes: number) => {
export const registerLegacyImportRoute = (
router: IRouter,
{
maxImportPayloadBytes,
coreUsageData,
logger,
}: { maxImportPayloadBytes: number; coreUsageData: InternalCoreUsageDataSetup; logger: Logger }
) => {
router.post(
{
path: '/api/kibana/dashboards/import',
@ -34,9 +42,17 @@ export const registerImportRoute = (router: IRouter, maxImportPayloadBytes: numb
},
},
async (ctx, req, res) => {
logger.warn(
"The import dashboard API '/api/kibana/dashboards/import' is deprecated. Use the saved objects import objects API '/api/saved_objects/_import' instead."
);
const { client } = ctx.core.savedObjects;
const objects = req.body.objects as SavedObject[];
const { force, exclude } = req.query;
const usageStatsClient = coreUsageData.getClient();
usageStatsClient.incrementLegacyDashboardsImport({ request: req }).catch(() => {});
const result = await importDashboards(client, objects, {
overwrite: force,
exclude: Array.isArray(exclude) ? exclude : [exclude],

View file

@ -0,0 +1,89 @@
/*
* 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.
*/
const exportObjects = [
{
id: '1',
type: 'index-pattern',
attributes: {},
references: [],
},
{
id: '2',
type: 'search',
attributes: {},
references: [
{
name: 'ref_0',
type: 'index-pattern',
id: '1',
},
],
},
];
jest.mock('../lib/export_dashboards', () => ({
exportDashboards: jest.fn().mockResolvedValue({ version: 'mockversion', objects: exportObjects }),
}));
import supertest from 'supertest';
import type { UnwrapPromise } from '@kbn/utility-types';
import { CoreUsageStatsClient } from '../../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../../core_usage_data/core_usage_data_service.mock';
import { registerLegacyExportRoute } from '../export';
import { setupServer } from '../../test_utils';
import { loggerMock } from 'src/core/server/logging/logger.mock';
type SetupServerReturn = UnwrapPromise<ReturnType<typeof setupServer>>;
let coreUsageStatsClient: jest.Mocked<CoreUsageStatsClient>;
describe('POST /api/dashboards/export', () => {
let server: SetupServerReturn['server'];
let httpSetup: SetupServerReturn['httpSetup'];
beforeEach(async () => {
({ server, httpSetup } = await setupServer());
const router = httpSetup.createRouter('');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementLegacyDashboardsExport.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);
registerLegacyExportRoute(router, {
kibanaVersion: '7.14.0',
coreUsageData,
logger: loggerMock.create(),
});
await server.start();
});
afterEach(async () => {
jest.clearAllMocks();
await server.stop();
});
it('calls exportDashboards and records usage stats', async () => {
const result = await supertest(httpSetup.server.listener).get(
'/api/kibana/dashboards/export?dashboard=942dcef0-b2cd-11e8-ad8e-85441f0c2e5c'
);
expect(result.status).toBe(200);
expect(result.header['content-type']).toEqual('application/json; charset=utf-8');
expect(result.header['content-disposition']).toMatch(
/attachment; filename="kibana-dashboards.*\.json/
);
expect(result.body.objects).toEqual(exportObjects);
expect(result.body.version).toEqual('mockversion');
expect(coreUsageStatsClient.incrementLegacyDashboardsExport).toHaveBeenCalledWith({
request: expect.anything(),
});
});
});

View file

@ -0,0 +1,84 @@
/*
* 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.
*/
const importObjects = [
{
id: '1',
type: 'index-pattern',
attributes: {},
references: [],
},
{
id: '2',
type: 'search',
attributes: {},
references: [
{
name: 'ref_0',
type: 'index-pattern',
id: '1',
},
],
},
];
jest.mock('../lib/import_dashboards', () => ({
importDashboards: jest.fn().mockResolvedValue({ objects: importObjects }),
}));
import supertest from 'supertest';
import type { UnwrapPromise } from '@kbn/utility-types';
import { CoreUsageStatsClient } from '../../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../../core_usage_data/core_usage_data_service.mock';
import { registerLegacyImportRoute } from '../import';
import { setupServer } from '../../test_utils';
import { loggerMock } from 'src/core/server/logging/logger.mock';
type SetupServerReturn = UnwrapPromise<ReturnType<typeof setupServer>>;
let coreUsageStatsClient: jest.Mocked<CoreUsageStatsClient>;
describe('POST /api/dashboards/import', () => {
let server: SetupServerReturn['server'];
let httpSetup: SetupServerReturn['httpSetup'];
beforeEach(async () => {
({ server, httpSetup } = await setupServer());
const router = httpSetup.createRouter('');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementLegacyDashboardsImport.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);
registerLegacyImportRoute(router, {
maxImportPayloadBytes: 26214400,
coreUsageData,
logger: loggerMock.create(),
});
await server.start();
});
afterEach(async () => {
jest.clearAllMocks();
await server.stop();
});
it('calls importDashboards and records usage stats', async () => {
const result = await supertest(httpSetup.server.listener)
.post('/api/kibana/dashboards/import')
.send({ version: '7.14.0', objects: importObjects });
expect(result.status).toBe(200);
expect(result.body.objects).toEqual(importObjects);
expect(coreUsageStatsClient.incrementLegacyDashboardsImport).toHaveBeenCalledWith({
request: expect.anything(),
});
});
});

View file

@ -7,7 +7,7 @@
*/
import { SavedObject, SavedObjectAttributes } from 'src/core/server';
import { savedObjectsClientMock } from '../../../../../core/server/mocks';
import { savedObjectsClientMock } from '../../../../mocks';
import { collectReferencesDeep } from './collect_references_deep';
const data: Array<SavedObject<SavedObjectAttributes>> = [

View file

@ -6,8 +6,8 @@
* Side Public License, v 1.
*/
import { savedObjectsClientMock } from '../../../../../core/server/mocks';
import { SavedObject } from '../../../../../core/server';
import { savedObjectsClientMock } from '../../../../mocks';
import { SavedObject } from '../../../..';
import { importDashboards } from './import_dashboards';
describe('importDashboards(req)', () => {

View file

@ -6,8 +6,5 @@
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../..',
roots: ['<rootDir>/src/plugins/legacy_export'],
};
export { exportDashboards } from './export_dashboards';
export { importDashboards } from './import_dashboards';

View file

@ -306,6 +306,7 @@ export class SavedObjectsService
logger: this.logger,
config: this.config,
migratorPromise: this.migrator$.pipe(first()).toPromise(),
kibanaVersion: this.coreContext.env.packageInfo.version,
});
registerCoreObjectTypes(this.typeRegistry);

View file

@ -491,6 +491,34 @@ export interface CoreUsageDataStart {
// @internal
export interface CoreUsageStats {
// (undocumented)
'apiCalls.legacyDashboardExport.namespace.custom.kibanaRequest.no'?: number;
// (undocumented)
'apiCalls.legacyDashboardExport.namespace.custom.kibanaRequest.yes'?: number;
// (undocumented)
'apiCalls.legacyDashboardExport.namespace.custom.total'?: number;
// (undocumented)
'apiCalls.legacyDashboardExport.namespace.default.kibanaRequest.no'?: number;
// (undocumented)
'apiCalls.legacyDashboardExport.namespace.default.kibanaRequest.yes'?: number;
// (undocumented)
'apiCalls.legacyDashboardExport.namespace.default.total'?: number;
// (undocumented)
'apiCalls.legacyDashboardExport.total'?: number;
// (undocumented)
'apiCalls.legacyDashboardImport.namespace.custom.kibanaRequest.no'?: number;
// (undocumented)
'apiCalls.legacyDashboardImport.namespace.custom.kibanaRequest.yes'?: number;
// (undocumented)
'apiCalls.legacyDashboardImport.namespace.custom.total'?: number;
// (undocumented)
'apiCalls.legacyDashboardImport.namespace.default.kibanaRequest.no'?: number;
// (undocumented)
'apiCalls.legacyDashboardImport.namespace.default.kibanaRequest.yes'?: number;
// (undocumented)
'apiCalls.legacyDashboardImport.namespace.default.total'?: number;
// (undocumented)
'apiCalls.legacyDashboardImport.total'?: number;
// (undocumented)
'apiCalls.savedObjectsBulkCreate.namespace.custom.kibanaRequest.no'?: number;
// (undocumented)

View file

@ -936,11 +936,51 @@ export function getCoreUsageCollector(
'How many times this API has been called by a non-Kibana client in a custom space.',
},
},
'apiCalls.savedObjectsExport.allTypesSelected.yes': {
// Legacy dashboard import/export APIs
'apiCalls.legacyDashboardExport.total': {
type: 'long',
_meta: { description: 'How many times this API has been called.' },
},
'apiCalls.legacyDashboardExport.namespace.default.total': {
type: 'long',
_meta: { description: 'How many times this API has been called in the Default space.' },
},
'apiCalls.legacyDashboardExport.namespace.default.kibanaRequest.yes': {
type: 'long',
_meta: {
description:
'How many times this API has been called with the `createNewCopiesEnabled` option.',
'How many times this API has been called by the Kibana client in the Default space.',
},
},
'apiCalls.legacyDashboardExport.namespace.default.kibanaRequest.no': {
type: 'long',
_meta: {
description:
'How many times this API has been called by a non-Kibana client in the Default space.',
},
},
'apiCalls.legacyDashboardExport.namespace.custom.total': {
type: 'long',
_meta: { description: 'How many times this API has been called in a custom space.' },
},
'apiCalls.legacyDashboardExport.namespace.custom.kibanaRequest.yes': {
type: 'long',
_meta: {
description:
'How many times this API has been called by the Kibana client in a custom space.',
},
},
'apiCalls.legacyDashboardExport.namespace.custom.kibanaRequest.no': {
type: 'long',
_meta: {
description:
'How many times this API has been called by a non-Kibana client in a custom space.',
},
},
'apiCalls.savedObjectsExport.allTypesSelected.yes': {
type: 'long',
_meta: {
description: 'How many times this API has been called with all types selected.',
},
},
'apiCalls.savedObjectsExport.allTypesSelected.no': {
@ -949,6 +989,46 @@ export function getCoreUsageCollector(
description: 'How many times this API has been called without all types selected.',
},
},
'apiCalls.legacyDashboardImport.total': {
type: 'long',
_meta: { description: 'How many times this API has been called.' },
},
'apiCalls.legacyDashboardImport.namespace.default.total': {
type: 'long',
_meta: { description: 'How many times this API has been called in the Default space.' },
},
'apiCalls.legacyDashboardImport.namespace.default.kibanaRequest.yes': {
type: 'long',
_meta: {
description:
'How many times this API has been called by the Kibana client in the Default space.',
},
},
'apiCalls.legacyDashboardImport.namespace.default.kibanaRequest.no': {
type: 'long',
_meta: {
description:
'How many times this API has been called by a non-Kibana client in the Default space.',
},
},
'apiCalls.legacyDashboardImport.namespace.custom.total': {
type: 'long',
_meta: { description: 'How many times this API has been called in a custom space.' },
},
'apiCalls.legacyDashboardImport.namespace.custom.kibanaRequest.yes': {
type: 'long',
_meta: {
description:
'How many times this API has been called by the Kibana client in a custom space.',
},
},
'apiCalls.legacyDashboardImport.namespace.custom.kibanaRequest.no': {
type: 'long',
_meta: {
description:
'How many times this API has been called by a non-Kibana client in a custom space.',
},
},
// Saved Objects Repository counters
'savedObjectsRepository.resolvedOutcome.exactMatch': {
type: 'long',

View file

@ -1,3 +0,0 @@
# `legacyExport` plugin [deprecated]
The `legacyExport` plugin adds support for the legacy saved objects export format.

View file

@ -1,10 +0,0 @@
{
"id": "legacyExport",
"owner": {
"name": "Kibana Core",
"githubTeam": "kibana-core"
},
"version": "kibana",
"server": true,
"ui": false
}

View file

@ -1,12 +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
* 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 { PluginInitializer } from 'src/core/server';
import { LegacyExportPlugin } from './plugin';
export const plugin: PluginInitializer<{}, {}> = (context) => new LegacyExportPlugin(context);

View file

@ -1,10 +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
* 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.
*/
export { exportDashboards } from './export/export_dashboards';
export { importDashboards } from './import/import_dashboards';

View file

@ -1,34 +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
* 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 { Plugin, CoreSetup, PluginInitializerContext } from 'kibana/server';
import { registerRoutes } from './routes';
/** @deprecated */
export class LegacyExportPlugin implements Plugin<{}, {}> {
constructor(private readonly initContext: PluginInitializerContext) {}
public setup({ http }: CoreSetup) {
const globalConfig = this.initContext.config.legacy.get();
const router = http.createRouter();
registerRoutes(
router,
this.initContext.env.packageInfo.version,
globalConfig.savedObjects.maxImportPayloadBytes.getValueInBytes()
);
return {};
}
public start() {
return {};
}
public stop() {}
}

View file

@ -1,20 +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
* 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 { IRouter } from 'src/core/server';
import { registerImportRoute } from './import';
import { registerExportRoute } from './export';
export const registerRoutes = (
router: IRouter,
kibanaVersion: string,
maxImportPayloadBytes: number
) => {
registerExportRoute(router, kibanaVersion);
registerImportRoute(router, maxImportPayloadBytes);
};

View file

@ -1,15 +0,0 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./target/types",
"emitDeclarationOnly": true,
"declaration": true,
"declarationMap": true
},
"include": [
"server/**/*",
],
"references": [
{ "path": "../../core/tsconfig.json" }
]
}

View file

@ -6850,10 +6850,52 @@
"description": "How many times this API has been called by a non-Kibana client in a custom space."
}
},
"apiCalls.legacyDashboardExport.total": {
"type": "long",
"_meta": {
"description": "How many times this API has been called."
}
},
"apiCalls.legacyDashboardExport.namespace.default.total": {
"type": "long",
"_meta": {
"description": "How many times this API has been called in the Default space."
}
},
"apiCalls.legacyDashboardExport.namespace.default.kibanaRequest.yes": {
"type": "long",
"_meta": {
"description": "How many times this API has been called by the Kibana client in the Default space."
}
},
"apiCalls.legacyDashboardExport.namespace.default.kibanaRequest.no": {
"type": "long",
"_meta": {
"description": "How many times this API has been called by a non-Kibana client in the Default space."
}
},
"apiCalls.legacyDashboardExport.namespace.custom.total": {
"type": "long",
"_meta": {
"description": "How many times this API has been called in a custom space."
}
},
"apiCalls.legacyDashboardExport.namespace.custom.kibanaRequest.yes": {
"type": "long",
"_meta": {
"description": "How many times this API has been called by the Kibana client in a custom space."
}
},
"apiCalls.legacyDashboardExport.namespace.custom.kibanaRequest.no": {
"type": "long",
"_meta": {
"description": "How many times this API has been called by a non-Kibana client in a custom space."
}
},
"apiCalls.savedObjectsExport.allTypesSelected.yes": {
"type": "long",
"_meta": {
"description": "How many times this API has been called with the `createNewCopiesEnabled` option."
"description": "How many times this API has been called with all types selected."
}
},
"apiCalls.savedObjectsExport.allTypesSelected.no": {
@ -6862,6 +6904,48 @@
"description": "How many times this API has been called without all types selected."
}
},
"apiCalls.legacyDashboardImport.total": {
"type": "long",
"_meta": {
"description": "How many times this API has been called."
}
},
"apiCalls.legacyDashboardImport.namespace.default.total": {
"type": "long",
"_meta": {
"description": "How many times this API has been called in the Default space."
}
},
"apiCalls.legacyDashboardImport.namespace.default.kibanaRequest.yes": {
"type": "long",
"_meta": {
"description": "How many times this API has been called by the Kibana client in the Default space."
}
},
"apiCalls.legacyDashboardImport.namespace.default.kibanaRequest.no": {
"type": "long",
"_meta": {
"description": "How many times this API has been called by a non-Kibana client in the Default space."
}
},
"apiCalls.legacyDashboardImport.namespace.custom.total": {
"type": "long",
"_meta": {
"description": "How many times this API has been called in a custom space."
}
},
"apiCalls.legacyDashboardImport.namespace.custom.kibanaRequest.yes": {
"type": "long",
"_meta": {
"description": "How many times this API has been called by the Kibana client in a custom space."
}
},
"apiCalls.legacyDashboardImport.namespace.custom.kibanaRequest.no": {
"type": "long",
"_meta": {
"description": "How many times this API has been called by a non-Kibana client in a custom space."
}
},
"savedObjectsRepository.resolvedOutcome.exactMatch": {
"type": "long",
"_meta": {

View file

@ -52,7 +52,6 @@
{ "path": "../src/plugins/url_forwarding/tsconfig.json" },
{ "path": "../src/plugins/usage_collection/tsconfig.json" },
{ "path": "../src/plugins/index_pattern_management/tsconfig.json" },
{ "path": "../src/plugins/legacy_export/tsconfig.json" },
{ "path": "../src/plugins/visualize/tsconfig.json" },
{ "path": "plugin_functional/plugins/core_app_status/tsconfig.json" },
{ "path": "plugin_functional/plugins/core_provider_plugin/tsconfig.json" },

View file

@ -34,7 +34,6 @@
{ "path": "../../src/plugins/kibana_react/tsconfig.json" },
{ "path": "../../src/plugins/kibana_usage_collection/tsconfig.json" },
{ "path": "../../src/plugins/kibana_utils/tsconfig.json" },
{ "path": "../../src/plugins/legacy_export/tsconfig.json" },
{ "path": "../../src/plugins/management/tsconfig.json" },
{ "path": "../../src/plugins/navigation/tsconfig.json" },
{ "path": "../../src/plugins/newsfeed/tsconfig.json" },