Skip to content

Commit

Permalink
[ML] Disabling ML if license feature is disabled (elastic#73187)
Browse files Browse the repository at this point in the history
* [ML] Disabling ML if license feature is disabled

* disabling UI feature

* removing unused import

* small refactor

* disabling ml using plugin updater

* function rename

* update comment

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
jgowdyelastic and elasticmachine committed Jul 29, 2020
1 parent 1b4d4d8 commit 10cbaf5
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 45 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/ml/common/license/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export {
MINIMUM_LICENSE,
isFullLicense,
isMinimumLicense,
isMlEnabled,
} from './ml_license';
4 changes: 4 additions & 0 deletions x-pack/plugins/ml/common/license/ml_license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,7 @@ export function isFullLicense(license: ILicense) {
export function isMinimumLicense(license: ILicense) {
return license.check(PLUGIN_ID, MINIMUM_LICENSE).state === 'valid';
}

export function isMlEnabled(license: ILicense) {
return license.getFeature(PLUGIN_ID).isEnabled;
}
43 changes: 17 additions & 26 deletions x-pack/plugins/ml/public/application/management/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,28 @@
*/

import { i18n } from '@kbn/i18n';
import { take } from 'rxjs/operators';

import { CoreSetup } from 'kibana/public';
import { MlStartDependencies, MlSetupDependencies } from '../../plugin';
import { ManagementSetup } from 'src/plugins/management/public';
import { MlStartDependencies } from '../../plugin';

import { ManagementAppMountParams } from '../../../../../../src/plugins/management/public';
import { PLUGIN_ID } from '../../../common/constants/app';
import { MINIMUM_FULL_LICENSE } from '../../../common/license';

export function initManagementSection(
pluginsSetup: MlSetupDependencies,
export function registerManagementSection(
management: ManagementSetup | undefined,
core: CoreSetup<MlStartDependencies>
) {
const licensing = pluginsSetup.licensing.license$.pipe(take(1));
licensing.subscribe((license) => {
const management = pluginsSetup.management;
if (
management !== undefined &&
license.check(PLUGIN_ID, MINIMUM_FULL_LICENSE).state === 'valid'
) {
management.sections.section.insightsAndAlerting.registerApp({
id: 'jobsListLink',
title: i18n.translate('xpack.ml.management.jobsListTitle', {
defaultMessage: 'Machine Learning Jobs',
}),
order: 2,
async mount(params: ManagementAppMountParams) {
const { mountApp } = await import('./jobs_list');
return mountApp(core, params);
},
});
}
});
if (management !== undefined) {
management.sections.section.insightsAndAlerting.registerApp({
id: 'jobsListLink',
title: i18n.translate('xpack.ml.management.jobsListTitle', {
defaultMessage: 'Machine Learning Jobs',
}),
order: 2,
async mount(params: ManagementAppMountParams) {
const { mountApp } = await import('./jobs_list');
return mountApp(core, params);
},
});
}
}
43 changes: 28 additions & 15 deletions x-pack/plugins/ml/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ import {
AppMountParameters,
PluginInitializerContext,
} from 'kibana/public';
import { BehaviorSubject } from 'rxjs';
import { take } from 'rxjs/operators';
import { ManagementSetup } from 'src/plugins/management/public';
import { SharePluginSetup, SharePluginStart, UrlGeneratorState } from 'src/plugins/share/public';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';

import { DataPublicPluginStart } from 'src/plugins/data/public';
import { HomePublicPluginSetup } from 'src/plugins/home/public';
import { EmbeddableSetup } from 'src/plugins/embeddable/public';
import { AppStatus, AppUpdater } from '../../../../src/core/public';
import { SecurityPluginSetup } from '../../security/public';
import { LicensingPluginSetup } from '../../licensing/public';
import { initManagementSection } from './application/management';
import { registerManagementSection } from './application/management';
import { LicenseManagementUIPluginSetup } from '../../license_management/public';
import { setDependencyCache } from './application/util/dependency_cache';
import { PLUGIN_ID, PLUGIN_ICON } from '../common/constants/app';
Expand All @@ -31,7 +34,8 @@ import { registerEmbeddables } from './embeddables';
import { UiActionsSetup, UiActionsStart } from '../../../../src/plugins/ui_actions/public';
import { registerMlUiActions } from './ui_actions';
import { KibanaLegacyStart } from '../../../../src/plugins/kibana_legacy/public';
import { MlUrlGenerator, MlUrlGeneratorState, ML_APP_URL_GENERATOR } from './url_generator';
import { registerUrlGenerator, MlUrlGeneratorState, ML_APP_URL_GENERATOR } from './url_generator';
import { isMlEnabled, isFullLicense } from '../common/license';

export interface MlStartDependencies {
data: DataPublicPluginStart;
Expand Down Expand Up @@ -61,18 +65,11 @@ declare module '../../../../src/plugins/share/public' {
export type MlCoreSetup = CoreSetup<MlStartDependencies, MlPluginStart>;

export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
private appUpdater = new BehaviorSubject<AppUpdater>(() => ({}));

constructor(private initializerContext: PluginInitializerContext) {}

setup(core: MlCoreSetup, pluginsSetup: MlSetupDependencies) {
const baseUrl = core.http.basePath.prepend('/app/ml');

pluginsSetup.share.urlGenerators.registerUrlGenerator(
new MlUrlGenerator({
appBasePath: baseUrl,
useHash: core.uiSettings.get('state:storeInSessionStorage'),
})
);

core.application.register({
id: PLUGIN_ID,
title: i18n.translate('xpack.ml.plugin.title', {
Expand All @@ -82,6 +79,7 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
euiIconType: PLUGIN_ICON,
appRoute: '/app/ml',
category: DEFAULT_APP_CATEGORIES.kibana,
updater$: this.appUpdater,
mount: async (params: AppMountParameters) => {
const [coreStart, pluginsStart] = await core.getStartServices();
const kibanaVersion = this.initializerContext.env.packageInfo.version;
Expand Down Expand Up @@ -112,11 +110,26 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
},
});

registerFeature(pluginsSetup.home);
const licensing = pluginsSetup.licensing.license$.pipe(take(1));
licensing.subscribe((license) => {
if (isMlEnabled(license)) {
// add ML to home page
registerFeature(pluginsSetup.home);

initManagementSection(pluginsSetup, core);
registerEmbeddables(pluginsSetup.embeddable, core);
registerMlUiActions(pluginsSetup.uiActions, core);
// register various ML plugin features which require a full license
if (isFullLicense(license)) {
registerManagementSection(pluginsSetup.management, core);
registerEmbeddables(pluginsSetup.embeddable, core);
registerMlUiActions(pluginsSetup.uiActions, core);
registerUrlGenerator(pluginsSetup.share, core);
}
} else {
// if ml is disabled in elasticsearch, disable ML in kibana
this.appUpdater.next(() => ({
status: AppStatus.inaccessible,
}));
}
});

return {};
}
Expand Down
20 changes: 19 additions & 1 deletion x-pack/plugins/ml/public/url_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { UrlGeneratorsDefinition } from '../../../../src/plugins/share/public';
import { CoreSetup } from 'kibana/public';
import { SharePluginSetup, UrlGeneratorsDefinition } from '../../../../src/plugins/share/public';
import { TimeRange } from '../../../../src/plugins/data/public';
import { setStateToKbnUrl } from '../../../../src/plugins/kibana_utils/public';
import { JobId } from '../../reporting/common/types';
import { ExplorerAppState } from './application/explorer/explorer_dashboard_service';
import { MlStartDependencies } from './plugin';

export const ML_APP_URL_GENERATOR = 'ML_APP_URL_GENERATOR';

Expand Down Expand Up @@ -88,3 +90,19 @@ export class MlUrlGenerator implements UrlGeneratorsDefinition<typeof ML_APP_URL
return url;
}
}

/**
* Registers the URL generator
*/
export function registerUrlGenerator(
share: SharePluginSetup,
core: CoreSetup<MlStartDependencies>
) {
const baseUrl = core.http.basePath.prepend('/app/ml');
share.urlGenerators.registerUrlGenerator(
new MlUrlGenerator({
appBasePath: baseUrl,
useHash: core.uiSettings.get('state:storeInSessionStorage'),
})
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';
import { CapabilitiesSwitcher, CoreSetup, Logger } from 'src/core/server';
import { ILicense } from '../../../../licensing/common/types';
import { isFullLicense, isMinimumLicense } from '../../../common/license';
import { isFullLicense, isMinimumLicense, isMlEnabled } from '../../../common/license';
import { MlCapabilities, basicLicenseMlCapabilities } from '../../../common/types/capabilities';

export const setupCapabilitiesSwitcher = (
Expand All @@ -30,9 +30,10 @@ function getSwitcher(license$: Observable<ILicense>, logger: Logger): Capabiliti

try {
const license = await license$.pipe(take(1)).toPromise();
const mlEnabled = isMlEnabled(license);

// full license, leave capabilities as they were
if (isFullLicense(license)) {
if (mlEnabled && isFullLicense(license)) {
return capabilities;
}

Expand All @@ -45,7 +46,7 @@ function getSwitcher(license$: Observable<ILicense>, logger: Logger): Capabiliti
});

// for a basic license, reapply the original capabilities for the basic license features
if (isMinimumLicense(license)) {
if (mlEnabled && isMinimumLicense(license)) {
basicLicenseMlCapabilities.forEach((c) => (mlCaps[c] = originalCapabilities[c]));
}

Expand Down

0 comments on commit 10cbaf5

Please sign in to comment.