kibana/x-pack/plugins/ml/server/plugin.ts
Kibana Machine 485960af24
[8.12] [RAM] Stack management rules available with only ml feature (#174791) (#174940)
# Backport

This will backport the following commits from `main` to `8.12`:
- [[RAM] Stack management rules available with only ml feature
(#174791)](https://github.com/elastic/kibana/pull/174791)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Xavier
Mouligneau","email":"xavier.mouligneau@elastic.co"},"sourceCommit":{"committedDate":"2024-01-16T16:13:02Z","message":"[RAM]
Stack management rules available with only ml feature (#174791)\n\n##
Summary\r\n\r\nFix =>
https://github.com/elastic/kibana/issues/173573","sha":"5d5f0d10739647ea7a963327c72dcda5b845ade1","branchLabelMapping":{"^v8.13.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:ResponseOps","Team:ML","v8.12.1","v8.13.0"],"title":"[RAM]
Stack management rules available with only ml
feature","number":174791,"url":"https://github.com/elastic/kibana/pull/174791","mergeCommit":{"message":"[RAM]
Stack management rules available with only ml feature (#174791)\n\n##
Summary\r\n\r\nFix =>
https://github.com/elastic/kibana/issues/173573","sha":"5d5f0d10739647ea7a963327c72dcda5b845ade1"}},"sourceBranch":"main","suggestedTargetBranches":["8.12"],"targetPullRequestStates":[{"branch":"8.12","label":"v8.12.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.13.0","branchLabelMappingKey":"^v8.13.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/174791","number":174791,"mergeCommit":{"message":"[RAM]
Stack management rules available with only ml feature (#174791)\n\n##
Summary\r\n\r\nFix =>
https://github.com/elastic/kibana/issues/173573","sha":"5d5f0d10739647ea7a963327c72dcda5b845ade1"}}]}]
BACKPORT-->

Co-authored-by: Xavier Mouligneau <xavier.mouligneau@elastic.co>
2024-01-16 12:01:09 -07:00

348 lines
12 KiB
TypeScript

/*
* 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 { i18n } from '@kbn/i18n';
import type {
CoreSetup,
CoreStart,
Plugin,
KibanaRequest,
Logger,
PluginInitializerContext,
CapabilitiesStart,
IClusterClient,
SavedObjectsServiceStart,
UiSettingsServiceStart,
} from '@kbn/core/server';
import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server';
import type { SecurityPluginSetup } from '@kbn/security-plugin/server';
import type { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/server';
import type { SpacesPluginSetup } from '@kbn/spaces-plugin/server';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/server';
import type { HomeServerPluginSetup } from '@kbn/home-plugin/server';
import type { CasesSetup } from '@kbn/cases-plugin/server';
import type { PluginsSetup, PluginsStart, RouteInitialization } from './types';
import type { MlCapabilities } from '../common/types/capabilities';
import { jsonSchemaRoutes } from './routes/json_schema';
import { notificationsRoutes } from './routes/notifications';
import {
type MlFeatures,
PLUGIN_ID,
type ConfigSchema,
initEnabledFeatures,
type CompatibleModule,
} from '../common/constants/app';
import { initMlServerLog } from './lib/log';
import { annotationRoutes } from './routes/annotations';
import { calendars } from './routes/calendars';
import { dataFeedRoutes } from './routes/datafeeds';
import { dataFrameAnalyticsRoutes } from './routes/data_frame_analytics';
import { dataRecognizer } from './routes/modules';
import { dataVisualizerRoutes } from './routes/data_visualizer';
import { fieldsService } from './routes/fields_service';
import { filtersRoutes } from './routes/filters';
import { indicesRoutes } from './routes/indices';
import { jobAuditMessagesRoutes } from './routes/job_audit_messages';
import { jobRoutes } from './routes/anomaly_detectors';
import { jobServiceRoutes } from './routes/job_service';
import { savedObjectsRoutes } from './routes/saved_objects';
import { jobValidationRoutes } from './routes/job_validation';
import { resultsServiceRoutes } from './routes/results_service';
import { modelManagementRoutes } from './routes/model_management';
import { systemRoutes } from './routes/system';
import { MlLicense } from '../common/license';
import { createSharedServices, SharedServices } from './shared_services';
import { getPluginPrivileges } from '../common/types/capabilities';
import { setupCapabilitiesSwitcher } from './lib/capabilities';
import { registerKibanaSettings } from './lib/register_settings';
import { trainedModelsRoutes } from './routes/trained_models';
import { managementRoutes } from './routes/management';
import {
setupSavedObjects,
jobSavedObjectsInitializationFactory,
savedObjectClientsFactory,
} from './saved_objects';
import { RouteGuard } from './lib/route_guard';
import { registerMlAlerts } from './lib/alerts/register_ml_alerts';
import { ML_ALERT_TYPES } from '../common/constants/alerts';
import { alertingRoutes } from './routes/alerting';
import { registerCollector } from './usage';
import { SavedObjectsSyncService } from './saved_objects/sync_task';
import { registerCasesPersistableState } from './lib/register_cases';
import { registerSampleDataSetLinks } from './lib/register_sample_data_set_links';
export type MlPluginSetup = SharedServices;
export type MlPluginStart = void;
export class MlServerPlugin
implements Plugin<MlPluginSetup, MlPluginStart, PluginsSetup, PluginsStart>
{
private log: Logger;
private mlLicense: MlLicense;
private capabilities: CapabilitiesStart | null = null;
private clusterClient: IClusterClient | null = null;
private fieldsFormat: FieldFormatsStart | null = null;
private uiSettings: UiSettingsServiceStart | null = null;
private savedObjectsStart: SavedObjectsServiceStart | null = null;
private spacesPlugin: SpacesPluginSetup | undefined;
private security: SecurityPluginSetup | undefined;
private home: HomeServerPluginSetup | null = null;
private cases: CasesSetup | null | undefined = null;
private dataViews: DataViewsPluginStart | null = null;
private isMlReady: Promise<void>;
private setMlReady: () => void = () => {};
private savedObjectsSyncService: SavedObjectsSyncService;
private enabledFeatures: MlFeatures = {
ad: true,
dfa: true,
nlp: true,
};
private compatibleModuleType: CompatibleModule | null = null;
constructor(ctx: PluginInitializerContext<ConfigSchema>) {
this.log = ctx.logger.get();
this.mlLicense = new MlLicense();
this.isMlReady = new Promise((resolve) => (this.setMlReady = resolve));
this.savedObjectsSyncService = new SavedObjectsSyncService(this.log);
const config = ctx.config.get();
initEnabledFeatures(this.enabledFeatures, config);
this.compatibleModuleType = config.compatibleModuleType ?? null;
this.enabledFeatures = Object.freeze(this.enabledFeatures);
}
public setup(coreSetup: CoreSetup<PluginsStart>, plugins: PluginsSetup): MlPluginSetup {
this.spacesPlugin = plugins.spaces;
this.security = plugins.security;
this.home = plugins.home;
this.cases = plugins.cases;
const { admin, user, apmUser } = getPluginPrivileges();
plugins.features.registerKibanaFeature({
id: PLUGIN_ID,
name: i18n.translate('xpack.ml.featureRegistry.mlFeatureName', {
defaultMessage: 'Machine Learning',
}),
order: 500,
category: DEFAULT_APP_CATEGORIES.kibana,
app: [PLUGIN_ID, 'kibana'],
catalogue: [PLUGIN_ID, `${PLUGIN_ID}_file_data_visualizer`],
management: {
insightsAndAlerting: ['jobsListLink', 'triggersActions'],
},
alerting: Object.values(ML_ALERT_TYPES),
privileges: {
all: admin,
read: user,
},
reserved: {
description: i18n.translate('xpack.ml.feature.reserved.description', {
defaultMessage:
'To grant users access, you should also assign either the machine_learning_user or machine_learning_admin role.',
}),
privileges: [
{
id: 'ml_user',
privilege: user,
},
{
id: 'ml_admin',
privilege: admin,
},
{
id: 'ml_apm_user',
privilege: apmUser,
},
],
},
});
// initialize capabilities switcher to add license filter to ml capabilities
setupCapabilitiesSwitcher(
coreSetup,
plugins.licensing.license$,
this.enabledFeatures,
this.log
);
setupSavedObjects(coreSetup.savedObjects);
this.savedObjectsSyncService.registerSyncTask(
plugins.taskManager,
plugins.security,
this.spacesPlugin !== undefined,
() => this.isMlReady
);
const { getInternalSavedObjectsClient, getMlSavedObjectsClient } = savedObjectClientsFactory(
() => this.savedObjectsStart
);
const getSpaces = plugins.spaces
? () => coreSetup.getStartServices().then(([, { spaces }]) => spaces!)
: undefined;
const getDataViews = () => {
if (this.dataViews === null) {
throw Error('Data views plugin not initialized');
}
return this.dataViews;
};
const resolveMlCapabilities = async (request: KibanaRequest) => {
if (this.capabilities === null) {
return null;
}
const capabilities = await this.capabilities.resolveCapabilities(request, {
capabilityPath: 'ml.*',
});
return capabilities.ml as MlCapabilities;
};
const { internalServicesProviders, sharedServicesProviders } = createSharedServices(
this.mlLicense,
getSpaces,
plugins.cloud,
plugins.security?.authz,
resolveMlCapabilities,
() => this.clusterClient,
() => getInternalSavedObjectsClient(),
() => this.uiSettings,
() => this.fieldsFormat,
getDataViews,
() => this.isMlReady,
this.compatibleModuleType
);
const routeInit: RouteInitialization = {
router: coreSetup.http.createRouter(),
routeGuard: new RouteGuard(
this.mlLicense,
getMlSavedObjectsClient,
getInternalSavedObjectsClient,
plugins.spaces,
plugins.security?.authz,
() => this.isMlReady,
() => this.dataViews,
coreSetup.getStartServices
),
mlLicense: this.mlLicense,
getEnabledFeatures: () => this.enabledFeatures,
};
// Register Anomaly Detection routes
if (this.enabledFeatures.ad) {
annotationRoutes(routeInit, plugins.security);
calendars(routeInit);
dataFeedRoutes(routeInit);
dataRecognizer(routeInit, this.compatibleModuleType);
filtersRoutes(routeInit);
jobAuditMessagesRoutes(routeInit);
jobRoutes(routeInit);
jobServiceRoutes(routeInit);
resultsServiceRoutes(routeInit);
jobValidationRoutes(routeInit);
}
// Register Data Frame Analytics routes
if (this.enabledFeatures.dfa) {
dataFrameAnalyticsRoutes(routeInit, plugins.cloud);
}
// Register Trained Model Management routes
if (this.enabledFeatures.dfa || this.enabledFeatures.nlp) {
trainedModelsRoutes(routeInit, plugins.cloud);
}
// Register Miscellaneous routes
modelManagementRoutes(routeInit);
dataVisualizerRoutes(routeInit);
fieldsService(routeInit);
indicesRoutes(routeInit);
managementRoutes(routeInit);
savedObjectsRoutes(routeInit, {
getSpaces,
resolveMlCapabilities,
});
systemRoutes(routeInit, {
getSpaces,
cloud: plugins.cloud,
resolveMlCapabilities,
});
notificationsRoutes(routeInit);
jsonSchemaRoutes(routeInit);
alertingRoutes(routeInit, sharedServicesProviders);
initMlServerLog({ log: this.log });
if (plugins.alerting) {
registerMlAlerts(
{
alerting: plugins.alerting,
logger: this.log,
mlSharedServices: sharedServicesProviders,
mlServicesProviders: internalServicesProviders,
},
this.enabledFeatures
);
}
registerKibanaSettings(coreSetup);
if (plugins.usageCollection) {
const getIndexForType = (type: string) =>
coreSetup
.getStartServices()
.then(([coreStart]) => coreStart.savedObjects.getIndexForType(type));
registerCollector(plugins.usageCollection, getIndexForType);
}
return { ...sharedServicesProviders };
}
public start(coreStart: CoreStart, plugins: PluginsStart): MlPluginStart {
this.uiSettings = coreStart.uiSettings;
this.fieldsFormat = plugins.fieldFormats;
this.capabilities = coreStart.capabilities;
this.clusterClient = coreStart.elasticsearch.client;
this.savedObjectsStart = coreStart.savedObjects;
this.dataViews = plugins.dataViews;
this.mlLicense.setup(plugins.licensing.license$, async (mlLicense: MlLicense) => {
if (mlLicense.isMlEnabled() === false || mlLicense.isFullLicense() === false) {
try {
await this.savedObjectsSyncService.unscheduleSyncTask(plugins.taskManager);
} catch (e) {
this.log.debug(`Error unscheduling saved objects sync task`, e);
}
return;
}
if (mlLicense.isMlEnabled() && mlLicense.isFullLicense()) {
if (this.cases) {
registerCasesPersistableState(this.cases, this.enabledFeatures, this.log);
}
if (this.home) {
registerSampleDataSetLinks(this.home, this.enabledFeatures, this.log);
}
}
// check whether the job saved objects exist
// and create them if needed.
const { initializeJobs } = jobSavedObjectsInitializationFactory(
coreStart,
this.security,
this.spacesPlugin !== undefined
);
initializeJobs().finally(() => {
this.setMlReady();
});
this.savedObjectsSyncService.scheduleSyncTask(plugins.taskManager, coreStart);
});
}
public stop() {
this.mlLicense.unsubscribe();
}
}