[ML] Moving to kibana capabilities (#64057)
* [ML] Moving to kibana capabilities * fixing types * renaming privilges * renaming privileges to capabilities * renaming resolvers * correcting admin capabilities * fixing includes * removing any types * renaming type * readding spaces * adding capabilities switcher * updating comment * removing unnecessary failing tests * adding error to log
This commit is contained in:
parent
6bb751540b
commit
b3c7002799
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { createAction } from 'redux-actions';
|
||||
import { createAsyncAction } from './utils';
|
||||
import { PrivilegesResponse } from '../../../../../../plugins/ml/common/types/privileges';
|
||||
import { MlCapabilitiesResponse } from '../../../../../../plugins/ml/common/types/capabilities';
|
||||
import { AnomaliesTableRecord } from '../../../../../../plugins/ml/common/types/anomalies';
|
||||
import {
|
||||
CreateMLJobSuccess,
|
||||
|
@ -27,7 +27,7 @@ export const createMLJobAction = createAsyncAction<
|
|||
CreateMLJobSuccess | null
|
||||
>('CREATE_ML_JOB');
|
||||
|
||||
export const getMLCapabilitiesAction = createAsyncAction<any, PrivilegesResponse>(
|
||||
export const getMLCapabilitiesAction = createAsyncAction<any, MlCapabilitiesResponse>(
|
||||
'GET_ML_CAPABILITIES'
|
||||
);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import moment from 'moment';
|
|||
import { apiService } from './utils';
|
||||
import { AnomalyRecords, AnomalyRecordsParams } from '../actions';
|
||||
import { API_URLS, ML_JOB_ID, ML_MODULE_ID } from '../../../common/constants';
|
||||
import { PrivilegesResponse } from '../../../../../../plugins/ml/common/types/privileges';
|
||||
import { MlCapabilitiesResponse } from '../../../../../../plugins/ml/common/types/capabilities';
|
||||
import {
|
||||
CreateMLJobSuccess,
|
||||
DeleteJobResults,
|
||||
|
@ -20,7 +20,7 @@ import { JobExistResult } from '../../../../../../plugins/ml/common/types/data_r
|
|||
|
||||
export const getMLJobId = (monitorId: string) => `${monitorId}_${ML_JOB_ID}`.toLowerCase();
|
||||
|
||||
export const getMLCapabilities = async (): Promise<PrivilegesResponse> => {
|
||||
export const getMLCapabilities = async (): Promise<MlCapabilitiesResponse> => {
|
||||
return await apiService.get(API_URLS.ML_CAPABILITIES);
|
||||
};
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
import { getAsyncInitialState, handleAsyncAction } from './utils';
|
||||
import { IHttpFetchError } from '../../../../../../../target/types/core/public/http';
|
||||
import { AsyncInitialState } from './types';
|
||||
import { PrivilegesResponse } from '../../../../../../plugins/ml/common/types/privileges';
|
||||
import { MlCapabilitiesResponse } from '../../../../../../plugins/ml/common/types/capabilities';
|
||||
import { CreateMLJobSuccess, DeleteJobResults } from '../actions/types';
|
||||
import { JobExistResult } from '../../../../../../plugins/ml/common/types/data_recognizer';
|
||||
|
||||
|
@ -26,7 +26,7 @@ export interface MLJobState {
|
|||
createJob: AsyncInitialState<CreateMLJobSuccess>;
|
||||
deleteJob: AsyncInitialState<DeleteJobResults>;
|
||||
anomalies: AsyncInitialState<AnomalyRecords>;
|
||||
mlCapabilities: AsyncInitialState<PrivilegesResponse>;
|
||||
mlCapabilities: AsyncInitialState<MlCapabilitiesResponse>;
|
||||
}
|
||||
|
||||
const initialState: MLJobState = {
|
||||
|
|
|
@ -4,4 +4,11 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { MlLicense, LicenseStatus, MINIMUM_FULL_LICENSE, MINIMUM_LICENSE } from './ml_license';
|
||||
export {
|
||||
MlLicense,
|
||||
LicenseStatus,
|
||||
MINIMUM_FULL_LICENSE,
|
||||
MINIMUM_LICENSE,
|
||||
isFullLicense,
|
||||
isMinimumLicense,
|
||||
} from './ml_license';
|
||||
|
|
|
@ -38,8 +38,8 @@ export class MlLicense {
|
|||
this._isSecurityEnabled = securityIsEnabled;
|
||||
this._hasLicenseExpired = this._license.status === 'expired';
|
||||
this._isMlEnabled = this._license.getFeature(PLUGIN_ID).isEnabled;
|
||||
this._isMinimumLicense = this._license.check(PLUGIN_ID, MINIMUM_LICENSE).state === 'valid';
|
||||
this._isFullLicense = this._license.check(PLUGIN_ID, MINIMUM_FULL_LICENSE).state === 'valid';
|
||||
this._isMinimumLicense = isMinimumLicense(this._license);
|
||||
this._isFullLicense = isFullLicense(this._license);
|
||||
|
||||
if (this._initialized === false && postInitFunctions !== undefined) {
|
||||
postInitFunctions.forEach(f => f(this));
|
||||
|
@ -74,3 +74,11 @@ export class MlLicense {
|
|||
return this._isFullLicense;
|
||||
}
|
||||
}
|
||||
|
||||
export function isFullLicense(license: ILicense) {
|
||||
return license.check(PLUGIN_ID, MINIMUM_FULL_LICENSE).state === 'valid';
|
||||
}
|
||||
|
||||
export function isMinimumLicense(license: ILicense) {
|
||||
return license.check(PLUGIN_ID, MINIMUM_LICENSE).state === 'valid';
|
||||
}
|
||||
|
|
66
x-pack/plugins/ml/common/types/capabilities.ts
Normal file
66
x-pack/plugins/ml/common/types/capabilities.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { KibanaRequest } from 'kibana/server';
|
||||
|
||||
export const userMlCapabilities = {
|
||||
// Anomaly Detection
|
||||
canGetJobs: false,
|
||||
canGetDatafeeds: false,
|
||||
// Calendars
|
||||
canGetCalendars: false,
|
||||
// File Data Visualizer
|
||||
canFindFileStructure: false,
|
||||
// Filters
|
||||
canGetFilters: false,
|
||||
// Data Frame Analytics
|
||||
canGetDataFrameAnalytics: false,
|
||||
};
|
||||
|
||||
export const adminMlCapabilities = {
|
||||
// Anomaly Detection
|
||||
canCreateJob: false,
|
||||
canDeleteJob: false,
|
||||
canOpenJob: false,
|
||||
canCloseJob: false,
|
||||
canForecastJob: false,
|
||||
canStartStopDatafeed: false,
|
||||
canUpdateJob: false,
|
||||
canUpdateDatafeed: false,
|
||||
canPreviewDatafeed: false,
|
||||
// Calendars
|
||||
canCreateCalendar: false,
|
||||
canDeleteCalendar: false,
|
||||
// Filters
|
||||
canCreateFilter: false,
|
||||
canDeleteFilter: false,
|
||||
// Data Frame Analytics
|
||||
canDeleteDataFrameAnalytics: false,
|
||||
canCreateDataFrameAnalytics: false,
|
||||
canStartStopDataFrameAnalytics: false,
|
||||
};
|
||||
|
||||
export type UserMlCapabilities = typeof userMlCapabilities;
|
||||
export type AdminMlCapabilities = typeof adminMlCapabilities;
|
||||
export type MlCapabilities = UserMlCapabilities & AdminMlCapabilities;
|
||||
|
||||
export const basicLicenseMlCapabilities = ['canFindFileStructure'] as Array<keyof MlCapabilities>;
|
||||
|
||||
export function getDefaultCapabilities(): MlCapabilities {
|
||||
return {
|
||||
...userMlCapabilities,
|
||||
...adminMlCapabilities,
|
||||
};
|
||||
}
|
||||
|
||||
export interface MlCapabilitiesResponse {
|
||||
capabilities: MlCapabilities;
|
||||
upgradeInProgress: boolean;
|
||||
isPlatinumOrTrialLicense: boolean;
|
||||
mlFeatureEnabledInSpace: boolean;
|
||||
}
|
||||
|
||||
export type ResolveMlCapabilities = (request: KibanaRequest) => Promise<MlCapabilities | null>;
|
|
@ -1,75 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
//
|
||||
|
||||
export interface Privileges {
|
||||
// Anomaly Detection
|
||||
canGetJobs: boolean;
|
||||
canCreateJob: boolean;
|
||||
canDeleteJob: boolean;
|
||||
canOpenJob: boolean;
|
||||
canCloseJob: boolean;
|
||||
canForecastJob: boolean;
|
||||
canGetDatafeeds: boolean;
|
||||
canStartStopDatafeed: boolean;
|
||||
canUpdateJob: boolean;
|
||||
canUpdateDatafeed: boolean;
|
||||
canPreviewDatafeed: boolean;
|
||||
// Calendars
|
||||
canGetCalendars: boolean;
|
||||
canCreateCalendar: boolean;
|
||||
canDeleteCalendar: boolean;
|
||||
// Filters
|
||||
canGetFilters: boolean;
|
||||
canCreateFilter: boolean;
|
||||
canDeleteFilter: boolean;
|
||||
// File Data Visualizer
|
||||
canFindFileStructure: boolean;
|
||||
// Data Frame Analytics
|
||||
canGetDataFrameAnalytics: boolean;
|
||||
canDeleteDataFrameAnalytics: boolean;
|
||||
canCreateDataFrameAnalytics: boolean;
|
||||
canStartStopDataFrameAnalytics: boolean;
|
||||
}
|
||||
|
||||
export function getDefaultPrivileges(): Privileges {
|
||||
return {
|
||||
// Anomaly Detection
|
||||
canGetJobs: false,
|
||||
canCreateJob: false,
|
||||
canDeleteJob: false,
|
||||
canOpenJob: false,
|
||||
canCloseJob: false,
|
||||
canForecastJob: false,
|
||||
canGetDatafeeds: false,
|
||||
canStartStopDatafeed: false,
|
||||
canUpdateJob: false,
|
||||
canUpdateDatafeed: false,
|
||||
canPreviewDatafeed: false,
|
||||
// Calendars
|
||||
canGetCalendars: false,
|
||||
canCreateCalendar: false,
|
||||
canDeleteCalendar: false,
|
||||
// Filters
|
||||
canGetFilters: false,
|
||||
canCreateFilter: false,
|
||||
canDeleteFilter: false,
|
||||
// File Data Visualizer
|
||||
canFindFileStructure: false,
|
||||
// Data Frame Analytics
|
||||
canGetDataFrameAnalytics: false,
|
||||
canDeleteDataFrameAnalytics: false,
|
||||
canCreateDataFrameAnalytics: false,
|
||||
canStartStopDataFrameAnalytics: false,
|
||||
};
|
||||
}
|
||||
|
||||
export interface PrivilegesResponse {
|
||||
capabilities: Privileges;
|
||||
upgradeInProgress: boolean;
|
||||
isPlatinumOrTrialLicense: boolean;
|
||||
mlFeatureEnabledInSpace: boolean;
|
||||
}
|
|
@ -8,19 +8,19 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { hasLicenseExpired } from '../license';
|
||||
|
||||
import { Privileges, getDefaultPrivileges } from '../../../common/types/privileges';
|
||||
import { getPrivileges, getManageMlPrivileges } from './get_privileges';
|
||||
import { MlCapabilities, getDefaultCapabilities } from '../../../common/types/capabilities';
|
||||
import { getCapabilities, getManageMlCapabilities } from './get_capabilities';
|
||||
import { ACCESS_DENIED_PATH } from '../management/management_urls';
|
||||
|
||||
let privileges: Privileges = getDefaultPrivileges();
|
||||
// manage_ml requires all monitor and admin cluster privileges: https://github.com/elastic/elasticsearch/blob/664a29c8905d8ce9ba8c18aa1ed5c5de93a0eabc/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilege.java#L53
|
||||
export function checkGetManagementMlJobs() {
|
||||
let _capabilities: MlCapabilities = getDefaultCapabilities();
|
||||
|
||||
export function checkGetManagementMlJobsResolver() {
|
||||
return new Promise<{ mlFeatureEnabledInSpace: boolean }>((resolve, reject) => {
|
||||
getManageMlPrivileges().then(
|
||||
getManageMlCapabilities().then(
|
||||
({ capabilities, isPlatinumOrTrialLicense, mlFeatureEnabledInSpace }) => {
|
||||
privileges = capabilities;
|
||||
// Loop through all privileges to ensure they are all set to true.
|
||||
const isManageML = Object.values(privileges).every(p => p === true);
|
||||
_capabilities = capabilities;
|
||||
// Loop through all capabilities to ensure they are all set to true.
|
||||
const isManageML = Object.values(_capabilities).every(p => p === true);
|
||||
|
||||
if (isManageML === true && isPlatinumOrTrialLicense === true) {
|
||||
return resolve({ mlFeatureEnabledInSpace });
|
||||
|
@ -33,17 +33,17 @@ export function checkGetManagementMlJobs() {
|
|||
});
|
||||
}
|
||||
|
||||
export function checkGetJobsPrivilege(): Promise<Privileges> {
|
||||
export function checkGetJobsCapabilitiesResolver(): Promise<MlCapabilities> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getPrivileges().then(({ capabilities, isPlatinumOrTrialLicense }) => {
|
||||
privileges = capabilities;
|
||||
getCapabilities().then(({ capabilities, isPlatinumOrTrialLicense }) => {
|
||||
_capabilities = capabilities;
|
||||
// the minimum privilege for using ML with a platinum or trial license is being able to get the transforms list.
|
||||
// all other functionality is controlled by the return privileges object.
|
||||
// all other functionality is controlled by the return capabilities object.
|
||||
// if the license is basic (isPlatinumOrTrialLicense === false) then do not redirect,
|
||||
// allow the promise to resolve as the separate license check will redirect then user to
|
||||
// a basic feature
|
||||
if (privileges.canGetJobs || isPlatinumOrTrialLicense === false) {
|
||||
return resolve(privileges);
|
||||
if (_capabilities.canGetJobs || isPlatinumOrTrialLicense === false) {
|
||||
return resolve(_capabilities);
|
||||
} else {
|
||||
window.location.href = '#/access-denied';
|
||||
return reject();
|
||||
|
@ -52,15 +52,15 @@ export function checkGetJobsPrivilege(): Promise<Privileges> {
|
|||
});
|
||||
}
|
||||
|
||||
export function checkCreateJobsPrivilege(): Promise<Privileges> {
|
||||
export function checkCreateJobsCapabilitiesResolver(): Promise<MlCapabilities> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getPrivileges().then(({ capabilities, isPlatinumOrTrialLicense }) => {
|
||||
privileges = capabilities;
|
||||
getCapabilities().then(({ capabilities, isPlatinumOrTrialLicense }) => {
|
||||
_capabilities = capabilities;
|
||||
// if the license is basic (isPlatinumOrTrialLicense === false) then do not redirect,
|
||||
// allow the promise to resolve as the separate license check will redirect then user to
|
||||
// a basic feature
|
||||
if (privileges.canCreateJob || isPlatinumOrTrialLicense === false) {
|
||||
return resolve(privileges);
|
||||
if (_capabilities.canCreateJob || isPlatinumOrTrialLicense === false) {
|
||||
return resolve(_capabilities);
|
||||
} else {
|
||||
// if the user has no permission to create a job,
|
||||
// redirect them back to the Transforms Management page
|
||||
|
@ -71,14 +71,14 @@ export function checkCreateJobsPrivilege(): Promise<Privileges> {
|
|||
});
|
||||
}
|
||||
|
||||
export function checkFindFileStructurePrivilege(): Promise<Privileges> {
|
||||
export function checkFindFileStructurePrivilegeResolver(): Promise<MlCapabilities> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getPrivileges().then(({ capabilities }) => {
|
||||
privileges = capabilities;
|
||||
getCapabilities().then(({ capabilities }) => {
|
||||
_capabilities = capabilities;
|
||||
// the minimum privilege for using ML with a basic license is being able to use the datavisualizer.
|
||||
// all other functionality is controlled by the return privileges object
|
||||
if (privileges.canFindFileStructure) {
|
||||
return resolve(privileges);
|
||||
// all other functionality is controlled by the return _capabilities object
|
||||
if (_capabilities.canFindFileStructure) {
|
||||
return resolve(_capabilities);
|
||||
} else {
|
||||
window.location.href = '#/access-denied';
|
||||
return reject();
|
||||
|
@ -89,14 +89,14 @@ export function checkFindFileStructurePrivilege(): Promise<Privileges> {
|
|||
|
||||
// check the privilege type and the license to see whether a user has permission to access a feature.
|
||||
// takes the name of the privilege variable as specified in get_privileges.js
|
||||
export function checkPermission(privilegeType: keyof Privileges) {
|
||||
export function checkPermission(capability: keyof MlCapabilities) {
|
||||
const licenseHasExpired = hasLicenseExpired();
|
||||
return privileges[privilegeType] === true && licenseHasExpired !== true;
|
||||
return _capabilities[capability] === true && licenseHasExpired !== true;
|
||||
}
|
||||
|
||||
// create the text for the button's tooltips if the user's license has
|
||||
// expired or if they don't have the privilege to press that button
|
||||
export function createPermissionFailureMessage(privilegeType: keyof Privileges) {
|
||||
export function createPermissionFailureMessage(privilegeType: keyof MlCapabilities) {
|
||||
let message = '';
|
||||
const licenseHasExpired = hasLicenseExpired();
|
||||
if (licenseHasExpired) {
|
|
@ -7,12 +7,12 @@
|
|||
import { ml } from '../services/ml_api_service';
|
||||
|
||||
import { setUpgradeInProgress } from '../services/upgrade_service';
|
||||
import { PrivilegesResponse } from '../../../common/types/privileges';
|
||||
import { MlCapabilitiesResponse } from '../../../common/types/capabilities';
|
||||
|
||||
export function getPrivileges(): Promise<PrivilegesResponse> {
|
||||
export function getCapabilities(): Promise<MlCapabilitiesResponse> {
|
||||
return new Promise((resolve, reject) => {
|
||||
ml.checkMlPrivileges()
|
||||
.then((resp: PrivilegesResponse) => {
|
||||
ml.checkMlCapabilities()
|
||||
.then((resp: MlCapabilitiesResponse) => {
|
||||
if (resp.upgradeInProgress === true) {
|
||||
setUpgradeInProgress(true);
|
||||
}
|
||||
|
@ -24,10 +24,10 @@ export function getPrivileges(): Promise<PrivilegesResponse> {
|
|||
});
|
||||
}
|
||||
|
||||
export function getManageMlPrivileges(): Promise<PrivilegesResponse> {
|
||||
export function getManageMlCapabilities(): Promise<MlCapabilitiesResponse> {
|
||||
return new Promise((resolve, reject) => {
|
||||
ml.checkManageMLPrivileges()
|
||||
.then((resp: PrivilegesResponse) => {
|
||||
ml.checkManageMLCapabilities()
|
||||
.then((resp: MlCapabilitiesResponse) => {
|
||||
if (resp.upgradeInProgress === true) {
|
||||
setUpgradeInProgress(true);
|
||||
}
|
|
@ -8,14 +8,14 @@ import React from 'react';
|
|||
import mockAnomaliesTableData from '../../explorer/__mocks__/mock_anomalies_table_data.json';
|
||||
import { getColumns } from './anomalies_table_columns';
|
||||
|
||||
jest.mock('../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: () => false,
|
||||
}));
|
||||
jest.mock('../../license', () => ({
|
||||
hasLicenseExpired: () => false,
|
||||
}));
|
||||
jest.mock('../../privilege/get_privileges', () => ({
|
||||
getPrivileges: () => {},
|
||||
jest.mock('../../capabilities/get_capabilities', () => ({
|
||||
getCapabilities: () => {},
|
||||
}));
|
||||
jest.mock('../../services/field_format_service', () => ({
|
||||
getFieldFormat: () => {},
|
||||
|
|
|
@ -23,7 +23,7 @@ import { DetectorCell } from './detector_cell';
|
|||
import { EntityCell } from '../entity_cell';
|
||||
import { InfluencersCell } from './influencers_cell';
|
||||
import { LinksMenu } from './links_menu';
|
||||
import { checkPermission } from '../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||
import { mlFieldFormatService } from '../../services/field_format_service';
|
||||
import { isRuleSupported } from '../../../../common/util/anomaly_utils';
|
||||
import { formatValue } from '../../formatters/format_value';
|
||||
|
|
|
@ -17,7 +17,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import { withKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
|
||||
import { ES_FIELD_TYPES } from '../../../../../../../src/plugins/data/public';
|
||||
import { checkPermission } from '../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||
import { SEARCH_QUERY_LANGUAGE } from '../../../../common/constants/search';
|
||||
import { isRuleSupported } from '../../../../common/util/anomaly_utils';
|
||||
import { parseInterval } from '../../../../common/util/parse_interval';
|
||||
|
|
|
@ -30,7 +30,7 @@ import {
|
|||
|
||||
import { DetectorDescriptionList } from './components/detector_description_list';
|
||||
import { ActionsSection } from './actions_section';
|
||||
import { checkPermission } from '../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||
import { ConditionsSection } from './conditions_section';
|
||||
import { ScopeSection } from './scope_section';
|
||||
import { SelectRuleAction } from './select_rule_action';
|
||||
|
|
|
@ -45,7 +45,7 @@ jest.mock('../../services/job_service', () => ({
|
|||
},
|
||||
}));
|
||||
jest.mock('../../services/ml_api_service', () => 'ml');
|
||||
jest.mock('../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: () => true,
|
||||
}));
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import React from 'react';
|
|||
import { EuiCallOut, EuiCheckbox, EuiLink, EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
|
||||
import { ScopeExpression } from './scope_expression';
|
||||
import { checkPermission } from '../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||
import { getScopeFieldDefaults } from './utils';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ jest.mock('../../services/job_service.js', () => 'mlJobService');
|
|||
// The mock is hoisted to the top, so need to prefix the mock function
|
||||
// with 'mock' so it can be used lazily.
|
||||
const mockCheckPermission = jest.fn(() => true);
|
||||
jest.mock('../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: privilege => mockCheckPermission(privilege),
|
||||
}));
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import * as CheckPrivilige from '../../../../../privilege/check_privilege';
|
||||
import * as CheckPrivilige from '../../../../../capabilities/check_capabilities';
|
||||
|
||||
import { DeleteAction } from './action_delete';
|
||||
|
||||
import mockAnalyticsListItem from './__mocks__/analytics_list_item.json';
|
||||
|
||||
jest.mock('../../../../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../../../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: jest.fn(() => false),
|
||||
createPermissionFailureMessage: jest.fn(),
|
||||
}));
|
||||
|
|
|
@ -19,7 +19,7 @@ import { deleteAnalytics } from '../../services/analytics_service';
|
|||
import {
|
||||
checkPermission,
|
||||
createPermissionFailureMessage,
|
||||
} from '../../../../../privilege/check_privilege';
|
||||
} from '../../../../../capabilities/check_capabilities';
|
||||
|
||||
import { isDataFrameAnalyticsRunning, DataFrameAnalyticsListRow } from './common';
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import { startAnalytics } from '../../services/analytics_service';
|
|||
import {
|
||||
checkPermission,
|
||||
createPermissionFailureMessage,
|
||||
} from '../../../../../privilege/check_privilege';
|
||||
} from '../../../../../capabilities/check_capabilities';
|
||||
|
||||
import { DataFrameAnalyticsListRow, isCompletedAnalyticsJob } from './common';
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import { DeepReadonly } from '../../../../../../../common/types/common';
|
|||
import {
|
||||
checkPermission,
|
||||
createPermissionFailureMessage,
|
||||
} from '../../../../../privilege/check_privilege';
|
||||
} from '../../../../../capabilities/check_capabilities';
|
||||
|
||||
import {
|
||||
getAnalysisType,
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
|
||||
import { DataFrameAnalyticsId, useRefreshAnalyticsList } from '../../../../common';
|
||||
import { checkPermission } from '../../../../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../../../../capabilities/check_capabilities';
|
||||
import { getTaskStateBadge } from './columns';
|
||||
|
||||
import {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import React, { FC } from 'react';
|
||||
import { EuiButton, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { createPermissionFailureMessage } from '../../../../../privilege/check_privilege';
|
||||
import { createPermissionFailureMessage } from '../../../../../capabilities/check_capabilities';
|
||||
import { CreateAnalyticsFormProps } from '../../hooks/use_create_analytics_form';
|
||||
|
||||
export const CreateAnalyticsButton: FC<CreateAnalyticsFormProps> = props => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { EuiComboBoxOptionOption } from '@elastic/eui';
|
||||
import { DeepPartial, DeepReadonly } from '../../../../../../../common/types/common';
|
||||
import { checkPermission } from '../../../../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../../../../capabilities/check_capabilities';
|
||||
import { mlNodesAvailable } from '../../../../../ml_nodes_check';
|
||||
import { newJobCapsService } from '../../../../../services/new_job_capabilities_service';
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import { EuiFlexGroup, EuiFlexItem, EuiCard, EuiIcon } from '@elastic/eui';
|
||||
import { ml } from '../../../../services/ml_api_service';
|
||||
import { isFullLicense } from '../../../../license';
|
||||
import { checkPermission } from '../../../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../../../capabilities/check_capabilities';
|
||||
import { mlNodesAvailable } from '../../../../ml_nodes_check/check_ml_nodes';
|
||||
import { useMlKibana } from '../../../../contexts/kibana';
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import { NavigationMenu } from '../../components/navigation_menu';
|
|||
import { ML_JOB_FIELD_TYPES } from '../../../../common/constants/field_types';
|
||||
import { SEARCH_QUERY_LANGUAGE } from '../../../../common/constants/search';
|
||||
import { isFullLicense } from '../../license';
|
||||
import { checkPermission } from '../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||
import { mlNodesAvailable } from '../../ml_nodes_check/check_ml_nodes';
|
||||
import { FullTimeRangeSelector } from '../../components/full_time_range_selector';
|
||||
import { mlTimefilterRefresh$ } from '../../services/timefilter_refresh_service';
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { checkPermission } from '../../../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../../../capabilities/check_capabilities';
|
||||
import { mlNodesAvailable } from '../../../../ml_nodes_check/check_ml_nodes';
|
||||
import { getIndexPatternNames } from '../../../../util/index_utils';
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import React, { Component } from 'react';
|
|||
import { EuiSpacer, EuiCallOut, EuiLoadingSpinner } from '@elastic/eui';
|
||||
|
||||
import { mlJobService } from '../../../../services/job_service';
|
||||
import { checkPermission } from '../../../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../../../capabilities/check_capabilities';
|
||||
import { ML_DATA_PREVIEW_COUNT } from '../../../../../../common/util/job_utils';
|
||||
import { MLJobEditor } from '../ml_job_editor';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { checkPermission } from '../../../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../../../capabilities/check_capabilities';
|
||||
import { mlNodesAvailable } from '../../../../ml_nodes_check/check_ml_nodes';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
import { cloneDeep } from 'lodash';
|
||||
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
import { checkPermission } from '../../../../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../../../../capabilities/check_capabilities';
|
||||
import { GroupList } from './group_list';
|
||||
import { NewGroupInput } from './new_group_input';
|
||||
import { mlMessageBarService } from '../../../../../components/messagebar';
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { checkPermission } from '../../../../privilege/check_privilege';
|
||||
import { checkPermission } from '../../../../capabilities/check_capabilities';
|
||||
import { mlNodesAvailable } from '../../../../ml_nodes_check/check_ml_nodes';
|
||||
|
||||
import React from 'react';
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { checkGetManagementMlJobs } from '../../../../privilege/check_privilege';
|
||||
import { checkGetManagementMlJobsResolver } from '../../../../capabilities/check_capabilities';
|
||||
|
||||
import { getDocLinks } from '../../../../util/dependency_cache';
|
||||
// @ts-ignore undeclared module
|
||||
|
@ -75,7 +75,7 @@ export const JobsListPage: FC<{ I18nContext: CoreStart['i18n']['Context'] }> = (
|
|||
|
||||
const check = async () => {
|
||||
try {
|
||||
const checkPrivilege = await checkGetManagementMlJobs();
|
||||
const checkPrivilege = await checkGetManagementMlJobsResolver();
|
||||
setInitialized(true);
|
||||
setIsMlEnabledInSpace(checkPrivilege.mlFeatureEnabledInSpace);
|
||||
} catch (e) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import React, { Fragment, FC } from 'react';
|
||||
import { EuiFlexGroup, EuiPage, EuiPageBody } from '@elastic/eui';
|
||||
import { checkPermission } from '../privilege/check_privilege';
|
||||
import { checkPermission } from '../capabilities/check_capabilities';
|
||||
import { mlNodesAvailable } from '../ml_nodes_check/check_ml_nodes';
|
||||
import { NavigationMenu } from '../components/navigation_menu';
|
||||
import { OverviewSideBar } from './components/sidebar';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { loadIndexPatterns, loadSavedSearches } from '../util/index_utils';
|
||||
import { checkFullLicense } from '../license';
|
||||
import { checkGetJobsPrivilege } from '../privilege/check_privilege';
|
||||
import { checkGetJobsCapabilitiesResolver } from '../capabilities/check_capabilities';
|
||||
import { getMlNodeCount } from '../ml_nodes_check/check_ml_nodes';
|
||||
import { loadMlServerInfo } from '../services/ml_server_info';
|
||||
|
||||
|
@ -28,6 +28,6 @@ export const basicResolvers = ({ indexPatterns }: BasicResolverDependencies): Re
|
|||
getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
loadIndexPatterns: () => loadIndexPatterns(indexPatterns),
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
loadSavedSearches,
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ import { useResolver } from '../../use_resolver';
|
|||
import { DatavisualizerSelector } from '../../../datavisualizer';
|
||||
|
||||
import { checkBasicLicense } from '../../../license';
|
||||
import { checkFindFileStructurePrivilege } from '../../../privilege/check_privilege';
|
||||
import { checkFindFileStructurePrivilegeResolver } from '../../../capabilities/check_capabilities';
|
||||
import { DATA_VISUALIZER_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
||||
const breadcrumbs = [ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB];
|
||||
|
@ -30,7 +30,7 @@ export const selectorRoute: MlRoute = {
|
|||
const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
||||
const { context } = useResolver(undefined, undefined, deps.config, {
|
||||
checkBasicLicense,
|
||||
checkFindFileStructurePrivilege,
|
||||
checkFindFileStructurePrivilege: checkFindFileStructurePrivilegeResolver,
|
||||
});
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -17,7 +17,7 @@ import { useResolver } from '../../use_resolver';
|
|||
import { FileDataVisualizerPage } from '../../../datavisualizer/file_based';
|
||||
|
||||
import { checkBasicLicense } from '../../../license';
|
||||
import { checkFindFileStructurePrivilege } from '../../../privilege/check_privilege';
|
||||
import { checkFindFileStructurePrivilegeResolver } from '../../../capabilities/check_capabilities';
|
||||
import { loadIndexPatterns } from '../../../util/index_utils';
|
||||
|
||||
import { DATA_VISUALIZER_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
@ -43,7 +43,7 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
const { context } = useResolver('', undefined, deps.config, {
|
||||
checkBasicLicense,
|
||||
loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns),
|
||||
checkFindFileStructurePrivilege,
|
||||
checkFindFileStructurePrivilege: checkFindFileStructurePrivilegeResolver,
|
||||
});
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -12,7 +12,7 @@ import { useResolver } from '../../use_resolver';
|
|||
import { Page } from '../../../datavisualizer/index_based';
|
||||
|
||||
import { checkBasicLicense } from '../../../license';
|
||||
import { checkGetJobsPrivilege } from '../../../privilege/check_privilege';
|
||||
import { checkGetJobsCapabilitiesResolver } from '../../../capabilities/check_capabilities';
|
||||
import { loadIndexPatterns } from '../../../util/index_utils';
|
||||
import { checkMlNodesAvailable } from '../../../ml_nodes_check';
|
||||
import { DATA_VISUALIZER_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
@ -39,7 +39,7 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
const { context } = useResolver(index, savedSearchId, deps.config, {
|
||||
checkBasicLicense,
|
||||
loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns),
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
checkMlNodesAvailable,
|
||||
});
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { Page, preConfiguredJobRedirect } from '../../../jobs/new_job/pages/inde
|
|||
import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
import { checkBasicLicense } from '../../../license';
|
||||
import { loadIndexPatterns } from '../../../util/index_utils';
|
||||
import { checkGetJobsPrivilege } from '../../../privilege/check_privilege';
|
||||
import { checkGetJobsCapabilitiesResolver } from '../../../capabilities/check_capabilities';
|
||||
import { checkMlNodesAvailable } from '../../../ml_nodes_check';
|
||||
|
||||
enum MODE {
|
||||
|
@ -71,7 +71,7 @@ const PageWrapper: FC<IndexOrSearchPageProps> = ({ nextStepPath, deps, mode }) =
|
|||
const dataVizResolvers = {
|
||||
checkBasicLicense,
|
||||
loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns),
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
checkMlNodesAvailable,
|
||||
};
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import { Page } from '../../../jobs/new_job/pages/new_job';
|
|||
import { JOB_TYPE } from '../../../../../common/constants/new_job';
|
||||
import { mlJobService } from '../../../services/job_service';
|
||||
import { loadNewJobCapabilities } from '../../../services/new_job_capabilities_service';
|
||||
import { checkCreateJobsPrivilege } from '../../../privilege/check_privilege';
|
||||
import { checkCreateJobsCapabilitiesResolver } from '../../../capabilities/check_capabilities';
|
||||
import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
||||
interface WizardPageProps extends PageProps {
|
||||
|
@ -115,7 +115,7 @@ const PageWrapper: FC<WizardPageProps> = ({ location, jobType, deps }) => {
|
|||
const { index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context, results } = useResolver(index, savedSearchId, deps.config, {
|
||||
...basicResolvers(deps),
|
||||
privileges: checkCreateJobsPrivilege,
|
||||
privileges: checkCreateJobsCapabilitiesResolver,
|
||||
jobCaps: () => loadNewJobCapabilities(index, savedSearchId, deps.indexPatterns),
|
||||
existingJobsAndGroups: mlJobService.getJobAndGroupIds,
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@ import { useResolver } from '../use_resolver';
|
|||
import { OverviewPage } from '../../overview';
|
||||
|
||||
import { checkFullLicense } from '../../license';
|
||||
import { checkGetJobsPrivilege } from '../../privilege/check_privilege';
|
||||
import { checkGetJobsCapabilitiesResolver } from '../../capabilities/check_capabilities';
|
||||
import { getMlNodeCount } from '../../ml_nodes_check';
|
||||
import { loadMlServerInfo } from '../../services/ml_server_info';
|
||||
import { useTimefilter } from '../../contexts/kibana';
|
||||
|
@ -38,7 +38,7 @@ export const overviewRoute: MlRoute = {
|
|||
const PageWrapper: FC<PageProps> = ({ deps }) => {
|
||||
const { context } = useResolver(undefined, undefined, deps.config, {
|
||||
checkFullLicense,
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
});
|
||||
|
|
|
@ -17,7 +17,10 @@ import { useResolver } from '../../use_resolver';
|
|||
|
||||
import { useTimefilter } from '../../../contexts/kibana';
|
||||
import { checkFullLicense } from '../../../license';
|
||||
import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege';
|
||||
import {
|
||||
checkGetJobsCapabilitiesResolver,
|
||||
checkPermission,
|
||||
} from '../../../capabilities/check_capabilities';
|
||||
import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes';
|
||||
import { CalendarsList } from '../../../settings/calendars';
|
||||
import { SETTINGS, ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
@ -42,7 +45,7 @@ export const calendarListRoute: MlRoute = {
|
|||
const PageWrapper: FC<PageProps> = ({ deps }) => {
|
||||
const { context } = useResolver(undefined, undefined, deps.config, {
|
||||
checkFullLicense,
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
getMlNodeCount,
|
||||
});
|
||||
|
||||
|
|
|
@ -17,7 +17,10 @@ import { useResolver } from '../../use_resolver';
|
|||
|
||||
import { useTimefilter } from '../../../contexts/kibana';
|
||||
import { checkFullLicense } from '../../../license';
|
||||
import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege';
|
||||
import {
|
||||
checkGetJobsCapabilitiesResolver,
|
||||
checkPermission,
|
||||
} from '../../../capabilities/check_capabilities';
|
||||
import { checkMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes';
|
||||
import { NewCalendar } from '../../../settings/calendars';
|
||||
import { SETTINGS, ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
@ -74,7 +77,7 @@ const PageWrapper: FC<NewCalendarPageProps> = ({ location, mode, deps }) => {
|
|||
|
||||
const { context } = useResolver(undefined, undefined, deps.config, {
|
||||
checkFullLicense,
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
checkMlNodesAvailable,
|
||||
});
|
||||
|
||||
|
|
|
@ -17,7 +17,10 @@ import { useResolver } from '../../use_resolver';
|
|||
|
||||
import { useTimefilter } from '../../../contexts/kibana';
|
||||
import { checkFullLicense } from '../../../license';
|
||||
import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege';
|
||||
import {
|
||||
checkGetJobsCapabilitiesResolver,
|
||||
checkPermission,
|
||||
} from '../../../capabilities/check_capabilities';
|
||||
import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes';
|
||||
import { FilterLists } from '../../../settings/filter_lists';
|
||||
|
||||
|
@ -43,7 +46,7 @@ export const filterListRoute: MlRoute = {
|
|||
const PageWrapper: FC<PageProps> = ({ deps }) => {
|
||||
const { context } = useResolver(undefined, undefined, deps.config, {
|
||||
checkFullLicense,
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
getMlNodeCount,
|
||||
});
|
||||
|
||||
|
|
|
@ -17,7 +17,10 @@ import { useResolver } from '../../use_resolver';
|
|||
|
||||
import { useTimefilter } from '../../../contexts/kibana';
|
||||
import { checkFullLicense } from '../../../license';
|
||||
import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege';
|
||||
import {
|
||||
checkGetJobsCapabilitiesResolver,
|
||||
checkPermission,
|
||||
} from '../../../capabilities/check_capabilities';
|
||||
import { checkMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes';
|
||||
import { EditFilterList } from '../../../settings/filter_lists';
|
||||
import { SETTINGS, ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
@ -74,7 +77,7 @@ const PageWrapper: FC<NewFilterPageProps> = ({ location, mode, deps }) => {
|
|||
|
||||
const { context } = useResolver(undefined, undefined, deps.config, {
|
||||
checkFullLicense,
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
checkMlNodesAvailable,
|
||||
});
|
||||
|
||||
|
|
|
@ -16,7 +16,10 @@ import { useResolver } from '../../use_resolver';
|
|||
|
||||
import { useTimefilter } from '../../../contexts/kibana';
|
||||
import { checkFullLicense } from '../../../license';
|
||||
import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege';
|
||||
import {
|
||||
checkGetJobsCapabilitiesResolver,
|
||||
checkPermission,
|
||||
} from '../../../capabilities/check_capabilities';
|
||||
import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes';
|
||||
import { Settings } from '../../../settings';
|
||||
import { ML_BREADCRUMB, SETTINGS } from '../../breadcrumbs';
|
||||
|
@ -32,7 +35,7 @@ export const settingsRoute: MlRoute = {
|
|||
const PageWrapper: FC<PageProps> = ({ deps }) => {
|
||||
const { context } = useResolver(undefined, undefined, deps.config, {
|
||||
checkFullLicense,
|
||||
checkGetJobsPrivilege,
|
||||
checkGetJobsCapabilities: checkGetJobsCapabilitiesResolver,
|
||||
getMlNodeCount,
|
||||
});
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import { jobs } from './jobs';
|
|||
import { fileDatavisualizer } from './datavisualizer';
|
||||
import { MlServerDefaults, MlServerLimits } from '../../../../common/types/ml_server_info';
|
||||
|
||||
import { PrivilegesResponse } from '../../../../common/types/privileges';
|
||||
import { MlCapabilitiesResponse } from '../../../../common/types/capabilities';
|
||||
import { Calendar, CalendarId, UpdateCalendar } from '../../../../common/types/calendars';
|
||||
import {
|
||||
Job,
|
||||
|
@ -300,18 +300,17 @@ export const ml = {
|
|||
});
|
||||
},
|
||||
|
||||
checkMlPrivileges() {
|
||||
return http<PrivilegesResponse>({
|
||||
checkMlCapabilities() {
|
||||
return http<MlCapabilitiesResponse>({
|
||||
path: `${basePath()}/ml_capabilities`,
|
||||
method: 'GET',
|
||||
});
|
||||
},
|
||||
|
||||
checkManageMLPrivileges() {
|
||||
return http<PrivilegesResponse>({
|
||||
checkManageMLCapabilities() {
|
||||
return http<MlCapabilitiesResponse>({
|
||||
path: `${basePath()}/ml_capabilities`,
|
||||
method: 'GET',
|
||||
query: { ignoreSpaces: true },
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
jest.mock('../../../components/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />,
|
||||
}));
|
||||
jest.mock('../../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: () => true,
|
||||
}));
|
||||
jest.mock('../../../license', () => ({
|
||||
hasLicenseExpired: () => false,
|
||||
isFullLicense: () => false,
|
||||
}));
|
||||
jest.mock('../../../privilege/get_privileges', () => ({
|
||||
getPrivileges: () => {},
|
||||
jest.mock('../../../capabilities/get_capabilities', () => ({
|
||||
getCapabilities: () => {},
|
||||
}));
|
||||
jest.mock('../../../ml_nodes_check/check_ml_nodes', () => ({
|
||||
mlNodesAvailable: () => true,
|
||||
|
|
|
@ -13,15 +13,15 @@ import { CalendarsList } from './calendars_list';
|
|||
jest.mock('../../../components/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />,
|
||||
}));
|
||||
jest.mock('../../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: () => true,
|
||||
}));
|
||||
jest.mock('../../../license', () => ({
|
||||
hasLicenseExpired: () => false,
|
||||
isFullLicense: () => false,
|
||||
}));
|
||||
jest.mock('../../../privilege/get_privileges', () => ({
|
||||
getPrivileges: () => {},
|
||||
jest.mock('../../../capabilities/get_capabilities', () => ({
|
||||
getCapabilities: () => {},
|
||||
}));
|
||||
jest.mock('../../../ml_nodes_check/check_ml_nodes', () => ({
|
||||
mlNodesAvailable: () => true,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// The mock is hoisted to the top, so need to prefix the mock function
|
||||
// with 'mock' so it can be used lazily.
|
||||
const mockCheckPermission = jest.fn(() => true);
|
||||
jest.mock('../../../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: privilege => mockCheckPermission(privilege),
|
||||
}));
|
||||
jest.mock('../../../../services/ml_api_service', () => 'ml');
|
||||
|
|
|
@ -12,7 +12,7 @@ import { FilterLists } from './filter_lists';
|
|||
jest.mock('../../../components/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />,
|
||||
}));
|
||||
jest.mock('../../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: () => true,
|
||||
}));
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
// Create a mock for the privilege check used within the table to
|
||||
// enable/disable the 'New Filter' button.
|
||||
jest.mock('../../../privilege/check_privilege', () => ({
|
||||
jest.mock('../../../capabilities/check_capabilities', () => ({
|
||||
checkPermission: () => true,
|
||||
}));
|
||||
jest.mock('../../../services/ml_api_service', () => 'ml');
|
||||
|
|
|
@ -32,7 +32,7 @@ import { mlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes';
|
|||
import {
|
||||
checkPermission,
|
||||
createPermissionFailureMessage,
|
||||
} from '../../../privilege/check_privilege';
|
||||
} from '../../../capabilities/check_capabilities';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import {
|
||||
adminMlCapabilities,
|
||||
userMlCapabilities,
|
||||
MlCapabilities,
|
||||
getDefaultCapabilities,
|
||||
} from '../../../../common/types/capabilities';
|
||||
|
||||
export function getAdminCapabilities() {
|
||||
const caps: any = {};
|
||||
Object.keys(adminMlCapabilities).forEach(k => {
|
||||
caps[k] = true;
|
||||
});
|
||||
return { ...getUserCapabilities(), ...caps } as MlCapabilities;
|
||||
}
|
||||
|
||||
export function getUserCapabilities() {
|
||||
const caps: any = {};
|
||||
Object.keys(userMlCapabilities).forEach(k => {
|
||||
caps[k] = true;
|
||||
});
|
||||
|
||||
return { ...getDefaultCapabilities(), ...caps } as MlCapabilities;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { cloneDeep } from 'lodash';
|
||||
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 { MlCapabilities, basicLicenseMlCapabilities } from '../../../common/types/capabilities';
|
||||
|
||||
export const setupCapabilitiesSwitcher = (
|
||||
coreSetup: CoreSetup,
|
||||
license$: Observable<ILicense>,
|
||||
logger: Logger
|
||||
) => {
|
||||
coreSetup.capabilities.registerSwitcher(getSwitcher(license$, logger));
|
||||
};
|
||||
|
||||
function getSwitcher(license$: Observable<ILicense>, logger: Logger): CapabilitiesSwitcher {
|
||||
return async (request, capabilities) => {
|
||||
const isAnonymousRequest = !request.route.options.authRequired;
|
||||
|
||||
if (isAnonymousRequest) {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
try {
|
||||
const license = await license$.pipe(take(1)).toPromise();
|
||||
|
||||
// full license, leave capabilities as they were
|
||||
if (isFullLicense(license)) {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
const mlCaps = capabilities.ml as MlCapabilities;
|
||||
const originalCapabilities = cloneDeep(mlCaps);
|
||||
|
||||
// not full licence, switch off all capabilities
|
||||
Object.keys(mlCaps).forEach(k => {
|
||||
mlCaps[k as keyof MlCapabilities] = false;
|
||||
});
|
||||
|
||||
// for a basic license, reapply the original capabilities for the basic license features
|
||||
if (isMinimumLicense(license)) {
|
||||
basicLicenseMlCapabilities.forEach(c => (mlCaps[c] = originalCapabilities[c]));
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
} catch (e) {
|
||||
logger.debug(`Error updating capabilities for ML based on licensing: ${e}`);
|
||||
return capabilities;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { getAdminCapabilities, getUserCapabilities } from './__mocks__/ml_capabilities';
|
||||
import { capabilitiesProvider } from './check_capabilities';
|
||||
import { MlLicense } from '../../../common/license';
|
||||
import { getDefaultCapabilities } from '../../../common/types/capabilities';
|
||||
|
||||
const mlLicense = {
|
||||
isSecurityEnabled: () => true,
|
||||
isFullLicense: () => true,
|
||||
} as MlLicense;
|
||||
|
||||
const mlLicenseBasic = {
|
||||
isSecurityEnabled: () => true,
|
||||
isFullLicense: () => false,
|
||||
} as MlLicense;
|
||||
|
||||
const mlIsEnabled = async () => true;
|
||||
const mlIsNotEnabled = async () => false;
|
||||
|
||||
const callWithRequestNonUpgrade = async () => ({ upgrade_mode: false });
|
||||
const callWithRequestUpgrade = async () => ({ upgrade_mode: true });
|
||||
|
||||
describe('check_capabilities', () => {
|
||||
describe('getCapabilities() - right number of capabilities', () => {
|
||||
test('kibana capabilities count', async done => {
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
callWithRequestNonUpgrade,
|
||||
getAdminCapabilities(),
|
||||
mlLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities } = await getCapabilities();
|
||||
const count = Object.keys(capabilities).length;
|
||||
expect(count).toBe(22);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCapabilities() with security', () => {
|
||||
test('ml_user capabilities only', async done => {
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
callWithRequestNonUpgrade,
|
||||
getUserCapabilities(),
|
||||
mlLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('full capabilities', async done => {
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
callWithRequestNonUpgrade,
|
||||
getAdminCapabilities(),
|
||||
mlLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(true);
|
||||
expect(capabilities.canDeleteJob).toBe(true);
|
||||
expect(capabilities.canOpenJob).toBe(true);
|
||||
expect(capabilities.canCloseJob).toBe(true);
|
||||
expect(capabilities.canForecastJob).toBe(true);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(true);
|
||||
expect(capabilities.canUpdateJob).toBe(true);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(true);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(true);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(true);
|
||||
expect(capabilities.canDeleteCalendar).toBe(true);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(true);
|
||||
expect(capabilities.canDeleteFilter).toBe(true);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(true);
|
||||
done();
|
||||
});
|
||||
|
||||
test('upgrade in progress with full capabilities', async done => {
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
callWithRequestUpgrade,
|
||||
getAdminCapabilities(),
|
||||
mlLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities();
|
||||
expect(upgradeInProgress).toBe(true);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('upgrade in progress with partial capabilities', async done => {
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
callWithRequestUpgrade,
|
||||
getUserCapabilities(),
|
||||
mlLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities();
|
||||
expect(upgradeInProgress).toBe(true);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('full capabilities, ml disabled in space', async done => {
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
callWithRequestNonUpgrade,
|
||||
getDefaultCapabilities(),
|
||||
mlLicense,
|
||||
mlIsNotEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(false);
|
||||
expect(capabilities.canGetJobs).toBe(false);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(false);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(false);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(false);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('full capabilities, basic license, ml disabled in space', async done => {
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
callWithRequestNonUpgrade,
|
||||
getDefaultCapabilities(),
|
||||
mlLicenseBasic,
|
||||
mlIsNotEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(false);
|
||||
expect(capabilities.canGetJobs).toBe(false);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(false);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(false);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(false);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { IScopedClusterClient } from 'kibana/server';
|
||||
import {
|
||||
MlCapabilities,
|
||||
adminMlCapabilities,
|
||||
MlCapabilitiesResponse,
|
||||
} from '../../../common/types/capabilities';
|
||||
import { upgradeCheckProvider } from './upgrade';
|
||||
import { MlLicense } from '../../../common/license';
|
||||
|
||||
export function capabilitiesProvider(
|
||||
callAsCurrentUser: IScopedClusterClient['callAsCurrentUser'],
|
||||
capabilities: MlCapabilities,
|
||||
mlLicense: MlLicense,
|
||||
isMlEnabledInSpace: () => Promise<boolean>
|
||||
) {
|
||||
const { isUpgradeInProgress } = upgradeCheckProvider(callAsCurrentUser);
|
||||
async function getCapabilities(): Promise<MlCapabilitiesResponse> {
|
||||
const upgradeInProgress = await isUpgradeInProgress();
|
||||
const isPlatinumOrTrialLicense = mlLicense.isFullLicense();
|
||||
const mlFeatureEnabledInSpace = await isMlEnabledInSpace();
|
||||
|
||||
if (upgradeInProgress === true) {
|
||||
// if an upgrade is in progress, set all admin capabilities to false
|
||||
disableAdminPrivileges(capabilities);
|
||||
}
|
||||
|
||||
return {
|
||||
capabilities,
|
||||
upgradeInProgress,
|
||||
isPlatinumOrTrialLicense,
|
||||
mlFeatureEnabledInSpace,
|
||||
};
|
||||
}
|
||||
return { getCapabilities };
|
||||
}
|
||||
|
||||
function disableAdminPrivileges(capabilities: MlCapabilities) {
|
||||
Object.keys(adminMlCapabilities).forEach(k => {
|
||||
capabilities[k as keyof MlCapabilities] = false;
|
||||
});
|
||||
}
|
|
@ -4,4 +4,5 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { privilegesProvider, MlCapabilities } from './check_privileges';
|
||||
export { capabilitiesProvider } from './check_capabilities';
|
||||
export { setupCapabilitiesSwitcher } from './capabilities_switcher';
|
|
@ -1,154 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export function callWithRequestProvider(testType: string) {
|
||||
switch (testType) {
|
||||
case 'partialPrivileges':
|
||||
return partialPrivileges;
|
||||
case 'fullPrivileges':
|
||||
return fullPrivileges;
|
||||
case 'upgradeWithFullPrivileges':
|
||||
return upgradeWithFullPrivileges;
|
||||
case 'upgradeWithPartialPrivileges':
|
||||
return upgradeWithPartialPrivileges;
|
||||
|
||||
default:
|
||||
return fullPrivileges;
|
||||
}
|
||||
}
|
||||
|
||||
const fullPrivileges = async (action: string, params?: any) => {
|
||||
switch (action) {
|
||||
case 'ml.privilegeCheck':
|
||||
return {
|
||||
username: 'test2',
|
||||
has_all_requested: false,
|
||||
cluster: fullClusterPrivileges,
|
||||
index: {},
|
||||
application: {},
|
||||
};
|
||||
case 'ml.info':
|
||||
return { upgrade_mode: false };
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const partialPrivileges = async (action: string, params?: any) => {
|
||||
switch (action) {
|
||||
case 'ml.privilegeCheck':
|
||||
return {
|
||||
username: 'test2',
|
||||
has_all_requested: false,
|
||||
cluster: partialClusterPrivileges,
|
||||
index: {},
|
||||
application: {},
|
||||
};
|
||||
case 'ml.info':
|
||||
return { upgrade_mode: false };
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const upgradeWithFullPrivileges = async (action: string, params?: any) => {
|
||||
switch (action) {
|
||||
case 'ml.privilegeCheck':
|
||||
return {
|
||||
username: 'elastic',
|
||||
has_all_requested: true,
|
||||
cluster: fullClusterPrivileges,
|
||||
index: {},
|
||||
application: {},
|
||||
};
|
||||
case 'ml.info':
|
||||
return { upgrade_mode: true };
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const upgradeWithPartialPrivileges = async (action: string, params?: any) => {
|
||||
switch (action) {
|
||||
case 'ml.privilegeCheck':
|
||||
return {
|
||||
username: 'test2',
|
||||
has_all_requested: false,
|
||||
cluster: partialClusterPrivileges,
|
||||
index: {},
|
||||
application: {},
|
||||
};
|
||||
case 'ml.info':
|
||||
return { upgrade_mode: true };
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const fullClusterPrivileges = {
|
||||
'cluster:admin/xpack/ml/datafeeds/delete': true,
|
||||
'cluster:admin/xpack/ml/datafeeds/update': true,
|
||||
'cluster:admin/xpack/ml/job/forecast': true,
|
||||
'cluster:monitor/xpack/ml/job/stats/get': true,
|
||||
'cluster:admin/xpack/ml/filters/delete': true,
|
||||
'cluster:admin/xpack/ml/datafeeds/preview': true,
|
||||
'cluster:admin/xpack/ml/datafeeds/start': true,
|
||||
'cluster:admin/xpack/ml/filters/put': true,
|
||||
'cluster:admin/xpack/ml/datafeeds/stop': true,
|
||||
'cluster:monitor/xpack/ml/calendars/get': true,
|
||||
'cluster:admin/xpack/ml/filters/get': true,
|
||||
'cluster:monitor/xpack/ml/datafeeds/get': true,
|
||||
'cluster:admin/xpack/ml/filters/update': true,
|
||||
'cluster:admin/xpack/ml/calendars/events/post': true,
|
||||
'cluster:admin/xpack/ml/job/close': true,
|
||||
'cluster:monitor/xpack/ml/datafeeds/stats/get': true,
|
||||
'cluster:admin/xpack/ml/calendars/jobs/update': true,
|
||||
'cluster:admin/xpack/ml/calendars/put': true,
|
||||
'cluster:admin/xpack/ml/calendars/events/delete': true,
|
||||
'cluster:admin/xpack/ml/datafeeds/put': true,
|
||||
'cluster:admin/xpack/ml/job/open': true,
|
||||
'cluster:admin/xpack/ml/job/delete': true,
|
||||
'cluster:monitor/xpack/ml/job/get': true,
|
||||
'cluster:admin/xpack/ml/job/put': true,
|
||||
'cluster:admin/xpack/ml/job/update': true,
|
||||
'cluster:admin/xpack/ml/calendars/delete': true,
|
||||
'cluster:monitor/xpack/ml/findfilestructure': true,
|
||||
};
|
||||
|
||||
// the same as ml_user role
|
||||
const partialClusterPrivileges = {
|
||||
'cluster:admin/xpack/ml/datafeeds/delete': false,
|
||||
'cluster:admin/xpack/ml/datafeeds/update': false,
|
||||
'cluster:admin/xpack/ml/job/forecast': false,
|
||||
'cluster:monitor/xpack/ml/job/stats/get': true,
|
||||
'cluster:admin/xpack/ml/filters/delete': false,
|
||||
'cluster:admin/xpack/ml/datafeeds/preview': false,
|
||||
'cluster:admin/xpack/ml/datafeeds/start': false,
|
||||
'cluster:admin/xpack/ml/filters/put': false,
|
||||
'cluster:admin/xpack/ml/datafeeds/stop': false,
|
||||
'cluster:monitor/xpack/ml/calendars/get': true,
|
||||
'cluster:admin/xpack/ml/filters/get': false,
|
||||
'cluster:monitor/xpack/ml/datafeeds/get': true,
|
||||
'cluster:admin/xpack/ml/filters/update': false,
|
||||
'cluster:admin/xpack/ml/calendars/events/post': false,
|
||||
'cluster:admin/xpack/ml/job/close': false,
|
||||
'cluster:monitor/xpack/ml/datafeeds/stats/get': true,
|
||||
'cluster:admin/xpack/ml/calendars/jobs/update': false,
|
||||
'cluster:admin/xpack/ml/calendars/put': false,
|
||||
'cluster:admin/xpack/ml/calendars/events/delete': false,
|
||||
'cluster:admin/xpack/ml/datafeeds/put': false,
|
||||
'cluster:admin/xpack/ml/job/open': false,
|
||||
'cluster:admin/xpack/ml/job/delete': false,
|
||||
'cluster:monitor/xpack/ml/job/get': true,
|
||||
'cluster:admin/xpack/ml/job/put': false,
|
||||
'cluster:admin/xpack/ml/job/update': false,
|
||||
'cluster:admin/xpack/ml/calendars/delete': false,
|
||||
'cluster:monitor/xpack/ml/findfilestructure': true,
|
||||
};
|
|
@ -1,515 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { callWithRequestProvider } from './__mocks__/call_with_request';
|
||||
import { privilegesProvider } from './check_privileges';
|
||||
import { mlPrivileges } from './privileges';
|
||||
import { MlLicense } from '../../../common/license';
|
||||
|
||||
const mlLicenseWithSecurity = {
|
||||
isSecurityEnabled: () => true,
|
||||
isFullLicense: () => true,
|
||||
} as MlLicense;
|
||||
|
||||
const mlLicenseWithOutSecurity = {
|
||||
isSecurityEnabled: () => false,
|
||||
isFullLicense: () => true,
|
||||
} as MlLicense;
|
||||
|
||||
const mlLicenseWithOutSecurityBasicLicense = {
|
||||
isSecurityEnabled: () => false,
|
||||
isFullLicense: () => false,
|
||||
} as MlLicense;
|
||||
|
||||
const mlLicenseWithSecurityBasicLicense = {
|
||||
isSecurityEnabled: () => true,
|
||||
isFullLicense: () => false,
|
||||
} as MlLicense;
|
||||
|
||||
const mlIsEnabled = async () => true;
|
||||
const mlIsNotEnabled = async () => false;
|
||||
|
||||
describe('check_privileges', () => {
|
||||
describe('getPrivileges() - right number of capabilities', () => {
|
||||
test('es capabilities count', async done => {
|
||||
const count = mlPrivileges.cluster.length;
|
||||
expect(count).toBe(27);
|
||||
done();
|
||||
});
|
||||
|
||||
test('kibana capabilities count', async done => {
|
||||
const callWithRequest = callWithRequestProvider('partialPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithSecurity,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities } = await getPrivileges();
|
||||
const count = Object.keys(capabilities).length;
|
||||
expect(count).toBe(22);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPrivileges() with security', () => {
|
||||
test('ml_user capabilities only', async done => {
|
||||
const callWithRequest = callWithRequestProvider('partialPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithSecurity,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('full capabilities', async done => {
|
||||
const callWithRequest = callWithRequestProvider('fullPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithSecurity,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(true);
|
||||
expect(capabilities.canDeleteJob).toBe(true);
|
||||
expect(capabilities.canOpenJob).toBe(true);
|
||||
expect(capabilities.canCloseJob).toBe(true);
|
||||
expect(capabilities.canForecastJob).toBe(true);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(true);
|
||||
expect(capabilities.canUpdateJob).toBe(true);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(true);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(true);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(true);
|
||||
expect(capabilities.canDeleteCalendar).toBe(true);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(true);
|
||||
expect(capabilities.canDeleteFilter).toBe(true);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(true);
|
||||
done();
|
||||
});
|
||||
|
||||
test('upgrade in progress with full capabilities', async done => {
|
||||
const callWithRequest = callWithRequestProvider('upgradeWithFullPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithSecurity,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(true);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('upgrade in progress with partial capabilities', async done => {
|
||||
const callWithRequest = callWithRequestProvider('upgradeWithPartialPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithSecurity,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(true);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('ml_user capabilities with security with basic license', async done => {
|
||||
const callWithRequest = callWithRequestProvider('partialPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithSecurityBasicLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(false);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(false);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(false);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('full user with security with basic license', async done => {
|
||||
const callWithRequest = callWithRequestProvider('fullPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithSecurityBasicLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(false);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(false);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(false);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('full capabilities, ml disabled in space', async done => {
|
||||
const callWithRequest = callWithRequestProvider('fullPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithSecurity,
|
||||
mlIsNotEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(false);
|
||||
expect(capabilities.canGetJobs).toBe(false);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(false);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(false);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(false);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPrivileges() without security', () => {
|
||||
test('ml_user capabilities only', async done => {
|
||||
const callWithRequest = callWithRequestProvider('partialPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithOutSecurity,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(true);
|
||||
expect(capabilities.canDeleteJob).toBe(true);
|
||||
expect(capabilities.canOpenJob).toBe(true);
|
||||
expect(capabilities.canCloseJob).toBe(true);
|
||||
expect(capabilities.canForecastJob).toBe(true);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(true);
|
||||
expect(capabilities.canUpdateJob).toBe(true);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(true);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(true);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(true);
|
||||
expect(capabilities.canDeleteCalendar).toBe(true);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(true);
|
||||
expect(capabilities.canDeleteFilter).toBe(true);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(true);
|
||||
done();
|
||||
});
|
||||
|
||||
test('upgrade in progress with full capabilities', async done => {
|
||||
const callWithRequest = callWithRequestProvider('upgradeWithFullPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithOutSecurity,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(true);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('upgrade in progress with partial capabilities', async done => {
|
||||
const callWithRequest = callWithRequestProvider('upgradeWithPartialPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithOutSecurity,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(true);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(true);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(true);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(true);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(true);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(true);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('ml_user capabilities without security with basic license', async done => {
|
||||
const callWithRequest = callWithRequestProvider('partialPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithOutSecurityBasicLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(false);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(false);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(false);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('full user without security with basic license', async done => {
|
||||
const callWithRequest = callWithRequestProvider('fullPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithOutSecurityBasicLicense,
|
||||
mlIsEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(true);
|
||||
expect(capabilities.canGetJobs).toBe(false);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(false);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(false);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(true);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('ml_user capabilities only, ml disabled in space', async done => {
|
||||
const callWithRequest = callWithRequestProvider('partialPrivileges');
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
callWithRequest,
|
||||
mlLicenseWithOutSecurity,
|
||||
mlIsNotEnabled
|
||||
);
|
||||
const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getPrivileges();
|
||||
expect(upgradeInProgress).toBe(false);
|
||||
expect(mlFeatureEnabledInSpace).toBe(false);
|
||||
expect(capabilities.canGetJobs).toBe(false);
|
||||
expect(capabilities.canCreateJob).toBe(false);
|
||||
expect(capabilities.canDeleteJob).toBe(false);
|
||||
expect(capabilities.canOpenJob).toBe(false);
|
||||
expect(capabilities.canCloseJob).toBe(false);
|
||||
expect(capabilities.canForecastJob).toBe(false);
|
||||
expect(capabilities.canGetDatafeeds).toBe(false);
|
||||
expect(capabilities.canStartStopDatafeed).toBe(false);
|
||||
expect(capabilities.canUpdateJob).toBe(false);
|
||||
expect(capabilities.canUpdateDatafeed).toBe(false);
|
||||
expect(capabilities.canPreviewDatafeed).toBe(false);
|
||||
expect(capabilities.canGetCalendars).toBe(false);
|
||||
expect(capabilities.canCreateCalendar).toBe(false);
|
||||
expect(capabilities.canDeleteCalendar).toBe(false);
|
||||
expect(capabilities.canGetFilters).toBe(false);
|
||||
expect(capabilities.canCreateFilter).toBe(false);
|
||||
expect(capabilities.canDeleteFilter).toBe(false);
|
||||
expect(capabilities.canFindFileStructure).toBe(false);
|
||||
expect(capabilities.canGetDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canDeleteDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canCreateDataFrameAnalytics).toBe(false);
|
||||
expect(capabilities.canStartStopDataFrameAnalytics).toBe(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,269 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { IScopedClusterClient } from 'kibana/server';
|
||||
import { Privileges, getDefaultPrivileges } from '../../../common/types/privileges';
|
||||
import { upgradeCheckProvider } from './upgrade';
|
||||
import { MlLicense } from '../../../common/license';
|
||||
|
||||
import { mlPrivileges } from './privileges';
|
||||
|
||||
type ClusterPrivilege = Record<string, boolean>;
|
||||
|
||||
export interface MlCapabilities {
|
||||
capabilities: Privileges;
|
||||
upgradeInProgress: boolean;
|
||||
isPlatinumOrTrialLicense: boolean;
|
||||
mlFeatureEnabledInSpace: boolean;
|
||||
}
|
||||
|
||||
export function privilegesProvider(
|
||||
callAsCurrentUser: IScopedClusterClient['callAsCurrentUser'],
|
||||
mlLicense: MlLicense,
|
||||
isMlEnabledInSpace: () => Promise<boolean>,
|
||||
ignoreSpaces: boolean = false
|
||||
) {
|
||||
const { isUpgradeInProgress } = upgradeCheckProvider(callAsCurrentUser);
|
||||
async function getPrivileges(): Promise<MlCapabilities> {
|
||||
// get the default privileges, forced to be false.
|
||||
const privileges = getDefaultPrivileges();
|
||||
|
||||
const upgradeInProgress = await isUpgradeInProgress();
|
||||
const isSecurityEnabled = mlLicense.isSecurityEnabled();
|
||||
|
||||
const isPlatinumOrTrialLicense = mlLicense.isFullLicense();
|
||||
const mlFeatureEnabledInSpace = await isMlEnabledInSpace();
|
||||
|
||||
const setGettingPrivileges = isPlatinumOrTrialLicense
|
||||
? setFullGettingPrivileges
|
||||
: setBasicGettingPrivileges;
|
||||
|
||||
const setActionPrivileges = isPlatinumOrTrialLicense
|
||||
? setFullActionPrivileges
|
||||
: setBasicActionPrivileges;
|
||||
|
||||
if (mlFeatureEnabledInSpace === false && ignoreSpaces === false) {
|
||||
// if ML isn't enabled in the current space,
|
||||
// return with the default privileges (all false)
|
||||
return {
|
||||
capabilities: privileges,
|
||||
upgradeInProgress,
|
||||
isPlatinumOrTrialLicense,
|
||||
mlFeatureEnabledInSpace,
|
||||
};
|
||||
}
|
||||
|
||||
if (isSecurityEnabled === false) {
|
||||
if (upgradeInProgress === true) {
|
||||
// if security is disabled and an upgrade in is progress,
|
||||
// force all "getting" privileges to be true
|
||||
// leaving all "setting" privileges to be the default false
|
||||
setGettingPrivileges({}, privileges, true);
|
||||
} else {
|
||||
// if no upgrade is in progress,
|
||||
// get all privileges forced to true
|
||||
setGettingPrivileges({}, privileges, true);
|
||||
setActionPrivileges({}, privileges, true);
|
||||
}
|
||||
} else {
|
||||
// security enabled
|
||||
// load all ml privileges for this user.
|
||||
const { cluster } = await callAsCurrentUser('ml.privilegeCheck', { body: mlPrivileges });
|
||||
setGettingPrivileges(cluster, privileges);
|
||||
if (upgradeInProgress === false) {
|
||||
// if an upgrade is in progress, don't apply the "setting"
|
||||
// privileges. leave them to be the default false.
|
||||
setActionPrivileges(cluster, privileges);
|
||||
}
|
||||
}
|
||||
return {
|
||||
capabilities: privileges,
|
||||
upgradeInProgress,
|
||||
isPlatinumOrTrialLicense,
|
||||
mlFeatureEnabledInSpace,
|
||||
};
|
||||
}
|
||||
return { getPrivileges };
|
||||
}
|
||||
|
||||
function setFullGettingPrivileges(
|
||||
cluster: ClusterPrivilege = {},
|
||||
privileges: Privileges,
|
||||
forceTrue = false
|
||||
) {
|
||||
// Anomaly Detection
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:monitor/xpack/ml/job/get'] &&
|
||||
cluster['cluster:monitor/xpack/ml/job/stats/get'])
|
||||
) {
|
||||
privileges.canGetJobs = true;
|
||||
}
|
||||
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:monitor/xpack/ml/datafeeds/get'] &&
|
||||
cluster['cluster:monitor/xpack/ml/datafeeds/stats/get'])
|
||||
) {
|
||||
privileges.canGetDatafeeds = true;
|
||||
}
|
||||
|
||||
// Calendars
|
||||
if (forceTrue || cluster['cluster:monitor/xpack/ml/calendars/get']) {
|
||||
privileges.canGetCalendars = true;
|
||||
}
|
||||
|
||||
// Filters
|
||||
if (forceTrue || cluster['cluster:admin/xpack/ml/filters/get']) {
|
||||
privileges.canGetFilters = true;
|
||||
}
|
||||
|
||||
// File Data Visualizer
|
||||
if (forceTrue || cluster['cluster:monitor/xpack/ml/findfilestructure']) {
|
||||
privileges.canFindFileStructure = true;
|
||||
}
|
||||
|
||||
// Data Frame Analytics
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:monitor/xpack/ml/job/get'] &&
|
||||
cluster['cluster:monitor/xpack/ml/job/stats/get'])
|
||||
) {
|
||||
privileges.canGetDataFrameAnalytics = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setFullActionPrivileges(
|
||||
cluster: ClusterPrivilege = {},
|
||||
privileges: Privileges,
|
||||
forceTrue = false
|
||||
) {
|
||||
// Anomaly Detection
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/job/put'] &&
|
||||
cluster['cluster:admin/xpack/ml/job/open'] &&
|
||||
cluster['cluster:admin/xpack/ml/datafeeds/put'])
|
||||
) {
|
||||
privileges.canCreateJob = true;
|
||||
}
|
||||
|
||||
if (forceTrue || cluster['cluster:admin/xpack/ml/job/update']) {
|
||||
privileges.canUpdateJob = true;
|
||||
}
|
||||
|
||||
if (forceTrue || cluster['cluster:admin/xpack/ml/job/open']) {
|
||||
privileges.canOpenJob = true;
|
||||
}
|
||||
|
||||
if (forceTrue || cluster['cluster:admin/xpack/ml/job/close']) {
|
||||
privileges.canCloseJob = true;
|
||||
}
|
||||
|
||||
if (forceTrue || cluster['cluster:admin/xpack/ml/job/forecast']) {
|
||||
privileges.canForecastJob = true;
|
||||
}
|
||||
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/job/delete'] &&
|
||||
cluster['cluster:admin/xpack/ml/datafeeds/delete'])
|
||||
) {
|
||||
privileges.canDeleteJob = true;
|
||||
}
|
||||
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/job/open'] &&
|
||||
cluster['cluster:admin/xpack/ml/datafeeds/start'] &&
|
||||
cluster['cluster:admin/xpack/ml/datafeeds/stop'])
|
||||
) {
|
||||
privileges.canStartStopDatafeed = true;
|
||||
}
|
||||
|
||||
if (forceTrue || cluster['cluster:admin/xpack/ml/datafeeds/update']) {
|
||||
privileges.canUpdateDatafeed = true;
|
||||
}
|
||||
|
||||
if (forceTrue || cluster['cluster:admin/xpack/ml/datafeeds/preview']) {
|
||||
privileges.canPreviewDatafeed = true;
|
||||
}
|
||||
|
||||
// Calendars
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/calendars/put'] &&
|
||||
cluster['cluster:admin/xpack/ml/calendars/jobs/update'] &&
|
||||
cluster['cluster:admin/xpack/ml/calendars/events/post'])
|
||||
) {
|
||||
privileges.canCreateCalendar = true;
|
||||
}
|
||||
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/calendars/delete'] &&
|
||||
cluster['cluster:admin/xpack/ml/calendars/events/delete'])
|
||||
) {
|
||||
privileges.canDeleteCalendar = true;
|
||||
}
|
||||
|
||||
// Filters
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/filters/put'] &&
|
||||
cluster['cluster:admin/xpack/ml/filters/update'])
|
||||
) {
|
||||
privileges.canCreateFilter = true;
|
||||
}
|
||||
|
||||
if (forceTrue || cluster['cluster:admin/xpack/ml/filters/delete']) {
|
||||
privileges.canDeleteFilter = true;
|
||||
}
|
||||
|
||||
// Data Frame Analytics
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/job/put'] &&
|
||||
cluster['cluster:admin/xpack/ml/job/open'] &&
|
||||
cluster['cluster:admin/xpack/ml/datafeeds/put'])
|
||||
) {
|
||||
privileges.canCreateDataFrameAnalytics = true;
|
||||
}
|
||||
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/job/delete'] &&
|
||||
cluster['cluster:admin/xpack/ml/datafeeds/delete'])
|
||||
) {
|
||||
privileges.canDeleteDataFrameAnalytics = true;
|
||||
}
|
||||
|
||||
if (
|
||||
forceTrue ||
|
||||
(cluster['cluster:admin/xpack/ml/job/open'] &&
|
||||
cluster['cluster:admin/xpack/ml/datafeeds/start'] &&
|
||||
cluster['cluster:admin/xpack/ml/datafeeds/stop'])
|
||||
) {
|
||||
privileges.canStartStopDataFrameAnalytics = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setBasicGettingPrivileges(
|
||||
cluster: ClusterPrivilege = {},
|
||||
privileges: Privileges,
|
||||
forceTrue = false
|
||||
) {
|
||||
// File Data Visualizer
|
||||
if (forceTrue || cluster['cluster:monitor/xpack/ml/findfilestructure']) {
|
||||
privileges.canFindFileStructure = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setBasicActionPrivileges(
|
||||
cluster: ClusterPrivilege = {},
|
||||
privileges: Privileges,
|
||||
forceTrue = false
|
||||
) {}
|
|
@ -1,37 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const mlPrivileges = {
|
||||
cluster: [
|
||||
'cluster:monitor/xpack/ml/job/get',
|
||||
'cluster:monitor/xpack/ml/job/stats/get',
|
||||
'cluster:monitor/xpack/ml/datafeeds/get',
|
||||
'cluster:monitor/xpack/ml/datafeeds/stats/get',
|
||||
'cluster:monitor/xpack/ml/calendars/get',
|
||||
'cluster:admin/xpack/ml/job/put',
|
||||
'cluster:admin/xpack/ml/job/delete',
|
||||
'cluster:admin/xpack/ml/job/update',
|
||||
'cluster:admin/xpack/ml/job/open',
|
||||
'cluster:admin/xpack/ml/job/close',
|
||||
'cluster:admin/xpack/ml/job/forecast',
|
||||
'cluster:admin/xpack/ml/datafeeds/put',
|
||||
'cluster:admin/xpack/ml/datafeeds/delete',
|
||||
'cluster:admin/xpack/ml/datafeeds/start',
|
||||
'cluster:admin/xpack/ml/datafeeds/stop',
|
||||
'cluster:admin/xpack/ml/datafeeds/update',
|
||||
'cluster:admin/xpack/ml/datafeeds/preview',
|
||||
'cluster:admin/xpack/ml/calendars/put',
|
||||
'cluster:admin/xpack/ml/calendars/delete',
|
||||
'cluster:admin/xpack/ml/calendars/jobs/update',
|
||||
'cluster:admin/xpack/ml/calendars/events/post',
|
||||
'cluster:admin/xpack/ml/calendars/events/delete',
|
||||
'cluster:admin/xpack/ml/filters/put',
|
||||
'cluster:admin/xpack/ml/filters/get',
|
||||
'cluster:admin/xpack/ml/filters/update',
|
||||
'cluster:admin/xpack/ml/filters/delete',
|
||||
'cluster:monitor/xpack/ml/findfilestructure',
|
||||
],
|
||||
};
|
|
@ -7,14 +7,18 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
Plugin,
|
||||
IScopedClusterClient,
|
||||
KibanaRequest,
|
||||
Logger,
|
||||
PluginInitializerContext,
|
||||
ICustomClusterClient,
|
||||
CapabilitiesStart,
|
||||
} from 'kibana/server';
|
||||
import { PluginsSetup, RouteInitialization } from './types';
|
||||
import { PLUGIN_ID, PLUGIN_ICON } from '../common/constants/app';
|
||||
import { MlCapabilities } from '../common/types/capabilities';
|
||||
|
||||
import { elasticsearchJsPlugin } from './client/elasticsearch_ml';
|
||||
import { initMlTelemetry } from './lib/telemetry';
|
||||
|
@ -41,6 +45,8 @@ import { systemRoutes } from './routes/system';
|
|||
import { MlLicense } from '../common/license';
|
||||
import { MlServerLicense } from './lib/license';
|
||||
import { createSharedServices, SharedServices } from './shared_services';
|
||||
import { userMlCapabilities, adminMlCapabilities } from '../common/types/capabilities';
|
||||
import { setupCapabilitiesSwitcher } from './lib/capabilities';
|
||||
|
||||
declare module 'kibana/server' {
|
||||
interface RequestHandlerContext {
|
||||
|
@ -59,6 +65,7 @@ export class MlServerPlugin implements Plugin<MlPluginSetup, MlPluginStart, Plug
|
|||
private log: Logger;
|
||||
private version: string;
|
||||
private mlLicense: MlServerLicense;
|
||||
private capabilities: CapabilitiesStart | null = null;
|
||||
|
||||
constructor(ctx: PluginInitializerContext) {
|
||||
this.log = ctx.logger.get();
|
||||
|
@ -67,6 +74,9 @@ export class MlServerPlugin implements Plugin<MlPluginSetup, MlPluginStart, Plug
|
|||
}
|
||||
|
||||
public setup(coreSetup: CoreSetup, plugins: PluginsSetup): MlPluginSetup {
|
||||
const userMlCapabilitiesKeys = Object.keys(userMlCapabilities);
|
||||
const adminMlCapabilitiesKeys = Object.keys(adminMlCapabilities);
|
||||
|
||||
plugins.features.registerFeature({
|
||||
id: PLUGIN_ID,
|
||||
name: i18n.translate('xpack.ml.featureRegistry.mlFeatureName', {
|
||||
|
@ -93,7 +103,7 @@ export class MlServerPlugin implements Plugin<MlPluginSetup, MlPluginStart, Plug
|
|||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
ui: userMlCapabilitiesKeys,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -105,7 +115,7 @@ export class MlServerPlugin implements Plugin<MlPluginSetup, MlPluginStart, Plug
|
|||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
ui: [...adminMlCapabilitiesKeys, ...userMlCapabilitiesKeys],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -116,6 +126,9 @@ export class MlServerPlugin implements Plugin<MlPluginSetup, MlPluginStart, Plug
|
|||
(mlLicense: MlLicense) => initSampleDataSets(mlLicense, plugins),
|
||||
]);
|
||||
|
||||
// initialize capabilities switcher to add license filter to ml capabilities
|
||||
setupCapabilitiesSwitcher(coreSetup, plugins.licensing.license$, this.log);
|
||||
|
||||
// Can access via router's handler function 'context' parameter - context.ml.mlClient
|
||||
const mlClient = coreSetup.elasticsearch.createClient(PLUGIN_ID, {
|
||||
plugins: [elasticsearchJsPlugin],
|
||||
|
@ -132,6 +145,14 @@ export class MlServerPlugin implements Plugin<MlPluginSetup, MlPluginStart, Plug
|
|||
mlLicense: this.mlLicense,
|
||||
};
|
||||
|
||||
const resolveMlCapabilities = async (request: KibanaRequest) => {
|
||||
if (this.capabilities === null) {
|
||||
return null;
|
||||
}
|
||||
const capabilities = await this.capabilities.resolveCapabilities(request);
|
||||
return capabilities.ml as MlCapabilities;
|
||||
};
|
||||
|
||||
annotationRoutes(routeInit, plugins.security);
|
||||
calendars(routeInit);
|
||||
dataFeedRoutes(routeInit);
|
||||
|
@ -144,24 +165,27 @@ export class MlServerPlugin implements Plugin<MlPluginSetup, MlPluginStart, Plug
|
|||
indicesRoutes(routeInit);
|
||||
jobAuditMessagesRoutes(routeInit);
|
||||
jobRoutes(routeInit);
|
||||
jobServiceRoutes(routeInit);
|
||||
jobServiceRoutes(routeInit, { resolveMlCapabilities });
|
||||
notificationRoutes(routeInit);
|
||||
resultsServiceRoutes(routeInit);
|
||||
jobValidationRoutes(routeInit, this.version);
|
||||
systemRoutes(routeInit, {
|
||||
spaces: plugins.spaces,
|
||||
cloud: plugins.cloud,
|
||||
resolveMlCapabilities,
|
||||
});
|
||||
initMlServerLog({ log: this.log });
|
||||
initMlTelemetry(coreSetup, plugins.usageCollection);
|
||||
|
||||
return {
|
||||
...createSharedServices(this.mlLicense, plugins.spaces, plugins.cloud),
|
||||
...createSharedServices(this.mlLicense, plugins.spaces, plugins.cloud, resolveMlCapabilities),
|
||||
mlClient,
|
||||
};
|
||||
}
|
||||
|
||||
public start(): MlPluginStart {}
|
||||
public start(coreStart: CoreStart): MlPluginStart {
|
||||
this.capabilities = coreStart.capabilities;
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.mlLicense.unsubscribe();
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
"GetPartitionFieldsValues",
|
||||
|
||||
"Modules",
|
||||
"DataRecognizer",
|
||||
"RecognizeIndex",
|
||||
"GetModule",
|
||||
"SetupModule",
|
||||
|
@ -100,7 +101,7 @@
|
|||
|
||||
"SystemRoutes",
|
||||
"HasPrivileges",
|
||||
"MlCapabilities",
|
||||
"MlCapabilitiesResponse",
|
||||
"MlNodeCount",
|
||||
"MlInfo",
|
||||
"MlEsSearch",
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
import Boom from 'boom';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IScopedClusterClient } from 'kibana/server';
|
||||
import { KibanaRequest } from 'kibana/server';
|
||||
import { wrapError } from '../client/error_wrapper';
|
||||
import { RouteInitialization } from '../types';
|
||||
import { RouteInitialization, JobServiceRouteDeps } from '../types';
|
||||
import {
|
||||
categorizationFieldExamplesSchema,
|
||||
chartSchema,
|
||||
|
@ -27,24 +27,17 @@ import { categorizationExamplesProvider } from '../models/job_service/new_job';
|
|||
/**
|
||||
* Routes for job service
|
||||
*/
|
||||
export function jobServiceRoutes({ router, mlLicense }: RouteInitialization) {
|
||||
async function hasPermissionToCreateJobs(
|
||||
callAsCurrentUser: IScopedClusterClient['callAsCurrentUser']
|
||||
) {
|
||||
if (mlLicense.isSecurityEnabled() === false) {
|
||||
return true;
|
||||
export function jobServiceRoutes(
|
||||
{ router, mlLicense }: RouteInitialization,
|
||||
{ resolveMlCapabilities }: JobServiceRouteDeps
|
||||
) {
|
||||
async function hasPermissionToCreateJobs(request: KibanaRequest) {
|
||||
const mlCapabilities = await resolveMlCapabilities(request);
|
||||
if (mlCapabilities === null) {
|
||||
throw new Error('resolveMlCapabilities is not defined');
|
||||
}
|
||||
|
||||
const resp = await callAsCurrentUser('ml.privilegeCheck', {
|
||||
body: {
|
||||
cluster: [
|
||||
'cluster:admin/xpack/ml/job/put',
|
||||
'cluster:admin/xpack/ml/job/open',
|
||||
'cluster:admin/xpack/ml/datafeeds/put',
|
||||
],
|
||||
},
|
||||
});
|
||||
return resp.has_all_requested;
|
||||
return mlCapabilities.canCreateJob;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -595,7 +588,7 @@ export function jobServiceRoutes({ router, mlLicense }: RouteInitialization) {
|
|||
try {
|
||||
// due to the use of the _analyze endpoint which is called by the kibana user,
|
||||
// basic job creation privileges are required to use this endpoint
|
||||
if ((await hasPermissionToCreateJobs(context.ml!.mlClient.callAsCurrentUser)) === false) {
|
||||
if ((await hasPermissionToCreateJobs(request)) === false) {
|
||||
throw Boom.forbidden(
|
||||
'Insufficient privileges, the machine_learning_admin role is required.'
|
||||
);
|
||||
|
|
|
@ -10,7 +10,7 @@ import { Request } from 'hapi';
|
|||
import { RequestHandlerContext } from 'kibana/server';
|
||||
import { wrapError } from '../client/error_wrapper';
|
||||
import { mlLog } from '../client/log';
|
||||
import { privilegesProvider } from '../lib/check_privileges';
|
||||
import { capabilitiesProvider } from '../lib/capabilities';
|
||||
import { spacesUtilsProvider } from '../lib/spaces_utils';
|
||||
import { RouteInitialization, SystemRouteDeps } from '../types';
|
||||
|
||||
|
@ -19,7 +19,7 @@ import { RouteInitialization, SystemRouteDeps } from '../types';
|
|||
*/
|
||||
export function systemRoutes(
|
||||
{ router, mlLicense }: RouteInitialization,
|
||||
{ spaces, cloud }: SystemRouteDeps
|
||||
{ spaces, cloud, resolveMlCapabilities }: SystemRouteDeps
|
||||
) {
|
||||
async function getNodeCount(context: RequestHandlerContext) {
|
||||
const filterPath = 'nodes.*.attributes';
|
||||
|
@ -103,35 +103,35 @@ export function systemRoutes(
|
|||
* @apiGroup SystemRoutes
|
||||
*
|
||||
* @api {get} /api/ml/ml_capabilities Check ML capabilities
|
||||
* @apiName MlCapabilities
|
||||
* @apiName MlCapabilitiesResponse
|
||||
* @apiDescription Checks ML capabilities
|
||||
*/
|
||||
router.get(
|
||||
{
|
||||
path: '/api/ml/ml_capabilities',
|
||||
validate: {
|
||||
query: schema.object({
|
||||
ignoreSpaces: schema.maybe(schema.string()),
|
||||
}),
|
||||
},
|
||||
validate: false,
|
||||
},
|
||||
mlLicense.basicLicenseAPIGuard(async (context, request, response) => {
|
||||
try {
|
||||
const ignoreSpaces = request.query && request.query.ignoreSpaces === 'true';
|
||||
// if spaces is disabled force isMlEnabledInSpace to be true
|
||||
const { isMlEnabledInSpace } =
|
||||
spaces !== undefined
|
||||
? spacesUtilsProvider(spaces, (request as unknown) as Request)
|
||||
: { isMlEnabledInSpace: async () => true };
|
||||
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
const mlCapabilities = await resolveMlCapabilities(request);
|
||||
if (mlCapabilities === null) {
|
||||
return response.customError(wrapError(new Error('resolveMlCapabilities is not defined')));
|
||||
}
|
||||
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
context.ml!.mlClient.callAsCurrentUser,
|
||||
mlCapabilities,
|
||||
mlLicense,
|
||||
isMlEnabledInSpace,
|
||||
ignoreSpaces
|
||||
isMlEnabledInSpace
|
||||
);
|
||||
return response.ok({
|
||||
body: await getPrivileges(),
|
||||
body: await getCapabilities(),
|
||||
});
|
||||
} catch (error) {
|
||||
return response.customError(wrapError(error));
|
||||
|
|
|
@ -4,23 +4,24 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { APICaller } from 'kibana/server';
|
||||
import { APICaller, KibanaRequest } from 'kibana/server';
|
||||
import { SearchResponse, SearchParams } from 'elasticsearch';
|
||||
import { MlServerLicense } from '../../lib/license';
|
||||
import { CloudSetup } from '../../../../cloud/server';
|
||||
import { LicenseCheck } from '../license_checks';
|
||||
import { spacesUtilsProvider, RequestFacade } from '../../lib/spaces_utils';
|
||||
import { spacesUtilsProvider } from '../../lib/spaces_utils';
|
||||
import { SpacesPluginSetup } from '../../../../spaces/server';
|
||||
import { privilegesProvider, MlCapabilities } from '../../lib/check_privileges';
|
||||
import { capabilitiesProvider } from '../../lib/capabilities';
|
||||
import { MlInfoResponse } from '../../../common/types/ml_server_info';
|
||||
import { ML_RESULTS_INDEX_PATTERN } from '../../../common/constants/index_patterns';
|
||||
import { MlCapabilitiesResponse, ResolveMlCapabilities } from '../../../common/types/capabilities';
|
||||
|
||||
export interface MlSystemProvider {
|
||||
mlSystemProvider(
|
||||
callAsCurrentUser: APICaller,
|
||||
request: RequestFacade
|
||||
request: KibanaRequest
|
||||
): {
|
||||
mlCapabilities(ignoreSpaces?: boolean): Promise<MlCapabilities>;
|
||||
mlCapabilities(): Promise<MlCapabilitiesResponse>;
|
||||
mlInfo(): Promise<MlInfoResponse>;
|
||||
mlSearch<T>(searchParams: SearchParams): Promise<SearchResponse<T>>;
|
||||
};
|
||||
|
@ -31,12 +32,13 @@ export function getMlSystemProvider(
|
|||
isFullLicense: LicenseCheck,
|
||||
mlLicense: MlServerLicense,
|
||||
spaces: SpacesPluginSetup | undefined,
|
||||
cloud: CloudSetup | undefined
|
||||
cloud: CloudSetup | undefined,
|
||||
resolveMlCapabilities: ResolveMlCapabilities
|
||||
): MlSystemProvider {
|
||||
return {
|
||||
mlSystemProvider(callAsCurrentUser: APICaller, request: RequestFacade) {
|
||||
mlSystemProvider(callAsCurrentUser: APICaller, request: KibanaRequest) {
|
||||
return {
|
||||
mlCapabilities(ignoreSpaces?: boolean) {
|
||||
async mlCapabilities() {
|
||||
isMinimumLicense();
|
||||
|
||||
const { isMlEnabledInSpace } =
|
||||
|
@ -44,13 +46,18 @@ export function getMlSystemProvider(
|
|||
? spacesUtilsProvider(spaces, request)
|
||||
: { isMlEnabledInSpace: async () => true };
|
||||
|
||||
const { getPrivileges } = privilegesProvider(
|
||||
const mlCapabilities = await resolveMlCapabilities(request);
|
||||
if (mlCapabilities === null) {
|
||||
throw new Error('resolveMlCapabilities is not defined');
|
||||
}
|
||||
|
||||
const { getCapabilities } = capabilitiesProvider(
|
||||
callAsCurrentUser,
|
||||
mlCapabilities,
|
||||
mlLicense,
|
||||
isMlEnabledInSpace,
|
||||
ignoreSpaces
|
||||
isMlEnabledInSpace
|
||||
);
|
||||
return getPrivileges();
|
||||
return getCapabilities();
|
||||
},
|
||||
async mlInfo(): Promise<MlInfoResponse> {
|
||||
isMinimumLicense();
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
AnomalyDetectorsProvider,
|
||||
getAnomalyDetectorsProvider,
|
||||
} from './providers/anomaly_detectors';
|
||||
import { ResolveMlCapabilities } from '../../common/types/capabilities';
|
||||
|
||||
export type SharedServices = JobServiceProvider &
|
||||
AnomalyDetectorsProvider &
|
||||
|
@ -27,14 +28,22 @@ export type SharedServices = JobServiceProvider &
|
|||
export function createSharedServices(
|
||||
mlLicense: MlServerLicense,
|
||||
spaces: SpacesPluginSetup | undefined,
|
||||
cloud: CloudSetup
|
||||
cloud: CloudSetup,
|
||||
resolveMlCapabilities: ResolveMlCapabilities
|
||||
): SharedServices {
|
||||
const { isFullLicense, isMinimumLicense } = licenseChecks(mlLicense);
|
||||
|
||||
return {
|
||||
...getJobServiceProvider(isFullLicense),
|
||||
...getAnomalyDetectorsProvider(isFullLicense),
|
||||
...getMlSystemProvider(isMinimumLicense, isFullLicense, mlLicense, spaces, cloud),
|
||||
...getMlSystemProvider(
|
||||
isMinimumLicense,
|
||||
isFullLicense,
|
||||
mlLicense,
|
||||
spaces,
|
||||
cloud,
|
||||
resolveMlCapabilities
|
||||
),
|
||||
...getModulesProvider(isFullLicense),
|
||||
...getResultsServiceProvider(isFullLicense),
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ import { PluginSetupContract as FeaturesPluginSetup } from '../../features/serve
|
|||
import { LicensingPluginSetup } from '../../licensing/server';
|
||||
import { SpacesPluginSetup } from '../../spaces/server';
|
||||
import { MlServerLicense } from './lib/license';
|
||||
import { ResolveMlCapabilities } from '../common/types/capabilities';
|
||||
|
||||
export interface LicenseCheckResult {
|
||||
isAvailable: boolean;
|
||||
|
@ -26,6 +27,11 @@ export interface LicenseCheckResult {
|
|||
export interface SystemRouteDeps {
|
||||
cloud: CloudSetup;
|
||||
spaces?: SpacesPluginSetup;
|
||||
resolveMlCapabilities: ResolveMlCapabilities;
|
||||
}
|
||||
|
||||
export interface JobServiceRouteDeps {
|
||||
resolveMlCapabilities: ResolveMlCapabilities;
|
||||
}
|
||||
|
||||
export interface PluginsSetup {
|
||||
|
|
Loading…
Reference in a new issue