[ML] Catching registration errors after license change (#167622)

We register our cases integration after checking that the license level
is platinum or trial, however if the license changes from platinum ->
basic and then back again, we attempt to register them again. This
throws an error during kibana start up.

To test, change the license level platinum/trial -> basic and then basic
-> platinum.
There will now be a warning the log `ML failed to register cases
persistable state for ml_anomaly_swimlane`

Also updates the AIOPs change point cases registration which also should
only be registered when running with a platinum or trial license.
This commit is contained in:
James Gowdy 2023-10-03 09:11:59 +01:00 committed by GitHub
parent 87287fcd05
commit eddcdbea24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 88 additions and 42 deletions

View file

@ -10,8 +10,6 @@ import { Subscription } from 'rxjs';
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server';
import type { DataRequestHandlerContext } from '@kbn/data-plugin/server';
import type { UsageCounter } from '@kbn/usage-collection-plugin/server';
import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '../common/constants';
import { PLUGIN_ID } from '../common';
import { isActiveLicense } from './lib/license';
import {
@ -24,6 +22,7 @@ import {
import { defineLogRateAnalysisRoute } from './routes';
import { defineLogCategorizationRoutes } from './routes/log_categorization';
import { registerCasesPersistableState } from './register_cases';
export class AiopsPlugin
implements Plugin<AiopsPluginSetup, AiopsPluginStart, AiopsPluginSetupDeps, AiopsPluginStartDeps>
@ -49,6 +48,10 @@ export class AiopsPlugin
const aiopsLicense: AiopsLicense = { isActivePlatinumLicense: false };
this.licenseSubscription = plugins.licensing.license$.subscribe(async (license) => {
aiopsLicense.isActivePlatinumLicense = isActiveLicense('platinum', license);
if (aiopsLicense.isActivePlatinumLicense) {
registerCasesPersistableState(plugins.cases, this.logger);
}
});
const router = core.http.createRouter<DataRequestHandlerContext>();
@ -59,12 +62,6 @@ export class AiopsPlugin
defineLogCategorizationRoutes(router, aiopsLicense, this.usageCounter);
});
if (plugins.cases) {
plugins.cases.attachmentFramework.registerPersistableState({
id: CASES_ATTACHMENT_CHANGE_POINT_CHART,
});
}
return {};
}

View file

@ -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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { Logger } from '@kbn/core/server';
import type { CasesSetup } from '@kbn/cases-plugin/server';
import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '../common/constants';
export function registerCasesPersistableState(cases: CasesSetup | undefined, logger: Logger) {
if (cases) {
try {
cases.attachmentFramework.registerPersistableState({
id: CASES_ATTACHMENT_CHANGE_POINT_CHART,
});
} catch (error) {
logger.warn(
`AIOPs failed to register cases persistable state for ${CASES_ATTACHMENT_CHANGE_POINT_CHART}`
);
}
}
}

View file

@ -6,13 +6,13 @@
*/
import type { PluginSetup, PluginStart } from '@kbn/data-plugin/server';
import type { LicensingPluginStart } from '@kbn/licensing-plugin/server';
import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server';
import type { CasesSetup } from '@kbn/cases-plugin/server';
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
export interface AiopsPluginSetupDeps {
data: PluginSetup;
licensing: LicensingPluginStart;
licensing: LicensingPluginSetup;
cases?: CasesSetup;
usageCollection?: UsageCollectionSetup;
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import type { Logger } from '@kbn/core/server';
import type { CasesSetup } from '@kbn/cases-plugin/server';
import type { MlFeatures } from '../../common/constants/app';
import {
@ -12,14 +13,29 @@ import {
CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE,
} from '../../common/constants/cases';
export function registerCasesPersistableState(cases: CasesSetup, enabledFeatures: MlFeatures) {
export function registerCasesPersistableState(
cases: CasesSetup,
enabledFeatures: MlFeatures,
logger: Logger
) {
if (enabledFeatures.ad === true) {
cases.attachmentFramework.registerPersistableState({
id: CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE,
});
cases.attachmentFramework.registerPersistableState({
id: CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS,
});
try {
cases.attachmentFramework.registerPersistableState({
id: CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE,
});
} catch (error) {
logger.warn(
`ML failed to register cases persistable state for ${CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE}`
);
}
try {
cases.attachmentFramework.registerPersistableState({
id: CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS,
});
} catch (error) {
logger.warn(
`ML failed to register cases persistable state for ${CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS}`
);
}
}
}

View file

@ -5,13 +5,15 @@
* 2.0.
*/
import type { Logger } from '@kbn/core/server';
import { i18n } from '@kbn/i18n';
import type { HomeServerPluginSetup } from '@kbn/home-plugin/server';
import type { MlFeatures } from '../../common/constants/app';
export function registerSampleDataSetLinks(
home: HomeServerPluginSetup,
enabledFeatures: MlFeatures
enabledFeatures: MlFeatures,
logger: Logger
) {
if (enabledFeatures.ad === true) {
const sampleDataLinkLabel = i18n.translate('xpack.ml.sampleDataLinkLabel', {
@ -21,28 +23,36 @@ export function registerSampleDataSetLinks(
const getCreateJobPath = (jobId: string, dataViewId: string) =>
`/app/ml/modules/check_view_or_create?id=${jobId}&index=${dataViewId}`;
addAppLinksToSampleDataset('ecommerce', [
{
sampleObject: {
type: 'index-pattern',
id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f',
try {
addAppLinksToSampleDataset('ecommerce', [
{
sampleObject: {
type: 'index-pattern',
id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f',
},
getPath: (objectId) => getCreateJobPath('sample_data_ecommerce', objectId),
label: sampleDataLinkLabel,
icon: 'machineLearningApp',
},
getPath: (objectId) => getCreateJobPath('sample_data_ecommerce', objectId),
label: sampleDataLinkLabel,
icon: 'machineLearningApp',
},
]);
]);
} catch (error) {
logger.warn(`ML failed to register sample data links for sample_data_ecommerce`);
}
addAppLinksToSampleDataset('logs', [
{
sampleObject: {
type: 'index-pattern',
id: '90943e30-9a47-11e8-b64d-95841ca0b247',
try {
addAppLinksToSampleDataset('logs', [
{
sampleObject: {
type: 'index-pattern',
id: '90943e30-9a47-11e8-b64d-95841ca0b247',
},
getPath: (objectId) => getCreateJobPath('sample_data_weblogs', objectId),
label: sampleDataLinkLabel,
icon: 'machineLearningApp',
},
getPath: (objectId) => getCreateJobPath('sample_data_weblogs', objectId),
label: sampleDataLinkLabel,
icon: 'machineLearningApp',
},
]);
]);
} catch (error) {
logger.warn(`ML failed to register sample data links for sample_data_weblogs`);
}
}
}

View file

@ -313,10 +313,10 @@ export class MlServerPlugin
if (mlLicense.isMlEnabled() && mlLicense.isFullLicense()) {
if (this.cases) {
registerCasesPersistableState(this.cases, this.enabledFeatures);
registerCasesPersistableState(this.cases, this.enabledFeatures, this.log);
}
if (this.home) {
registerSampleDataSetLinks(this.home, this.enabledFeatures);
registerSampleDataSetLinks(this.home, this.enabledFeatures, this.log);
}
}
// check whether the job saved objects exist

View file

@ -35,7 +35,6 @@ export default ({ getService }: FtrProviderContext): void => {
expect(types).to.eql({
'.lens': '78559fd806809ac3a1008942ead2a079864054f5',
'.test': 'ab2204830c67f5cf992c9aa2f7e3ead752cc60a1',
aiopsChangePointChart: 'a1212d71947ec34487b374cecc47ab9941b5d91c',
});
});
});