mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Ingest Pipelines] Add license checks for processors (#154525)
This commit is contained in:
parent
dd083a351a
commit
aefc949911
8 changed files with 89 additions and 16 deletions
|
@ -11,6 +11,7 @@
|
||||||
"ingest_pipelines"
|
"ingest_pipelines"
|
||||||
],
|
],
|
||||||
"requiredPlugins": [
|
"requiredPlugins": [
|
||||||
|
"licensing",
|
||||||
"management",
|
"management",
|
||||||
"features",
|
"features",
|
||||||
"share",
|
"share",
|
||||||
|
|
|
@ -6,8 +6,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
|
import { licensingMock } from '@kbn/licensing-plugin/server/mocks';
|
||||||
import { setup, SetupResult } from './pipeline_processors_editor.helpers';
|
import { setup, SetupResult } from './pipeline_processors_editor.helpers';
|
||||||
import { Pipeline } from '../../../../../common/types';
|
import { Pipeline } from '../../../../../common/types';
|
||||||
|
import {
|
||||||
|
extractProcessorDetails,
|
||||||
|
getProcessorTypesAndLabels,
|
||||||
|
} from '../components/processor_form/processors/common_fields/processor_type_field';
|
||||||
|
import { mapProcessorTypeToDescriptor } from '../components/shared/map_processor_type_to_form';
|
||||||
|
|
||||||
const testProcessors: Pick<Pipeline, 'processors'> = {
|
const testProcessors: Pick<Pipeline, 'processors'> = {
|
||||||
processors: [
|
processors: [
|
||||||
|
@ -96,6 +102,28 @@ describe('Pipeline Editor', () => {
|
||||||
expect(d).toEqual({ test: { if: '1 == 1' } });
|
expect(d).toEqual({ test: { if: '1 == 1' } });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Shows inference and redact processors for licenses > platinum', async () => {
|
||||||
|
const basicLicense = licensingMock.createLicense({
|
||||||
|
license: { status: 'active', type: 'basic' },
|
||||||
|
});
|
||||||
|
const platinumLicense = licensingMock.createLicense({
|
||||||
|
license: { status: 'active', type: 'platinum' },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get the list of processors that are only available for platinum licenses
|
||||||
|
const processorsForPlatinumLicense = extractProcessorDetails(mapProcessorTypeToDescriptor)
|
||||||
|
.filter((processor) => processor.forLicenseAtLeast === 'platinum')
|
||||||
|
.map(({ value, label }) => ({ label, value }));
|
||||||
|
|
||||||
|
// Check that the list of processors for platinum licenses is not included in the list of processors for basic licenses
|
||||||
|
expect(getProcessorTypesAndLabels(basicLicense)).toEqual(
|
||||||
|
expect.not.arrayContaining(processorsForPlatinumLicense)
|
||||||
|
);
|
||||||
|
expect(getProcessorTypesAndLabels(platinumLicense)).toEqual(
|
||||||
|
expect.arrayContaining(processorsForPlatinumLicense)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('edits a processor without removing unknown processor.options', async () => {
|
it('edits a processor without removing unknown processor.options', async () => {
|
||||||
const { actions, exists, form } = testBed;
|
const { actions, exists, form } = testBed;
|
||||||
// Open the edit processor form for the set processor
|
// Open the edit processor form for the set processor
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui';
|
import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import React, { FunctionComponent, ReactNode } from 'react';
|
import React, { FunctionComponent, ReactNode, useMemo } from 'react';
|
||||||
import { flow } from 'fp-ts/lib/function';
|
import { flow } from 'fp-ts/lib/function';
|
||||||
import { map } from 'fp-ts/lib/Array';
|
import { map } from 'fp-ts/lib/Array';
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import {
|
||||||
FieldValidateResponse,
|
FieldValidateResponse,
|
||||||
VALIDATION_TYPES,
|
VALIDATION_TYPES,
|
||||||
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
|
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
|
||||||
|
import { ILicense } from '../../../../../../../types';
|
||||||
import {
|
import {
|
||||||
FIELD_TYPES,
|
FIELD_TYPES,
|
||||||
FieldConfig,
|
FieldConfig,
|
||||||
|
@ -25,11 +26,12 @@ import {
|
||||||
|
|
||||||
import { getProcessorDescriptor, mapProcessorTypeToDescriptor } from '../../../shared';
|
import { getProcessorDescriptor, mapProcessorTypeToDescriptor } from '../../../shared';
|
||||||
|
|
||||||
const extractProcessorTypesAndLabels = flow(
|
export const extractProcessorDetails = flow(
|
||||||
Object.entries,
|
Object.entries,
|
||||||
map(([type, { label }]) => ({
|
map(([type, { label, forLicenseAtLeast }]) => ({
|
||||||
label,
|
label,
|
||||||
value: type,
|
value: type,
|
||||||
|
...(forLicenseAtLeast ? { forLicenseAtLeast } : {}),
|
||||||
})),
|
})),
|
||||||
(arr) => arr.sort((a, b) => a.label.localeCompare(b.label))
|
(arr) => arr.sort((a, b) => a.label.localeCompare(b.label))
|
||||||
);
|
);
|
||||||
|
@ -39,9 +41,17 @@ interface ProcessorTypeAndLabel {
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const processorTypesAndLabels: ProcessorTypeAndLabel[] = extractProcessorTypesAndLabels(
|
export const getProcessorTypesAndLabels = (license: ILicense | null) => {
|
||||||
mapProcessorTypeToDescriptor
|
return (
|
||||||
);
|
extractProcessorDetails(mapProcessorTypeToDescriptor)
|
||||||
|
// Filter out any processors that are not available for the current license type
|
||||||
|
.filter((option) => {
|
||||||
|
return option.forLicenseAtLeast ? license?.hasAtLeast(option.forLicenseAtLeast) : true;
|
||||||
|
})
|
||||||
|
// Convert to EuiComboBox options
|
||||||
|
.map(({ value, label }) => ({ label, value }))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
initialType?: string;
|
initialType?: string;
|
||||||
|
@ -68,9 +78,12 @@ const typeConfig: FieldConfig<string> = {
|
||||||
|
|
||||||
export const ProcessorTypeField: FunctionComponent<Props> = ({ initialType }) => {
|
export const ProcessorTypeField: FunctionComponent<Props> = ({ initialType }) => {
|
||||||
const {
|
const {
|
||||||
services: { documentation },
|
services: { documentation, license },
|
||||||
} = useKibana();
|
} = useKibana();
|
||||||
const esDocUrl = documentation.getEsDocsBasePath();
|
const esDocUrl = documentation.getEsDocsBasePath();
|
||||||
|
// Some processors are only available for certain license types
|
||||||
|
const processorOptions = useMemo(() => getProcessorTypesAndLabels(license), [license]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UseField<string> config={typeConfig} defaultValue={initialType} path="type">
|
<UseField<string> config={typeConfig} defaultValue={initialType} path="type">
|
||||||
{(typeField) => {
|
{(typeField) => {
|
||||||
|
@ -128,7 +141,7 @@ export const ProcessorTypeField: FunctionComponent<Props> = ({ initialType }) =>
|
||||||
defaultMessage: 'Type and then hit "ENTER"',
|
defaultMessage: 'Type and then hit "ENTER"',
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
options={processorTypesAndLabels}
|
options={processorOptions}
|
||||||
selectedOptions={selectedOptions}
|
selectedOptions={selectedOptions}
|
||||||
onCreateOption={onCreateComboOption}
|
onCreateOption={onCreateComboOption}
|
||||||
onChange={(options: Array<EuiComboBoxOptionOption<string>>) => {
|
onChange={(options: Array<EuiComboBoxOptionOption<string>>) => {
|
||||||
|
|
|
@ -10,6 +10,8 @@ import React, { ReactNode } from 'react';
|
||||||
import { FormattedMessage } from '@kbn/i18n-react';
|
import { FormattedMessage } from '@kbn/i18n-react';
|
||||||
import { EuiCode, EuiLink } from '@elastic/eui';
|
import { EuiCode, EuiLink } from '@elastic/eui';
|
||||||
|
|
||||||
|
import { LicenseType } from '../../../../../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Append,
|
Append,
|
||||||
Bytes,
|
Bytes,
|
||||||
|
@ -69,6 +71,10 @@ interface FieldDescriptor {
|
||||||
* Default
|
* Default
|
||||||
*/
|
*/
|
||||||
getDefaultDescription: (processorOptions: Record<string, any>) => string | undefined;
|
getDefaultDescription: (processorOptions: Record<string, any>) => string | undefined;
|
||||||
|
/**
|
||||||
|
* Some processors are only available for certain license types
|
||||||
|
*/
|
||||||
|
forLicenseAtLeast?: LicenseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
type MapProcessorTypeToDescriptor = Record<string, FieldDescriptor>;
|
type MapProcessorTypeToDescriptor = Record<string, FieldDescriptor>;
|
||||||
|
@ -453,6 +459,7 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = {
|
||||||
},
|
},
|
||||||
inference: {
|
inference: {
|
||||||
FieldsComponent: Inference,
|
FieldsComponent: Inference,
|
||||||
|
forLicenseAtLeast: 'platinum',
|
||||||
docLinkPath: '/inference-processor.html',
|
docLinkPath: '/inference-processor.html',
|
||||||
label: i18n.translate('xpack.ingestPipelines.processors.label.inference', {
|
label: i18n.translate('xpack.ingestPipelines.processors.label.inference', {
|
||||||
defaultMessage: 'Inference',
|
defaultMessage: 'Inference',
|
||||||
|
@ -580,6 +587,7 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = {
|
||||||
},
|
},
|
||||||
redact: {
|
redact: {
|
||||||
FieldsComponent: Redact,
|
FieldsComponent: Redact,
|
||||||
|
forLicenseAtLeast: 'platinum',
|
||||||
docLinkPath: '/redact-processor.html',
|
docLinkPath: '/redact-processor.html',
|
||||||
label: i18n.translate('xpack.ingestPipelines.processors.label.redact', {
|
label: i18n.translate('xpack.ingestPipelines.processors.label.redact', {
|
||||||
defaultMessage: 'Redact',
|
defaultMessage: 'Redact',
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { ManagementAppMountParams } from '@kbn/management-plugin/public';
|
||||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||||
import type { FileUploadPluginStart } from '@kbn/file-upload-plugin/public';
|
import type { FileUploadPluginStart } from '@kbn/file-upload-plugin/public';
|
||||||
import { KibanaContextProvider, KibanaThemeProvider } from '../shared_imports';
|
import { KibanaContextProvider, KibanaThemeProvider } from '../shared_imports';
|
||||||
|
import { ILicense } from '../types';
|
||||||
|
|
||||||
import { API_BASE_PATH } from '../../common/constants';
|
import { API_BASE_PATH } from '../../common/constants';
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ export interface AppServices {
|
||||||
share: SharePluginStart;
|
share: SharePluginStart;
|
||||||
fileUpload: FileUploadPluginStart;
|
fileUpload: FileUploadPluginStart;
|
||||||
application: ApplicationStart;
|
application: ApplicationStart;
|
||||||
|
license: ILicense | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CoreServices {
|
export interface CoreServices {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import { CoreSetup } from '@kbn/core/public';
|
import { CoreSetup } from '@kbn/core/public';
|
||||||
import { ManagementAppMountParams } from '@kbn/management-plugin/public';
|
import { ManagementAppMountParams } from '@kbn/management-plugin/public';
|
||||||
|
|
||||||
import { StartDependencies } from '../types';
|
import { StartDependencies, ILicense } from '../types';
|
||||||
import {
|
import {
|
||||||
documentationService,
|
documentationService,
|
||||||
uiMetricService,
|
uiMetricService,
|
||||||
|
@ -18,11 +18,15 @@ import {
|
||||||
} from './services';
|
} from './services';
|
||||||
import { renderApp } from '.';
|
import { renderApp } from '.';
|
||||||
|
|
||||||
|
export interface AppParams extends ManagementAppMountParams {
|
||||||
|
license: ILicense | null;
|
||||||
|
}
|
||||||
|
|
||||||
export async function mountManagementSection(
|
export async function mountManagementSection(
|
||||||
{ http, getStartServices, notifications }: CoreSetup<StartDependencies>,
|
{ http, getStartServices, notifications }: CoreSetup<StartDependencies>,
|
||||||
params: ManagementAppMountParams
|
params: AppParams
|
||||||
) {
|
) {
|
||||||
const { element, setBreadcrumbs, history, theme$ } = params;
|
const { element, setBreadcrumbs, history, theme$, license } = params;
|
||||||
const [coreStart, depsStart] = await getStartServices();
|
const [coreStart, depsStart] = await getStartServices();
|
||||||
const {
|
const {
|
||||||
docLinks,
|
docLinks,
|
||||||
|
@ -47,6 +51,7 @@ export async function mountManagementSection(
|
||||||
fileUpload: depsStart.fileUpload,
|
fileUpload: depsStart.fileUpload,
|
||||||
application,
|
application,
|
||||||
executionContext,
|
executionContext,
|
||||||
|
license,
|
||||||
};
|
};
|
||||||
|
|
||||||
return renderApp(element, I18nContext, services, { http }, { theme$ });
|
return renderApp(element, I18nContext, services, { http }, { theme$ });
|
||||||
|
|
|
@ -6,16 +6,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { CoreSetup, Plugin } from '@kbn/core/public';
|
import { Subscription } from 'rxjs';
|
||||||
|
import { CoreStart, CoreSetup, Plugin } from '@kbn/core/public';
|
||||||
|
|
||||||
import { PLUGIN_ID } from '../common/constants';
|
import { PLUGIN_ID } from '../common/constants';
|
||||||
import { uiMetricService, apiService } from './application/services';
|
import { uiMetricService, apiService } from './application/services';
|
||||||
import { SetupDependencies, StartDependencies } from './types';
|
import { SetupDependencies, StartDependencies, ILicense } from './types';
|
||||||
import { IngestPipelinesLocatorDefinition } from './locator';
|
import { IngestPipelinesLocatorDefinition } from './locator';
|
||||||
|
|
||||||
export class IngestPipelinesPlugin
|
export class IngestPipelinesPlugin
|
||||||
implements Plugin<void, void, SetupDependencies, StartDependencies>
|
implements Plugin<void, void, SetupDependencies, StartDependencies>
|
||||||
{
|
{
|
||||||
|
private license: ILicense | null = null;
|
||||||
|
private licensingSubscription?: Subscription;
|
||||||
|
|
||||||
public setup(coreSetup: CoreSetup<StartDependencies>, plugins: SetupDependencies): void {
|
public setup(coreSetup: CoreSetup<StartDependencies>, plugins: SetupDependencies): void {
|
||||||
const { management, usageCollection, share } = plugins;
|
const { management, usageCollection, share } = plugins;
|
||||||
const { http, getStartServices } = coreSetup;
|
const { http, getStartServices } = coreSetup;
|
||||||
|
@ -42,7 +46,10 @@ export class IngestPipelinesPlugin
|
||||||
docTitle.change(pluginName);
|
docTitle.change(pluginName);
|
||||||
|
|
||||||
const { mountManagementSection } = await import('./application/mount_management_section');
|
const { mountManagementSection } = await import('./application/mount_management_section');
|
||||||
const unmountAppCallback = await mountManagementSection(coreSetup, params);
|
const unmountAppCallback = await mountManagementSection(coreSetup, {
|
||||||
|
...params,
|
||||||
|
license: this.license,
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
docTitle.reset();
|
docTitle.reset();
|
||||||
|
@ -58,7 +65,13 @@ export class IngestPipelinesPlugin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public start() {}
|
public start(core: CoreStart, { licensing }: StartDependencies) {
|
||||||
|
this.licensingSubscription = licensing?.license$.subscribe((license) => {
|
||||||
|
this.license = license;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public stop() {}
|
public stop() {
|
||||||
|
this.licensingSubscription?.unsubscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import { ManagementSetup } from '@kbn/management-plugin/public';
|
||||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||||
import { SharePluginStart, SharePluginSetup } from '@kbn/share-plugin/public';
|
import { SharePluginStart, SharePluginSetup } from '@kbn/share-plugin/public';
|
||||||
import type { FileUploadPluginStart } from '@kbn/file-upload-plugin/public';
|
import type { FileUploadPluginStart } from '@kbn/file-upload-plugin/public';
|
||||||
|
import { LicensingPluginStart } from '@kbn/licensing-plugin/public';
|
||||||
|
export type { LicenseType, ILicense } from '@kbn/licensing-plugin/public';
|
||||||
|
|
||||||
export interface SetupDependencies {
|
export interface SetupDependencies {
|
||||||
management: ManagementSetup;
|
management: ManagementSetup;
|
||||||
|
@ -19,4 +21,5 @@ export interface SetupDependencies {
|
||||||
export interface StartDependencies {
|
export interface StartDependencies {
|
||||||
share: SharePluginStart;
|
share: SharePluginStart;
|
||||||
fileUpload: FileUploadPluginStart;
|
fileUpload: FileUploadPluginStart;
|
||||||
|
licensing?: LicensingPluginStart;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue