[Logs] Provide help for migrating Logs UI settings (#189646)

## Summary

This implements https://github.com/elastic/kibana/issues/186824.

A new API has been added so that automated corrective actions can be
applied.

## UI / UX


![migration](https://github.com/user-attachments/assets/136d96e3-f3b0-46c4-b3b8-b70f0cb08b65)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Kerry Gallagher 2024-08-14 19:11:57 +01:00 committed by GitHub
parent d6b151862d
commit fc12e58c2f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 311 additions and 1 deletions

View file

@ -25,6 +25,7 @@ defaultQueue: 'n2-4-spot'
enabled:
- x-pack/test/alerting_api_integration/observability/config.ts
- x-pack/test/api_integration/apis/logs_ui/config.ts
- x-pack/test/api_integration/apis/logs_shared/config.ts
- x-pack/test/api_integration/apis/metrics_ui/config.ts
- x-pack/test/api_integration/apis/osquery/config.ts
- x-pack/test/api_integration/apis/synthetics/config.ts

View file

@ -0,0 +1,9 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export const MIGRATE_LOG_VIEW_SETTINGS_URL =
'/api/logs_shared/deprecations/migrate_log_view_settings';

View file

@ -0,0 +1,22 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { LogsSharedPluginCoreSetup } from '../types';
import { getLogSourcesSettingDeprecationInfo } from './log_sources_setting';
export const registerDeprecations = ({ core }: { core: LogsSharedPluginCoreSetup }) => {
core.deprecations.registerDeprecations({
getDeprecations: async (context) => {
return [
...(await getLogSourcesSettingDeprecationInfo({
context,
getStartServices: core.getStartServices,
})),
];
},
});
};

View file

@ -0,0 +1,73 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { DeprecationsDetails } from '@kbn/core-deprecations-common';
import { GetDeprecationsContext } from '@kbn/core-deprecations-server';
import { i18n } from '@kbn/i18n';
import { defaultLogViewId } from '../../common/log_views';
import { MIGRATE_LOG_VIEW_SETTINGS_URL } from '../../common/http_api/deprecations';
import { logSourcesKibanaAdvancedSettingRT } from '../../common';
import { LogsSharedPluginStartServicesAccessor } from '../types';
export const getLogSourcesSettingDeprecationInfo = async ({
getStartServices,
context,
}: {
context: GetDeprecationsContext;
getStartServices: LogsSharedPluginStartServicesAccessor;
}): Promise<DeprecationsDetails[]> => {
const [_, pluginStartDeps, pluginStart] = await getStartServices();
const logSourcesService =
pluginStartDeps.logsDataAccess.services.logSourcesServiceFactory.getLogSourcesService(
context.savedObjectsClient
);
const logViewsClient = pluginStart.logViews.getClient(
context.savedObjectsClient,
context.esClient.asCurrentUser,
logSourcesService
);
const logView = await logViewsClient.getLogView(defaultLogViewId);
if (logView && !logSourcesKibanaAdvancedSettingRT.is(logView.attributes.logIndices)) {
return [
{
title: i18n.translate(
'xpack.logsShared.deprecations.migrateLogViewSettingsToLogSourcesSetting.title',
{
defaultMessage: 'Log sources setting',
}
),
level: 'warning',
deprecationType: 'feature',
message: i18n.translate(
'xpack.logsShared.deprecations.migrateLogViewSettingsToLogSourcesSetting.message',
{
defaultMessage:
'Indices and Data view options previously provided via the Logs UI settings page are now deprecated. Please migrate to using the Kibana log sources advanced setting.',
}
),
correctiveActions: {
manualSteps: [
i18n.translate(
'xpack.logsShared.deprecations.migrateLogViewSettingsToLogSourcesSetting.message.manualStepMessage',
{
defaultMessage:
'Update the Log sources Kibana advanced setting (via Management > Advanced Settings) to match the setting previously provided via the Logs UI settings page. Then via the Logs UI settings page use the Kibana log sources advanced setting option.',
}
),
],
api: {
method: 'PUT',
path: MIGRATE_LOG_VIEW_SETTINGS_URL,
},
},
},
];
} else {
return [];
}
};

View file

@ -12,10 +12,12 @@ import {
initLogEntriesSummaryRoute,
} from './routes/log_entries';
import { initLogViewRoutes } from './routes/log_views';
import { initMigrateLogViewSettingsRoute } from './routes/deprecations';
export const initLogsSharedServer = (libs: LogsSharedBackendLibs) => {
initLogEntriesHighlightsRoute(libs);
initLogEntriesSummaryRoute(libs);
initLogEntriesSummaryHighlightsRoute(libs);
initLogViewRoutes(libs);
initMigrateLogViewSettingsRoute(libs);
};

View file

@ -24,6 +24,8 @@ import { LogsSharedLogEntriesDomain } from './lib/domains/log_entries_domain';
import { LogsSharedKibanaLogEntriesAdapter } from './lib/adapters/log_entries/kibana_log_entries_adapter';
import { LogEntriesService } from './services/log_entries';
import { LogsSharedConfig } from '../common/plugin_config';
import { registerDeprecations } from './deprecations';
import { defaultLogViewId } from '../common/log_views';
export class LogsSharedPlugin
implements
@ -58,7 +60,7 @@ export class LogsSharedPlugin
core.savedObjects.registerType(logViewSavedObjectType);
} else {
// Register a static internal view to use as a fallback when the log view SO is not registered
logViews.defineInternalLogView('default', {});
logViews.defineInternalLogView(defaultLogViewId, {});
}
const domainLibs: LogsSharedDomainLibs = {
@ -84,6 +86,8 @@ export class LogsSharedPlugin
const logEntriesService = new LogEntriesService();
logEntriesService.setup(core, plugins);
registerDeprecations({ core });
return {
...domainLibs,
logViews,

View file

@ -0,0 +1,8 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export * from './migrate_log_view_settings';

View file

@ -0,0 +1,62 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { defaultLogViewId } from '../../../common/log_views';
import { MIGRATE_LOG_VIEW_SETTINGS_URL } from '../../../common/http_api/deprecations';
import { logSourcesKibanaAdvancedSettingRT } from '../../../common';
import { LogsSharedBackendLibs } from '../../lib/logs_shared_types';
// This route facilitates automated one-click handling of updating log view's to use the
// Kibana advanced setting as part of the upgrade assistant.
// First, it will gather the indices currently set on the log view.
// Secondly, it will update the advanced setting to use these indices.
// Lastly, it will update the log view to use the kibana advanced setting.
export const initMigrateLogViewSettingsRoute = ({
framework,
getStartServices,
}: LogsSharedBackendLibs) => {
framework.router.put(
{ path: MIGRATE_LOG_VIEW_SETTINGS_URL, validate: false },
async (context, request, response) => {
try {
const [_, pluginStartDeps, pluginStart] = await getStartServices();
const logSourcesService =
await pluginStartDeps.logsDataAccess.services.logSourcesServiceFactory.getScopedLogSourcesService(
request
);
const logViewsClient = pluginStart.logViews.getScopedClient(request);
const logView = await logViewsClient.getLogView(defaultLogViewId);
if (!logView || logSourcesKibanaAdvancedSettingRT.is(logView.attributes.logIndices)) {
return response.customError({
body: new Error(
"Unable to migrate log view settings. A log view either doesn't exist or is already using the Kibana advanced setting."
),
statusCode: 400,
});
}
const indices = (
await logViewsClient.getResolvedLogView({
type: 'log-view-reference',
logViewId: defaultLogViewId,
})
).indices;
await logSourcesService.setLogSources([{ indexPattern: indices }]);
await logViewsClient.putLogView(defaultLogViewId, {
logIndices: { type: 'kibana_advanced_setting' },
});
return response.ok();
} catch (error) {
throw error;
}
}
);
};

View file

@ -42,5 +42,7 @@
"@kbn/test-jest-helpers",
"@kbn/router-utils",
"@kbn/logs-data-access-plugin",
"@kbn/core-deprecations-common",
"@kbn/core-deprecations-server",
]
}

View file

@ -0,0 +1,17 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrConfigProviderContext } from '@kbn/test';
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../config.ts'));
return {
...baseIntegrationTestsConfig.getAll(),
testFiles: [require.resolve('.')],
};
}

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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('Logs shared routes', () => {
loadTestFile(require.resolve('./migrate_log_view_settings'));
});
}

View file

@ -0,0 +1,95 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import expect from '@kbn/expect';
import { LogViewAttributes } from '@kbn/logs-shared-plugin/common/log_views';
import { infraSourceConfigurationSavedObjectName } from '@kbn/infra-plugin/server/lib/sources';
import { logViewSavedObjectName } from '@kbn/logs-shared-plugin/server';
import { defaultLogViewId } from '@kbn/logs-shared-plugin/common/log_views';
import { MIGRATE_LOG_VIEW_SETTINGS_URL } from '@kbn/logs-shared-plugin/common/http_api/deprecations';
import { OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID } from '@kbn/management-settings-ids';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const logViewsService = getService('infraLogViews');
const kibanaServer = getService('kibanaServer');
const retry = getService('retry');
const INDICES = 'logs-*,something-else-*,test-*';
describe('Log view settings migration', () => {
describe('Migration API', () => {
before(async () => {
await kibanaServer.savedObjects.clean({
types: [infraSourceConfigurationSavedObjectName, logViewSavedObjectName],
});
});
afterEach(async () => {
await kibanaServer.savedObjects.clean({
types: [infraSourceConfigurationSavedObjectName, logViewSavedObjectName],
});
});
it('performs a migration when the log view is not using the Kibana advanced setting', async () => {
const logViewAttributes: Partial<LogViewAttributes> = {
name: 'Test Log View 1',
description: 'Test Description 1',
logIndices: { type: 'index_name', indexName: INDICES },
logColumns: [],
};
await logViewsService.putLogView(defaultLogViewId, {
attributes: logViewAttributes,
});
await supertest
.put(MIGRATE_LOG_VIEW_SETTINGS_URL)
.set({
'kbn-xsrf': 'some-xsrf-token',
})
.send()
.expect(200);
await retry.try(async () => {
const migratedLogView = await logViewsService.getLogView(defaultLogViewId);
expect(migratedLogView.data.attributes.logIndices.type).to.eql('kibana_advanced_setting');
const uiSetting = await kibanaServer.uiSettings.get(
OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID
);
expect(uiSetting).to.eql([INDICES]);
});
});
it('should error when the log view is already using the Kibana advanced setting', async () => {
const logViewAttributes: Partial<LogViewAttributes> = {
name: 'Test Log View 1',
description: 'Test Description 1',
logIndices: { type: 'kibana_advanced_setting' },
logColumns: [],
};
await logViewsService.putLogView(defaultLogViewId, {
attributes: logViewAttributes,
});
const response = await supertest
.put(MIGRATE_LOG_VIEW_SETTINGS_URL)
.set({
'kbn-xsrf': 'some-xsrf-token',
})
.send()
.expect(400);
expect(response.body.message).to.eql(
"Unable to migrate log view settings. A log view either doesn't exist or is already using the Kibana advanced setting."
);
});
});
});
}

View file

@ -177,6 +177,7 @@
"@kbn/entities-schema",
"@kbn/actions-simulators-plugin",
"@kbn/cases-api-integration-test-plugin",
"@kbn/management-settings-ids",
"@kbn/mock-idp-utils"
]
}