= ({
{
field: 'packageTitle',
name: i18n.translate(
- 'xpack.ingestManager.configDetails.datasourcesTable.packageNameColumnTitle',
+ 'xpack.ingestManager.configDetails.packageConfigsTable.packageNameColumnTitle',
{
defaultMessage: 'Integration',
}
),
- render(packageTitle: string, datasource: InMemoryDatasource) {
+ render(packageTitle: string, packageConfig: InMemoryPackageConfig) {
return (
- {datasource.package && (
+ {packageConfig.package && (
@@ -159,24 +164,24 @@ export const DatasourcesTable: React.FunctionComponent = ({
{
field: 'namespace',
name: i18n.translate(
- 'xpack.ingestManager.configDetails.datasourcesTable.namespaceColumnTitle',
+ 'xpack.ingestManager.configDetails.packageConfigsTable.namespaceColumnTitle',
{
defaultMessage: 'Namespace',
}
),
- render: (namespace: InMemoryDatasource['namespace']) => {
+ render: (namespace: InMemoryPackageConfig['namespace']) => {
return namespace ? {namespace} : '';
},
},
{
field: 'streams',
name: i18n.translate(
- 'xpack.ingestManager.configDetails.datasourcesTable.streamsCountColumnTitle',
+ 'xpack.ingestManager.configDetails.packageConfigsTable.streamsCountColumnTitle',
{
defaultMessage: 'Streams',
}
),
- render: (streams: InMemoryDatasource['streams']) => {
+ render: (streams: InMemoryPackageConfig['streams']) => {
return (
<>
{streams.enabled}
@@ -187,67 +192,67 @@ export const DatasourcesTable: React.FunctionComponent = ({
},
{
name: i18n.translate(
- 'xpack.ingestManager.configDetails.datasourcesTable.actionsColumnTitle',
+ 'xpack.ingestManager.configDetails.packageConfigsTable.actionsColumnTitle',
{
defaultMessage: 'Actions',
}
),
actions: [
{
- render: (datasource: InMemoryDatasource) => (
+ render: (packageConfig: InMemoryPackageConfig) => (
{}}
- // key="datasourceView"
+ // key="packageConfigView"
// >
//
// ,
,
- // FIXME: implement Copy datasource action
- // {}} key="datasourceCopy">
+ // FIXME: implement Copy package config action
+ // {}} key="packageConfigCopy">
//
// ,
-
- {(deleteDatasourcePrompt) => {
+
+ {(deletePackageConfigsPrompt) => {
return (
{
- deleteDatasourcePrompt([datasource.id], refreshConfig);
+ deletePackageConfigsPrompt([packageConfig.id], refreshConfig);
}}
>
);
}}
- ,
+ ,
]}
/>
),
@@ -259,9 +264,9 @@ export const DatasourcesTable: React.FunctionComponent = ({
);
return (
-
+
itemId="id"
- items={datasources}
+ items={packageConfigs}
columns={columns}
sorting={{
sort: {
@@ -273,14 +278,14 @@ export const DatasourcesTable: React.FunctionComponent = ({
search={{
toolsRight: [
,
],
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/index.tsx
index eaa161d57bbe4..4ae16eb91e582 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/index.tsx
@@ -28,7 +28,7 @@ import { Loading } from '../../../components';
import { WithHeaderLayout } from '../../../layouts';
import { ConfigRefreshContext, useGetAgentStatus, AgentStatusRefreshContext } from './hooks';
import { LinkedAgentCount, AgentConfigActionMenu } from '../components';
-import { ConfigDatasourcesView, ConfigSettingsView } from './components';
+import { ConfigPackageConfigsView, ConfigSettingsView } from './components';
import { useIntraAppState } from '../../../hooks/use_intra_app_state';
const Divider = styled.div`
@@ -120,13 +120,16 @@ export const AgentConfigDetailsPage: React.FunctionComponent = () => {
},
{ isDivider: true },
{
- label: i18n.translate('xpack.ingestManager.configDetails.summary.datasources', {
- defaultMessage: 'Data sources',
+ label: i18n.translate('xpack.ingestManager.configDetails.summary.package_configs', {
+ defaultMessage: 'Integrations',
}),
content: (
),
@@ -204,12 +207,12 @@ export const AgentConfigDetailsPage: React.FunctionComponent = () => {
const headerTabs = useMemo(() => {
return [
{
- id: 'datasources',
- name: i18n.translate('xpack.ingestManager.configDetails.subTabs.datasourcesTabText', {
- defaultMessage: 'Data sources',
+ id: 'integrations',
+ name: i18n.translate('xpack.ingestManager.configDetails.subTabs.packageConfigsTabText', {
+ defaultMessage: 'Integrations',
}),
- href: getHref('configuration_details', { configId, tabId: 'datasources' }),
- isSelected: tabId === '' || tabId === 'datasources',
+ href: getHref('configuration_details', { configId, tabId: 'integrations' }),
+ isSelected: tabId === '' || tabId === 'integrations',
},
{
id: 'settings',
@@ -292,7 +295,7 @@ const AgentConfigDetailsContent: React.FunctionComponent<{ agentConfig: AgentCon
{
- return ;
+ return ;
}}
/>
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/edit_datasource_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/edit_package_config_page/index.tsx
similarity index 64%
rename from x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/edit_datasource_page/index.tsx
rename to x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/edit_package_config_page/index.tsx
index af39cb87f18c9..7fbcdbb9738cb 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/edit_datasource_page/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/edit_package_config_page/index.tsx
@@ -16,31 +16,34 @@ import {
EuiFlexItem,
EuiSpacer,
} from '@elastic/eui';
-import { AgentConfig, PackageInfo, NewDatasource } from '../../../types';
+import { AgentConfig, PackageInfo, NewPackageConfig } from '../../../types';
import {
useLink,
useBreadcrumbs,
useCore,
useConfig,
- sendUpdateDatasource,
+ sendUpdatePackageConfig,
sendGetAgentStatus,
sendGetOneAgentConfig,
- sendGetOneDatasource,
+ sendGetOnePackageConfig,
sendGetPackageInfoByKey,
} from '../../../hooks';
import { Loading, Error } from '../../../components';
import { ConfirmDeployConfigModal } from '../components';
-import { CreateDatasourcePageLayout } from '../create_datasource_page/components';
+import { CreatePackageConfigPageLayout } from '../create_package_config_page/components';
import {
- DatasourceValidationResults,
- validateDatasource,
+ PackageConfigValidationResults,
+ validatePackageConfig,
validationHasErrors,
-} from '../create_datasource_page/services';
-import { DatasourceFormState, CreateDatasourceFrom } from '../create_datasource_page/types';
-import { StepConfigureDatasource } from '../create_datasource_page/step_configure_datasource';
-import { StepDefineDatasource } from '../create_datasource_page/step_define_datasource';
+} from '../create_package_config_page/services';
+import {
+ PackageConfigFormState,
+ CreatePackageConfigFrom,
+} from '../create_package_config_page/types';
+import { StepConfigurePackage } from '../create_package_config_page/step_configure_package';
+import { StepDefinePackageConfig } from '../create_package_config_page/step_define_package_config';
-export const EditDatasourcePage: React.FunctionComponent = () => {
+export const EditPackageConfigPage: React.FunctionComponent = () => {
const {
notifications,
chrome: { getIsNavDrawerLocked$ },
@@ -50,7 +53,7 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
fleet: { enabled: isFleetEnabled },
} = useConfig();
const {
- params: { configId, datasourceId },
+ params: { configId, packageConfigId },
} = useRouteMatch();
const history = useHistory();
const { getHref, getPath } = useLink();
@@ -64,34 +67,35 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
return () => subscription.unsubscribe();
});
- // Agent config, package info, and datasource states
+ // Agent config, package info, and package config states
const [isLoadingData, setIsLoadingData] = useState(true);
const [loadingError, setLoadingError] = useState();
const [agentConfig, setAgentConfig] = useState();
const [packageInfo, setPackageInfo] = useState();
- const [datasource, setDatasource] = useState({
+ const [packageConfig, setPackageConfig] = useState({
name: '',
description: '',
+ namespace: '',
config_id: '',
enabled: true,
output_id: '',
inputs: [],
});
- // Retrieve agent config, package, and datasource info
+ // Retrieve agent config, package, and package config info
useEffect(() => {
const getData = async () => {
setIsLoadingData(true);
setLoadingError(undefined);
try {
- const [{ data: agentConfigData }, { data: datasourceData }] = await Promise.all([
+ const [{ data: agentConfigData }, { data: packageConfigData }] = await Promise.all([
sendGetOneAgentConfig(configId),
- sendGetOneDatasource(datasourceId),
+ sendGetOnePackageConfig(packageConfigId),
]);
if (agentConfigData?.item) {
setAgentConfig(agentConfigData.item);
}
- if (datasourceData?.item) {
+ if (packageConfigData?.item) {
const {
id,
revision,
@@ -100,30 +104,30 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
created_at,
updated_by,
updated_at,
- ...restOfDatasource
- } = datasourceData.item;
- // Remove `agent_stream` from all stream info, we assign this after saving
- const newDatasource = {
- ...restOfDatasource,
+ ...restOfPackageConfig
+ } = packageConfigData.item;
+ // Remove `compiled_stream` from all stream info, we assign this after saving
+ const newPackageConfig = {
+ ...restOfPackageConfig,
inputs: inputs.map((input) => {
const { streams, ...restOfInput } = input;
return {
...restOfInput,
streams: streams.map((stream) => {
- const { agent_stream, ...restOfStream } = stream;
+ const { compiled_stream, ...restOfStream } = stream;
return restOfStream;
}),
};
}),
};
- setDatasource(newDatasource);
- if (datasourceData.item.package) {
+ setPackageConfig(newPackageConfig);
+ if (packageConfigData.item.package) {
const { data: packageData } = await sendGetPackageInfoByKey(
- `${datasourceData.item.package.name}-${datasourceData.item.package.version}`
+ `${packageConfigData.item.package.name}-${packageConfigData.item.package.version}`
);
if (packageData?.response) {
setPackageInfo(packageData.response);
- setValidationResults(validateDatasource(newDatasource, packageData.response));
+ setValidationResults(validatePackageConfig(newPackageConfig, packageData.response));
setFormState('VALID');
}
}
@@ -134,7 +138,7 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
setIsLoadingData(false);
};
getData();
- }, [configId, datasourceId]);
+ }, [configId, packageConfigId]);
// Retrieve agent count
const [agentCount, setAgentCount] = useState(0);
@@ -151,21 +155,21 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
}
}, [configId, isFleetEnabled]);
- // Datasource validation state
- const [validationResults, setValidationResults] = useState();
+ // Package config validation state
+ const [validationResults, setValidationResults] = useState();
const hasErrors = validationResults ? validationHasErrors(validationResults) : false;
- // Update datasource method
- const updateDatasource = (updatedFields: Partial) => {
- const newDatasource = {
- ...datasource,
+ // Update package config method
+ const updatePackageConfig = (updatedFields: Partial) => {
+ const newPackageConfig = {
+ ...packageConfig,
...updatedFields,
};
- setDatasource(newDatasource);
+ setPackageConfig(newPackageConfig);
// eslint-disable-next-line no-console
- console.debug('Datasource updated', newDatasource);
- const newValidationResults = updateDatasourceValidation(newDatasource);
+ console.debug('Package config updated', newPackageConfig);
+ const newValidationResults = updatePackageConfigValidation(newPackageConfig);
const hasValidationErrors = newValidationResults
? validationHasErrors(newValidationResults)
: false;
@@ -174,12 +178,15 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
}
};
- const updateDatasourceValidation = (newDatasource?: NewDatasource) => {
+ const updatePackageConfigValidation = (newPackageConfig?: NewPackageConfig) => {
if (packageInfo) {
- const newValidationResult = validateDatasource(newDatasource || datasource, packageInfo);
+ const newValidationResult = validatePackageConfig(
+ newPackageConfig || packageConfig,
+ packageInfo
+ );
setValidationResults(newValidationResult);
// eslint-disable-next-line no-console
- console.debug('Datasource validation results', newValidationResult);
+ console.debug('Package config validation results', newValidationResult);
return newValidationResult;
}
@@ -188,11 +195,11 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
// Cancel url
const cancelUrl = getHref('configuration_details', { configId });
- // Save datasource
- const [formState, setFormState] = useState('INVALID');
- const saveDatasource = async () => {
+ // Save package config
+ const [formState, setFormState] = useState('INVALID');
+ const savePackageConfig = async () => {
setFormState('LOADING');
- const result = await sendUpdateDatasource(datasourceId, datasource);
+ const result = await sendUpdatePackageConfig(packageConfigId, packageConfig);
setFormState('SUBMITTED');
return result;
};
@@ -206,19 +213,19 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
setFormState('CONFIRM');
return;
}
- const { error } = await saveDatasource();
+ const { error } = await savePackageConfig();
if (!error) {
history.push(getPath('configuration_details', { configId }));
notifications.toasts.addSuccess({
- title: i18n.translate('xpack.ingestManager.editDatasource.updatedNotificationTitle', {
- defaultMessage: `Successfully updated '{datasourceName}'`,
+ title: i18n.translate('xpack.ingestManager.editPackageConfig.updatedNotificationTitle', {
+ defaultMessage: `Successfully updated '{packageConfigName}'`,
values: {
- datasourceName: datasource.name,
+ packageConfigName: packageConfig.name,
},
}),
text:
agentCount && agentConfig
- ? i18n.translate('xpack.ingestManager.editDatasource.updatedNotificationMessage', {
+ ? i18n.translate('xpack.ingestManager.editPackageConfig.updatedNotificationMessage', {
defaultMessage: `Fleet will deploy updates to all agents that use the '{agentConfigName}' configuration`,
values: {
agentConfigName: agentConfig.name,
@@ -235,28 +242,28 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
};
const layoutProps = {
- from: 'edit' as CreateDatasourceFrom,
+ from: 'edit' as CreatePackageConfigFrom,
cancelUrl,
agentConfig,
packageInfo,
};
return (
-
+
{isLoadingData ? (
) : loadingError || !agentConfig || !packageInfo ? (
}
error={
loadingError ||
- i18n.translate('xpack.ingestManager.editDatasource.errorLoadingDataMessage', {
- defaultMessage: 'There was an error loading this data source information',
+ i18n.translate('xpack.ingestManager.editPackageConfig.errorLoadingDataMessage', {
+ defaultMessage: 'There was an error loading this intergration information',
})
}
/>
@@ -275,35 +282,35 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
steps={[
{
title: i18n.translate(
- 'xpack.ingestManager.editDatasource.stepDefineDatasourceTitle',
+ 'xpack.ingestManager.editPackageConfig.stepDefinePackageConfigTitle',
{
- defaultMessage: 'Define your data source',
+ defaultMessage: 'Define your integration',
}
),
children: (
-
),
},
{
title: i18n.translate(
- 'xpack.ingestManager.editDatasource.stepConfgiureDatasourceTitle',
+ 'xpack.ingestManager.editPackageConfig.stepConfigurePackageConfigTitle',
{
defaultMessage: 'Select the data you want to collect',
}
),
children: (
-
@@ -326,7 +333,7 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
@@ -341,8 +348,8 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
fill
>
@@ -350,7 +357,7 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
>
)}
-
+
);
};
@@ -358,6 +365,6 @@ const Breadcrumb: React.FunctionComponent<{ configName: string; configId: string
configName,
configId,
}) => {
- useBreadcrumbs('edit_datasource', { configName, configId });
+ useBreadcrumbs('edit_integration', { configName, configId });
return null;
};
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/index.tsx
index 74fa67078f741..727ef23347251 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/index.tsx
@@ -9,8 +9,8 @@ import { PAGE_ROUTING_PATHS } from '../../constants';
import { useBreadcrumbs } from '../../hooks';
import { AgentConfigListPage } from './list_page';
import { AgentConfigDetailsPage } from './details_page';
-import { CreateDatasourcePage } from './create_datasource_page';
-import { EditDatasourcePage } from './edit_datasource_page';
+import { CreatePackageConfigPage } from './create_package_config_page';
+import { EditPackageConfigPage } from './edit_package_config_page';
export const AgentConfigApp: React.FunctionComponent = () => {
useBreadcrumbs('configurations');
@@ -18,11 +18,11 @@ export const AgentConfigApp: React.FunctionComponent = () => {
return (
-
-
+
+
-
-
+
+
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/components/create_config.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/components/create_config.tsx
index f746fadc4b0a3..d1abd88adba86 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/components/create_config.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/components/create_config.tsx
@@ -64,7 +64,7 @@ export const CreateAgentConfigFlyout: React.FunctionComponent = ({ onClos
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/index.tsx
index 8b1ff0988d443..0a9daf0038aab 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/index.tsx
@@ -176,12 +176,13 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
),
},
{
- field: 'datasources',
- name: i18n.translate('xpack.ingestManager.agentConfigList.datasourcesCountColumnTitle', {
- defaultMessage: 'Data sources',
+ field: 'package_configs',
+ name: i18n.translate('xpack.ingestManager.agentConfigList.packageConfigsCountColumnTitle', {
+ defaultMessage: 'Integrations',
}),
dataType: 'number',
- render: (datasources: AgentConfig['datasources']) => (datasources ? datasources.length : 0),
+ render: (packageConfigs: AgentConfig['package_configs']) =>
+ packageConfigs ? packageConfigs.length : 0,
},
{
name: i18n.translate('xpack.ingestManager.agentConfigList.actionsColumnTitle', {
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/index.tsx
index ca1a8df534044..cb0664143bb34 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/index.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/index.tsx
@@ -8,7 +8,7 @@ import React from 'react';
import { HashRouter as Router, Switch, Route } from 'react-router-dom';
import { PAGE_ROUTING_PATHS } from '../../constants';
import { useConfig, useBreadcrumbs } from '../../hooks';
-import { CreateDatasourcePage } from '../agent_config/create_datasource_page';
+import { CreatePackageConfigPage } from '../agent_config/create_package_config_page';
import { EPMHomePage } from './screens/home';
import { Detail } from './screens/detail';
@@ -19,8 +19,8 @@ export const EPMApp: React.FunctionComponent = () => {
return epm.enabled ? (
-
-
+
+
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/content.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/content.tsx
index 96aebb08e0c63..c9a8cabdf414b 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/content.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/content.tsx
@@ -4,17 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
+import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { DEFAULT_PANEL, DetailParams } from '.';
import { PackageInfo } from '../../../../types';
import { AssetsFacetGroup } from '../../components/assets_facet_group';
-import { Requirements } from '../../components/requirements';
import { CenterColumn, LeftColumn, RightColumn } from './layout';
import { OverviewPanel } from './overview_panel';
import { SideNavLinks } from './side_nav_links';
-import { DataSourcesPanel } from './data_sources_panel';
+import { PackageConfigsPanel } from './package_configs_panel';
import { SettingsPanel } from './settings_panel';
type ContentProps = PackageInfo & Pick & { hasIconPanel: boolean };
@@ -63,8 +62,8 @@ export function ContentPanel(props: ContentPanelProps) {
latestVersion={latestVersion}
/>
);
- case 'data-sources':
- return ;
+ case 'usages':
+ return ;
case 'overview':
default:
return ;
@@ -73,17 +72,11 @@ export function ContentPanel(props: ContentPanelProps) {
type RightColumnContentProps = PackageInfo & Pick;
function RightColumnContent(props: RightColumnContentProps) {
- const { assets, requirement, panel } = props;
+ const { assets, panel } = props;
switch (panel) {
case 'overview':
return (
-
-
-
-
-
-
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx
index db046d18ccebc..875a8f5c5c127 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx
@@ -70,10 +70,10 @@ export function Header(props: HeaderProps) {
{
+export const PackageConfigsPanel = ({ name, version }: PackageConfigsPanelProps) => {
const { getPath } = useLink();
const getPackageInstallStatus = useGetPackageInstallStatus();
const packageInstallStatus = getPackageInstallStatus(name);
@@ -23,11 +22,5 @@ export const DataSourcesPanel = ({ name, version }: DataSourcesPanelProps) => {
// this happens if they arrive with a direct url or they uninstall while on this tab
if (packageInstallStatus.status !== InstallStatus.installed)
return ;
- return (
-
-
- Data Sources
-
-
- );
+ return null;
};
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx
index 986b946131e33..125289ce3ee8d 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx
@@ -10,8 +10,8 @@ import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import { EuiSpacer } from '@elastic/eui';
import styled from 'styled-components';
import { InstallStatus, PackageInfo } from '../../../../types';
-import { useGetDatasources } from '../../../../hooks';
-import { DATASOURCE_SAVED_OBJECT_TYPE } from '../../../../constants';
+import { useGetPackageConfigs } from '../../../../hooks';
+import { PACKAGE_CONFIG_SAVED_OBJECT_TYPE } from '../../../../constants';
import { useGetPackageInstallStatus } from '../../hooks';
import { InstallationButton } from './installation_button';
import { UpdateIcon } from '../../components/icons';
@@ -46,13 +46,13 @@ export const SettingsPanel = (
) => {
const { name, title, removable, latestVersion, version } = props;
const getPackageInstallStatus = useGetPackageInstallStatus();
- const { data: datasourcesData } = useGetDatasources({
+ const { data: packageConfigsData } = useGetPackageConfigs({
perPage: 0,
page: 1,
- kuery: `${DATASOURCE_SAVED_OBJECT_TYPE}.package.name:${props.name}`,
+ kuery: `${PACKAGE_CONFIG_SAVED_OBJECT_TYPE}.package.name:${props.name}`,
});
const { status: installationStatus, version: installedVersion } = getPackageInstallStatus(name);
- const packageHasDatasources = !!datasourcesData?.total;
+ const packageHasUsages = !!packageConfigsData?.total;
const updateAvailable = installedVersion && installedVersion < latestVersion ? true : false;
const isViewingOldPackage = version < latestVersion;
// hide install/remove options if the user has version of the package is installed
@@ -185,16 +185,16 @@ export const SettingsPanel = (
- {packageHasDatasources && removable === true && (
+ {packageHasUsages && removable === true && (
= {
overview: i18n.translate('xpack.ingestManager.epm.packageDetailsNav.overviewLinkText', {
defaultMessage: 'Overview',
}),
- 'data-sources': i18n.translate('xpack.ingestManager.epm.packageDetailsNav.datasourcesLinkText', {
- defaultMessage: 'Data sources',
+ usages: i18n.translate('xpack.ingestManager.epm.packageDetailsNav.packageConfigsLinkText', {
+ defaultMessage: 'Usages',
}),
settings: i18n.translate('xpack.ingestManager.epm.packageDetailsNav.settingsLinkText', {
defaultMessage: 'Settings',
@@ -43,12 +43,9 @@ export function SideNavLinks({ name, version, active }: NavLinkProps) {
? p.theme.eui.euiFontWeightSemiBold
: p.theme.eui.euiFontWeightRegular};
`;
- // Don't display Data Sources tab as we haven't implemented this yet
- // FIXME: Restore when we implement data sources page
- if (
- panel === 'data-sources' &&
- (true || packageInstallStatus.status !== InstallStatus.installed)
- )
+ // Don't display usages tab as we haven't implemented this yet
+ // FIXME: Restore when we implement usages page
+ if (panel === 'usages' && (true || packageInstallStatus.status !== InstallStatus.installed))
return null;
return (
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_datasource_badges.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_package_badges.tsx
similarity index 68%
rename from x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_datasource_badges.tsx
rename to x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_package_badges.tsx
index 30bc9dc701427..fcdb5ff02e7a4 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_datasource_badges.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_config_package_badges.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiSpacer, EuiText, EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui';
-import { Datasource } from '../../../types';
+import { PackageConfig } from '../../../types';
import { useGetOneAgentConfig } from '../../../hooks';
import { PackageIcon } from '../../../components/package_icon';
@@ -14,7 +14,7 @@ interface Props {
agentConfigId: string;
}
-export const AgentConfigDatasourceBadges: React.FunctionComponent = ({ agentConfigId }) => {
+export const AgentConfigPackageBadges: React.FunctionComponent = ({ agentConfigId }) => {
const agentConfigRequest = useGetOneAgentConfig(agentConfigId);
const agentConfig = agentConfigRequest.data ? agentConfigRequest.data.item : null;
@@ -26,16 +26,16 @@ export const AgentConfigDatasourceBadges: React.FunctionComponent = ({ ag
{agentConfig.datasources.length},
+ count: agentConfig.package_configs.length,
+ countValue: {agentConfig.package_configs.length},
}}
/>
- {(agentConfig.datasources as Datasource[]).map((datasource, idx) => {
- if (!datasource.package) {
+ {(agentConfig.package_configs as PackageConfig[]).map((packageConfig, idx) => {
+ if (!packageConfig.package) {
return null;
}
return (
@@ -43,13 +43,13 @@ export const AgentConfigDatasourceBadges: React.FunctionComponent = ({ ag
- {datasource.package.title}
+ {packageConfig.package.title}
);
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/config_selection.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/config_selection.tsx
index 6e7427c6ab55e..8cd337586d1bc 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/config_selection.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/config_selection.tsx
@@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { EuiSelect, EuiSpacer, EuiText, EuiButtonEmpty } from '@elastic/eui';
import { AgentConfig } from '../../../../types';
import { useGetEnrollmentAPIKeys } from '../../../../hooks';
-import { AgentConfigDatasourceBadges } from '../agent_config_datasource_badges';
+import { AgentConfigPackageBadges } from '../agent_config_package_badges';
interface Props {
agentConfigs: AgentConfig[];
@@ -83,7 +83,7 @@ export const EnrollmentStepAgentConfig: React.FC = ({ agentConfigs, onKey
/>
{selectedState.agentConfigId && (
-
+
)}
void;
@@ -113,7 +113,7 @@ export const AgentReassignConfigFlyout: React.FunctionComponent = ({ onCl
{selectedAgentConfigId && (
-
+
)}
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/configuration_section.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/configuration_section.tsx
index 68364f9acbbf9..ed4b3fc8e6a5d 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/configuration_section.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/configuration_section.tsx
@@ -15,7 +15,7 @@ import {
} from '@elastic/eui';
import { OverviewPanel } from './overview_panel';
import { OverviewStats } from './overview_stats';
-import { useLink, useGetDatasources } from '../../../hooks';
+import { useLink, useGetPackageConfigs } from '../../../hooks';
import { AgentConfig } from '../../../types';
import { Loading } from '../../fleet/components';
@@ -23,7 +23,7 @@ export const OverviewConfigurationSection: React.FC<{ agentConfigs: AgentConfig[
agentConfigs,
}) => {
const { getHref } = useLink();
- const datasourcesRequest = useGetDatasources({
+ const packageConfigsRequest = useGetPackageConfigs({
page: 1,
perPage: 10000,
});
@@ -48,7 +48,7 @@ export const OverviewConfigurationSection: React.FC<{ agentConfigs: AgentConfig[
- {datasourcesRequest.isLoading ? (
+ {packageConfigsRequest.isLoading ? (
) : (
<>
@@ -63,12 +63,12 @@ export const OverviewConfigurationSection: React.FC<{ agentConfigs: AgentConfig[
-
+
>
)}
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts
index ece7aef2c247f..5dc9026aebdee 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts
@@ -8,7 +8,7 @@ export { getFlattenedObject } from '../../../../../../../src/core/public';
export {
agentConfigRouteService,
- datasourceRouteService,
+ packageConfigRouteService,
dataStreamRouteService,
fleetSetupRouteService,
agentRouteService,
@@ -18,8 +18,8 @@ export {
outputRoutesService,
settingsRoutesService,
appRoutesService,
- packageToConfigDatasourceInputs,
- storedDatasourcesToAgentInputs,
+ packageToPackageConfigInputs,
+ storedPackageConfigsToAgentInputs,
configToYaml,
AgentStatusKueryHelper,
} from '../../../../common';
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts
index 90315f38fd476..43ec2f6d1a74d 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts
@@ -13,11 +13,11 @@ export {
NewAgentConfig,
AgentEvent,
EnrollmentAPIKey,
- Datasource,
- NewDatasource,
- DatasourceInput,
- DatasourceInputStream,
- DatasourceConfigRecordEntry,
+ PackageConfig,
+ NewPackageConfig,
+ PackageConfigInput,
+ PackageConfigInputStream,
+ PackageConfigConfigRecordEntry,
Output,
DataStream,
// API schema - misc setup, status
@@ -35,11 +35,11 @@ export {
CopyAgentConfigResponse,
DeleteAgentConfigRequest,
DeleteAgentConfigResponse,
- // API schemas - Datasource
- CreateDatasourceRequest,
- CreateDatasourceResponse,
- UpdateDatasourceRequest,
- UpdateDatasourceResponse,
+ // API schemas - Package config
+ CreatePackageConfigRequest,
+ CreatePackageConfigResponse,
+ UpdatePackageConfigRequest,
+ UpdatePackageConfigResponse,
// API schemas - Data Streams
GetDataStreamsResponse,
// API schemas - Agents
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/intra_app_route_state.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/intra_app_route_state.ts
index c5833adcded5f..4fd770501ae3f 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/intra_app_route_state.ts
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/intra_app_route_state.ts
@@ -5,16 +5,16 @@
*/
import { ApplicationStart } from 'kibana/public';
-import { Datasource } from '../../../../common/types/models';
+import { PackageConfig } from './';
/**
- * Supported routing state for the create datasource page routes
+ * Supported routing state for the create package config page routes
*/
-export interface CreateDatasourceRouteState {
- /** On a successful save of the datasource, use navigate to the given app */
+export interface CreatePackageConfigRouteState {
+ /** On a successful save of the package config, use navigate to the given app */
onSaveNavigateTo?:
| Parameters
- | ((newDatasource: Datasource) => Parameters);
+ | ((newPackageConfig: PackageConfig) => Parameters);
/** On cancel, navigate to the given app */
onCancelNavigateTo?: Parameters;
/** Url to be used on cancel links */
@@ -41,6 +41,6 @@ export interface AgentDetailsReassignConfigAction {
* All possible Route states.
*/
export type AnyIntraAppRouteState =
- | CreateDatasourceRouteState
+ | CreatePackageConfigRouteState
| AgentConfigDetailsDeployAgentAction
| AgentDetailsReassignConfigAction;
diff --git a/x-pack/plugins/ingest_manager/public/index.ts b/x-pack/plugins/ingest_manager/public/index.ts
index ac56349b30c13..866d17145b075 100644
--- a/x-pack/plugins/ingest_manager/public/index.ts
+++ b/x-pack/plugins/ingest_manager/public/index.ts
@@ -13,10 +13,10 @@ export const plugin = (initializerContext: PluginInitializerContext) => {
};
export {
- CustomConfigureDatasourceContent,
- CustomConfigureDatasourceProps,
- registerDatasource,
-} from './applications/ingest_manager/sections/agent_config/create_datasource_page/components/custom_configure_datasource';
+ CustomConfigurePackageConfigContent,
+ CustomConfigurePackageConfigProps,
+ registerPackageConfigComponent,
+} from './applications/ingest_manager/sections/agent_config/create_package_config_page/components/custom_package_config';
-export { NewDatasource } from './applications/ingest_manager/types';
+export { NewPackageConfig } from './applications/ingest_manager/types';
export * from './applications/ingest_manager/types/intra_app_route_state';
diff --git a/x-pack/plugins/ingest_manager/public/plugin.ts b/x-pack/plugins/ingest_manager/public/plugin.ts
index 4a10a26151e78..69dd5e42a0bc5 100644
--- a/x-pack/plugins/ingest_manager/public/plugin.ts
+++ b/x-pack/plugins/ingest_manager/public/plugin.ts
@@ -18,7 +18,7 @@ import { PLUGIN_ID, CheckPermissionsResponse, PostIngestSetupResponse } from '..
import { IngestManagerConfigType } from '../common/types';
import { setupRouteService, appRoutesService } from '../common';
-import { registerDatasource } from './applications/ingest_manager/sections/agent_config/create_datasource_page/components/custom_configure_datasource';
+import { registerPackageConfigComponent } from './applications/ingest_manager/sections/agent_config/create_package_config_page/components/custom_package_config';
export { IngestManagerConfigType } from '../common/types';
@@ -31,7 +31,7 @@ export interface IngestManagerSetup {}
* Describes public IngestManager plugin contract returned at the `start` stage.
*/
export interface IngestManagerStart {
- registerDatasource: typeof registerDatasource;
+ registerPackageConfigComponent: typeof registerPackageConfigComponent;
success: Promise;
}
@@ -102,7 +102,7 @@ export class IngestManagerPlugin
return {
success: successPromise,
- registerDatasource,
+ registerPackageConfigComponent,
};
}
diff --git a/x-pack/plugins/ingest_manager/server/constants/index.ts b/x-pack/plugins/ingest_manager/server/constants/index.ts
index ebcce6320ec4b..650211ce9c1b2 100644
--- a/x-pack/plugins/ingest_manager/server/constants/index.ts
+++ b/x-pack/plugins/ingest_manager/server/constants/index.ts
@@ -16,7 +16,7 @@ export {
PLUGIN_ID,
EPM_API_ROUTES,
DATA_STREAM_API_ROUTES,
- DATASOURCE_API_ROUTES,
+ PACKAGE_CONFIG_API_ROUTES,
AGENT_API_ROUTES,
AGENT_CONFIG_API_ROUTES,
FLEET_SETUP_API_ROUTES,
@@ -31,7 +31,7 @@ export {
AGENT_EVENT_SAVED_OBJECT_TYPE,
AGENT_ACTION_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
- DATASOURCE_SAVED_OBJECT_TYPE,
+ PACKAGE_CONFIG_SAVED_OBJECT_TYPE,
OUTPUT_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
INDEX_PATTERN_SAVED_OBJECT_TYPE,
diff --git a/x-pack/plugins/ingest_manager/server/index.ts b/x-pack/plugins/ingest_manager/server/index.ts
index 1e9011c9dfe4f..5d6a1ad321b6d 100644
--- a/x-pack/plugins/ingest_manager/server/index.ts
+++ b/x-pack/plugins/ingest_manager/server/index.ts
@@ -43,7 +43,7 @@ export const config = {
export type IngestManagerConfigType = TypeOf;
-export { DatasourceServiceInterface } from './services/datasource';
+export { PackageConfigServiceInterface } from './services/package_config';
export const plugin = (initializerContext: PluginInitializerContext) => {
return new IngestManagerPlugin(initializerContext);
diff --git a/x-pack/plugins/ingest_manager/server/integration_tests/router.test.ts b/x-pack/plugins/ingest_manager/server/integration_tests/router.test.ts
index bfd8428222643..9d671c629ef91 100644
--- a/x-pack/plugins/ingest_manager/server/integration_tests/router.test.ts
+++ b/x-pack/plugins/ingest_manager/server/integration_tests/router.test.ts
@@ -46,8 +46,8 @@ describe('ingestManager', () => {
await kbnTestServer.request.get(root, '/api/ingest_manager/agent_configs').expect(404);
});
- it('does not have datasources api', async () => {
- await kbnTestServer.request.get(root, '/api/ingest_manager/datasources').expect(404);
+ it('does not have package configs api', async () => {
+ await kbnTestServer.request.get(root, '/api/ingest_manager/package_configs').expect(404);
});
it('does not have EPM api', async () => {
@@ -79,8 +79,8 @@ describe('ingestManager', () => {
await kbnTestServer.request.get(root, '/api/ingest_manager/agent_configs').expect(200);
});
- it('has datasources api', async () => {
- await kbnTestServer.request.get(root, '/api/ingest_manager/datasources').expect(200);
+ it('has package configs api', async () => {
+ await kbnTestServer.request.get(root, '/api/ingest_manager/package_configs').expect(200);
});
it('does not have EPM api', async () => {
@@ -92,7 +92,7 @@ describe('ingestManager', () => {
});
});
- // For now, only the manager routes (/agent_configs & /datasources) are added
+ // For now, only the manager routes (/agent_configs & /package_configs) are added
// EPM and ingest will be conditionally added when we enable these lines
// https://github.com/jfsiii/kibana/blob/f73b54ebb7e0f6fc00efd8a6800a01eb2d9fb772/x-pack/plugins/ingest_manager/server/plugin.ts#L84
// adding tests to confirm the Fleet & EPM routes are never added
@@ -118,8 +118,8 @@ describe('ingestManager', () => {
await kbnTestServer.request.get(root, '/api/ingest_manager/agent_configs').expect(200);
});
- it('has datasources api', async () => {
- await kbnTestServer.request.get(root, '/api/ingest_manager/datasources').expect(200);
+ it('has package configs api', async () => {
+ await kbnTestServer.request.get(root, '/api/ingest_manager/package_configs').expect(200);
});
it('does have EPM api', async () => {
@@ -152,8 +152,8 @@ describe('ingestManager', () => {
await kbnTestServer.request.get(root, '/api/ingest_manager/agent_configs').expect(200);
});
- it('has datasources api', async () => {
- await kbnTestServer.request.get(root, '/api/ingest_manager/datasources').expect(200);
+ it('has package configs api', async () => {
+ await kbnTestServer.request.get(root, '/api/ingest_manager/package_configs').expect(200);
});
it('does not have EPM api', async () => {
@@ -187,8 +187,8 @@ describe('ingestManager', () => {
await kbnTestServer.request.get(root, '/api/ingest_manager/agent_configs').expect(200);
});
- it('has datasources api', async () => {
- await kbnTestServer.request.get(root, '/api/ingest_manager/datasources').expect(200);
+ it('has package configs api', async () => {
+ await kbnTestServer.request.get(root, '/api/ingest_manager/package_configs').expect(200);
});
it('does have EPM api', async () => {
diff --git a/x-pack/plugins/ingest_manager/server/mocks.ts b/x-pack/plugins/ingest_manager/server/mocks.ts
index 3bdef14dc85a0..f305d9dd0c1a7 100644
--- a/x-pack/plugins/ingest_manager/server/mocks.ts
+++ b/x-pack/plugins/ingest_manager/server/mocks.ts
@@ -8,7 +8,7 @@ import { loggingSystemMock, savedObjectsServiceMock } from 'src/core/server/mock
import { IngestManagerAppContext } from './plugin';
import { encryptedSavedObjectsMock } from '../../encrypted_saved_objects/server/mocks';
import { securityMock } from '../../security/server/mocks';
-import { DatasourceServiceInterface } from './services/datasource';
+import { PackageConfigServiceInterface } from './services/package_config';
export const createAppContextStartContractMock = (): IngestManagerAppContext => {
return {
@@ -21,10 +21,10 @@ export const createAppContextStartContractMock = (): IngestManagerAppContext =>
};
};
-export const createDatasourceServiceMock = () => {
+export const createPackageConfigServiceMock = () => {
return {
assignPackageStream: jest.fn(),
- buildDatasourceFromPackage: jest.fn(),
+ buildPackageConfigFromPackage: jest.fn(),
bulkCreate: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
@@ -32,5 +32,5 @@ export const createDatasourceServiceMock = () => {
getByIDs: jest.fn(),
list: jest.fn(),
update: jest.fn(),
- } as jest.Mocked;
+ } as jest.Mocked;
};
diff --git a/x-pack/plugins/ingest_manager/server/plugin.ts b/x-pack/plugins/ingest_manager/server/plugin.ts
index 1ae9528f34410..91201dbf9848b 100644
--- a/x-pack/plugins/ingest_manager/server/plugin.ts
+++ b/x-pack/plugins/ingest_manager/server/plugin.ts
@@ -25,7 +25,7 @@ import {
PLUGIN_ID,
OUTPUT_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
- DATASOURCE_SAVED_OBJECT_TYPE,
+ PACKAGE_CONFIG_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
@@ -34,7 +34,7 @@ import {
import { registerSavedObjects, registerEncryptedSavedObjects } from './saved_objects';
import {
registerEPMRoutes,
- registerDatasourceRoutes,
+ registerPackageConfigRoutes,
registerDataStreamRoutes,
registerAgentConfigRoutes,
registerSetupRoutes,
@@ -45,14 +45,14 @@ import {
registerSettingsRoutes,
registerAppRoutes,
} from './routes';
-import { IngestManagerConfigType, NewDatasource } from '../common';
+import { IngestManagerConfigType, NewPackageConfig } from '../common';
import {
appContextService,
licenseService,
ESIndexPatternSavedObjectService,
ESIndexPatternService,
AgentService,
- datasourceService,
+ packageConfigService,
} from './services';
import {
getAgentStatusById,
@@ -91,7 +91,7 @@ export type IngestManagerSetupContract = void;
const allSavedObjectTypes = [
OUTPUT_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
- DATASOURCE_SAVED_OBJECT_TYPE,
+ PACKAGE_CONFIG_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
@@ -102,8 +102,8 @@ const allSavedObjectTypes = [
* Callbacks supported by the Ingest plugin
*/
export type ExternalCallback = [
- 'datasourceCreate',
- (newDatasource: NewDatasource) => Promise
+ 'packageConfigCreate',
+ (newPackageConfig: NewPackageConfig) => Promise
];
export type ExternalCallbacksStorage = Map>;
@@ -115,9 +115,9 @@ export interface IngestManagerStartContract {
esIndexPatternService: ESIndexPatternService;
agentService: AgentService;
/**
- * Services for Ingest's Datasources
+ * Services for Ingest's package configs
*/
- datasourceService: typeof datasourceService;
+ packageConfigService: typeof packageConfigService;
/**
* Register callbacks for inclusion in ingest API processing
* @param args
@@ -205,7 +205,7 @@ export class IngestManagerPlugin
if (this.security) {
registerSetupRoutes(router, config);
registerAgentConfigRoutes(router);
- registerDatasourceRoutes(router);
+ registerPackageConfigRoutes(router);
registerOutputRoutes(router);
registerSettingsRoutes(router);
registerDataStreamRoutes(router);
@@ -265,7 +265,7 @@ export class IngestManagerPlugin
getAgentStatusById,
authenticateAgentWithAccessToken,
},
- datasourceService,
+ packageConfigService,
registerExternalCallback: (...args: ExternalCallback) => {
return appContextService.addExternalCallback(...args);
},
diff --git a/x-pack/plugins/ingest_manager/server/routes/agent_config/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/agent_config/handlers.ts
index d01b361bd6ca4..7b12a076ff041 100644
--- a/x-pack/plugins/ingest_manager/server/routes/agent_config/handlers.ts
+++ b/x-pack/plugins/ingest_manager/server/routes/agent_config/handlers.ts
@@ -7,7 +7,7 @@ import { TypeOf } from '@kbn/config-schema';
import { RequestHandler, ResponseHeaders } from 'src/core/server';
import bluebird from 'bluebird';
import { configToYaml } from '../../../common/services';
-import { appContextService, agentConfigService, datasourceService } from '../../services';
+import { appContextService, agentConfigService, packageConfigService } from '../../services';
import { listAgents } from '../../services/agents';
import { AGENT_SAVED_OBJECT_TYPE } from '../../constants';
import {
@@ -20,7 +20,7 @@ import {
GetFullAgentConfigRequestSchema,
AgentConfig,
DefaultPackages,
- NewDatasource,
+ NewPackageConfig,
} from '../../types';
import {
GetAgentConfigsResponse,
@@ -107,30 +107,34 @@ export const createAgentConfigHandler: RequestHandler<
const withSysMonitoring = request.query.sys_monitoring ?? false;
try {
// eslint-disable-next-line prefer-const
- let [agentConfig, newSysDatasource] = await Promise.all(
- [
- agentConfigService.create(soClient, request.body, {
- user,
- }),
- // If needed, retrieve System package information and build a new Datasource for the system package
- // NOTE: we ignore failures in attempting to create datasource, since config might have been created
- // successfully
- withSysMonitoring
- ? datasourceService
- .buildDatasourceFromPackage(soClient, DefaultPackages.system)
- .catch(() => undefined)
- : undefined,
- ]
- );
+ let [agentConfig, newSysPackageConfig] = await Promise.all<
+ AgentConfig,
+ NewPackageConfig | undefined
+ >([
+ agentConfigService.create(soClient, request.body, {
+ user,
+ }),
+ // If needed, retrieve System package information and build a new package config for the system package
+ // NOTE: we ignore failures in attempting to create package config, since config might have been created
+ // successfully
+ withSysMonitoring
+ ? packageConfigService
+ .buildPackageConfigFromPackage(soClient, DefaultPackages.system)
+ .catch(() => undefined)
+ : undefined,
+ ]);
- // Create the system monitoring datasource and add it to config.
- if (withSysMonitoring && newSysDatasource !== undefined && agentConfig !== undefined) {
- newSysDatasource.config_id = agentConfig.id;
- const sysDatasource = await datasourceService.create(soClient, newSysDatasource, { user });
+ // Create the system monitoring package config and add it to agent config.
+ if (withSysMonitoring && newSysPackageConfig !== undefined && agentConfig !== undefined) {
+ newSysPackageConfig.config_id = agentConfig.id;
+ newSysPackageConfig.namespace = agentConfig.namespace;
+ const sysPackageConfig = await packageConfigService.create(soClient, newSysPackageConfig, {
+ user,
+ });
- if (sysDatasource) {
- agentConfig = await agentConfigService.assignDatasources(soClient, agentConfig.id, [
- sysDatasource.id,
+ if (sysPackageConfig) {
+ agentConfig = await agentConfigService.assignPackageConfigs(soClient, agentConfig.id, [
+ sysPackageConfig.id,
]);
}
}
diff --git a/x-pack/plugins/ingest_manager/server/routes/datasource/index.ts b/x-pack/plugins/ingest_manager/server/routes/datasource/index.ts
deleted file mode 100644
index 7217f28053cf3..0000000000000
--- a/x-pack/plugins/ingest_manager/server/routes/datasource/index.ts
+++ /dev/null
@@ -1,73 +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 { IRouter } from 'src/core/server';
-import { PLUGIN_ID, DATASOURCE_API_ROUTES } from '../../constants';
-import {
- GetDatasourcesRequestSchema,
- GetOneDatasourceRequestSchema,
- CreateDatasourceRequestSchema,
- UpdateDatasourceRequestSchema,
- DeleteDatasourcesRequestSchema,
-} from '../../types';
-import {
- getDatasourcesHandler,
- getOneDatasourceHandler,
- createDatasourceHandler,
- updateDatasourceHandler,
- deleteDatasourceHandler,
-} from './handlers';
-
-export const registerRoutes = (router: IRouter) => {
- // List
- router.get(
- {
- path: DATASOURCE_API_ROUTES.LIST_PATTERN,
- validate: GetDatasourcesRequestSchema,
- options: { tags: [`access:${PLUGIN_ID}-read`] },
- },
- getDatasourcesHandler
- );
-
- // Get one
- router.get(
- {
- path: DATASOURCE_API_ROUTES.INFO_PATTERN,
- validate: GetOneDatasourceRequestSchema,
- options: { tags: [`access:${PLUGIN_ID}-read`] },
- },
- getOneDatasourceHandler
- );
-
- // Create
- router.post(
- {
- path: DATASOURCE_API_ROUTES.CREATE_PATTERN,
- validate: CreateDatasourceRequestSchema,
- options: { tags: [`access:${PLUGIN_ID}-all`] },
- },
- createDatasourceHandler
- );
-
- // Update
- router.put(
- {
- path: DATASOURCE_API_ROUTES.UPDATE_PATTERN,
- validate: UpdateDatasourceRequestSchema,
- options: { tags: [`access:${PLUGIN_ID}-all`] },
- },
- updateDatasourceHandler
- );
-
- // Delete
- router.post(
- {
- path: DATASOURCE_API_ROUTES.DELETE_PATTERN,
- validate: DeleteDatasourcesRequestSchema,
- options: { tags: [`access:${PLUGIN_ID}`] },
- },
- deleteDatasourceHandler
- );
-};
diff --git a/x-pack/plugins/ingest_manager/server/routes/index.ts b/x-pack/plugins/ingest_manager/server/routes/index.ts
index 0978c2aa57bf6..f6b4439d8bef1 100644
--- a/x-pack/plugins/ingest_manager/server/routes/index.ts
+++ b/x-pack/plugins/ingest_manager/server/routes/index.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { registerRoutes as registerAgentConfigRoutes } from './agent_config';
-export { registerRoutes as registerDatasourceRoutes } from './datasource';
+export { registerRoutes as registerPackageConfigRoutes } from './package_config';
export { registerRoutes as registerDataStreamRoutes } from './data_streams';
export { registerRoutes as registerEPMRoutes } from './epm';
export { registerRoutes as registerSetupRoutes } from './setup';
diff --git a/x-pack/plugins/ingest_manager/server/routes/datasource/datasource_handlers.test.ts b/x-pack/plugins/ingest_manager/server/routes/package_config/handlers.test.ts
similarity index 85%
rename from x-pack/plugins/ingest_manager/server/routes/datasource/datasource_handlers.test.ts
rename to x-pack/plugins/ingest_manager/server/routes/package_config/handlers.test.ts
index 07cbeb8b2cec5..6d712ce063290 100644
--- a/x-pack/plugins/ingest_manager/server/routes/datasource/datasource_handlers.test.ts
+++ b/x-pack/plugins/ingest_manager/server/routes/package_config/handlers.test.ts
@@ -7,23 +7,23 @@
import { httpServerMock, httpServiceMock } from 'src/core/server/mocks';
import { IRouter, KibanaRequest, Logger, RequestHandler, RouteConfig } from 'kibana/server';
import { registerRoutes } from './index';
-import { DATASOURCE_API_ROUTES } from '../../../common/constants';
+import { PACKAGE_CONFIG_API_ROUTES } from '../../../common/constants';
import { xpackMocks } from '../../../../../mocks';
import { appContextService } from '../../services';
import { createAppContextStartContractMock } from '../../mocks';
-import { DatasourceServiceInterface, ExternalCallback } from '../..';
-import { CreateDatasourceRequestSchema } from '../../types/rest_spec';
-import { datasourceService } from '../../services';
+import { PackageConfigServiceInterface, ExternalCallback } from '../..';
+import { CreatePackageConfigRequestSchema } from '../../types/rest_spec';
+import { packageConfigService } from '../../services';
-const datasourceServiceMock = datasourceService as jest.Mocked;
+const packageConfigServiceMock = packageConfigService as jest.Mocked;
-jest.mock('../../services/datasource', (): {
- datasourceService: jest.Mocked;
+jest.mock('../../services/package_config', (): {
+ packageConfigService: jest.Mocked;
} => {
return {
- datasourceService: {
+ packageConfigService: {
assignPackageStream: jest.fn((packageInfo, dataInputs) => Promise.resolve(dataInputs)),
- buildDatasourceFromPackage: jest.fn(),
+ buildPackageConfigFromPackage: jest.fn(),
bulkCreate: jest.fn(),
create: jest.fn((soClient, newData) =>
Promise.resolve({
@@ -52,7 +52,7 @@ jest.mock('../../services/epm/packages', () => {
};
});
-describe('When calling datasource', () => {
+describe('When calling package config', () => {
let routerMock: jest.Mocked;
let routeHandler: RequestHandler;
let routeConfig: RouteConfig;
@@ -77,12 +77,12 @@ describe('When calling datasource', () => {
describe('create api handler', () => {
const getCreateKibanaRequest = (
- newData?: typeof CreateDatasourceRequestSchema.body
- ): KibanaRequest => {
+ newData?: typeof CreatePackageConfigRequestSchema.body
+ ): KibanaRequest => {
return httpServerMock.createKibanaRequest<
undefined,
undefined,
- typeof CreateDatasourceRequestSchema.body
+ typeof CreatePackageConfigRequestSchema.body
>({
path: routeConfig.path,
method: 'post',
@@ -102,7 +102,7 @@ describe('When calling datasource', () => {
// Set the routeConfig and routeHandler to the Create API
beforeAll(() => {
[routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) =>
- path.startsWith(DATASOURCE_API_ROUTES.CREATE_PATTERN)
+ path.startsWith(PACKAGE_CONFIG_API_ROUTES.CREATE_PATTERN)
)!;
});
@@ -151,8 +151,8 @@ describe('When calling datasource', () => {
});
beforeEach(() => {
- appContextService.addExternalCallback('datasourceCreate', callbackOne);
- appContextService.addExternalCallback('datasourceCreate', callbackTwo);
+ appContextService.addExternalCallback('packageConfigCreate', callbackOne);
+ appContextService.addExternalCallback('packageConfigCreate', callbackTwo);
});
afterEach(() => (callbackCallingOrder.length = 0));
@@ -164,7 +164,7 @@ describe('When calling datasource', () => {
expect(callbackCallingOrder).toEqual(['one', 'two']);
});
- it('should feed datasource returned by last callback', async () => {
+ it('should feed package config returned by last callback', async () => {
const request = getCreateKibanaRequest();
await routeHandler(context, request, response);
expect(response.ok).toHaveBeenCalled();
@@ -213,7 +213,7 @@ describe('When calling datasource', () => {
const request = getCreateKibanaRequest();
await routeHandler(context, request, response);
expect(response.ok).toHaveBeenCalled();
- expect(datasourceServiceMock.create.mock.calls[0][1]).toEqual({
+ expect(packageConfigServiceMock.create.mock.calls[0][1]).toEqual({
config_id: 'a5ca00c0-b30c-11ea-9732-1bb05811278c',
description: '',
enabled: true,
@@ -268,8 +268,8 @@ describe('When calling datasource', () => {
});
beforeEach(() => {
- appContextService.addExternalCallback('datasourceCreate', callbackThree);
- appContextService.addExternalCallback('datasourceCreate', callbackFour);
+ appContextService.addExternalCallback('packageConfigCreate', callbackThree);
+ appContextService.addExternalCallback('packageConfigCreate', callbackFour);
});
it('should skip over callback exceptions and still execute other callbacks', async () => {
@@ -285,16 +285,16 @@ describe('When calling datasource', () => {
await routeHandler(context, request, response);
expect(response.ok).toHaveBeenCalled();
expect(errorLogger.mock.calls).toEqual([
- ['An external registered [datasourceCreate] callback failed when executed'],
+ ['An external registered [packageConfigCreate] callback failed when executed'],
[new Error('callbackThree threw error on purpose')],
]);
});
- it('should create datasource with last successful returned datasource', async () => {
+ it('should create package config with last successful returned package config', async () => {
const request = getCreateKibanaRequest();
await routeHandler(context, request, response);
expect(response.ok).toHaveBeenCalled();
- expect(datasourceServiceMock.create.mock.calls[0][1]).toEqual({
+ expect(packageConfigServiceMock.create.mock.calls[0][1]).toEqual({
config_id: 'a5ca00c0-b30c-11ea-9732-1bb05811278c',
description: '',
enabled: true,
diff --git a/x-pack/plugins/ingest_manager/server/routes/datasource/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/package_config/handlers.ts
similarity index 56%
rename from x-pack/plugins/ingest_manager/server/routes/datasource/handlers.ts
rename to x-pack/plugins/ingest_manager/server/routes/package_config/handlers.ts
index 4f83d24a846ea..e212c861ce770 100644
--- a/x-pack/plugins/ingest_manager/server/routes/datasource/handlers.ts
+++ b/x-pack/plugins/ingest_manager/server/routes/package_config/handlers.ts
@@ -6,25 +6,28 @@
import { TypeOf } from '@kbn/config-schema';
import Boom from 'boom';
import { RequestHandler } from 'src/core/server';
-import { appContextService, datasourceService } from '../../services';
+import { appContextService, packageConfigService } from '../../services';
import { ensureInstalledPackage, getPackageInfo } from '../../services/epm/packages';
import {
- GetDatasourcesRequestSchema,
- GetOneDatasourceRequestSchema,
- CreateDatasourceRequestSchema,
- UpdateDatasourceRequestSchema,
- DeleteDatasourcesRequestSchema,
- NewDatasource,
+ GetPackageConfigsRequestSchema,
+ GetOnePackageConfigRequestSchema,
+ CreatePackageConfigRequestSchema,
+ UpdatePackageConfigRequestSchema,
+ DeletePackageConfigsRequestSchema,
+ NewPackageConfig,
} from '../../types';
-import { CreateDatasourceResponse, DeleteDatasourcesResponse } from '../../../common';
+import { CreatePackageConfigResponse, DeletePackageConfigsResponse } from '../../../common';
-export const getDatasourcesHandler: RequestHandler<
+export const getPackageConfigsHandler: RequestHandler<
undefined,
- TypeOf
+ TypeOf
> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
try {
- const { items, total, page, perPage } = await datasourceService.list(soClient, request.query);
+ const { items, total, page, perPage } = await packageConfigService.list(
+ soClient,
+ request.query
+ );
return response.ok({
body: {
items,
@@ -42,23 +45,23 @@ export const getDatasourcesHandler: RequestHandler<
}
};
-export const getOneDatasourceHandler: RequestHandler> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
try {
- const datasource = await datasourceService.get(soClient, request.params.datasourceId);
- if (datasource) {
+ const packageConfig = await packageConfigService.get(soClient, request.params.packageConfigId);
+ if (packageConfig) {
return response.ok({
body: {
- item: datasource,
+ item: packageConfig,
success: true,
},
});
} else {
return response.customError({
statusCode: 404,
- body: { message: 'Datasource not found' },
+ body: { message: 'Package config not found' },
});
}
} catch (e) {
@@ -69,10 +72,10 @@ export const getOneDatasourceHandler: RequestHandler
+ TypeOf
> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
const callCluster = context.core.elasticsearch.legacy.client.callAsCurrentUser;
@@ -80,33 +83,30 @@ export const createDatasourceHandler: RequestHandler<
const logger = appContextService.getLogger();
let newData = { ...request.body };
try {
- // If we have external callbacks, then process those now before creating the actual datasource
- const externalCallbacks = appContextService.getExternalCallbacks('datasourceCreate');
+ // If we have external callbacks, then process those now before creating the actual package config
+ const externalCallbacks = appContextService.getExternalCallbacks('packageConfigCreate');
if (externalCallbacks && externalCallbacks.size > 0) {
- let updatedNewData: NewDatasource = newData;
+ let updatedNewData: NewPackageConfig = newData;
for (const callback of externalCallbacks) {
try {
// ensure that the returned value by the callback passes schema validation
- updatedNewData = CreateDatasourceRequestSchema.body.validate(
+ updatedNewData = CreatePackageConfigRequestSchema.body.validate(
await callback(updatedNewData)
);
} catch (error) {
// Log the error, but keep going and process the other callbacks
- logger.error('An external registered [datasourceCreate] callback failed when executed');
+ logger.error(
+ 'An external registered [packageConfigCreate] callback failed when executed'
+ );
logger.error(error);
}
}
- // The type `NewDatasource` and the `DatasourceBaseSchema` are incompatible.
- // `NewDatasrouce` defines `namespace` as optional string, which means that `undefined` is a
- // valid value, however, the schema defines it as string with a minimum length of 1.
- // Here, we need to cast the value back to the schema type and ignore the TS error.
- // @ts-ignore
- newData = updatedNewData as typeof CreateDatasourceRequestSchema.body;
+ newData = updatedNewData;
}
- // Make sure the datasource package is installed
+ // Make sure the associated package is installed
if (newData.package?.name) {
await ensureInstalledPackage({
savedObjectsClient: soClient,
@@ -118,15 +118,15 @@ export const createDatasourceHandler: RequestHandler<
pkgName: newData.package.name,
pkgVersion: newData.package.version,
});
- newData.inputs = (await datasourceService.assignPackageStream(
+ newData.inputs = (await packageConfigService.assignPackageStream(
pkgInfo,
newData.inputs
- )) as TypeOf['inputs'];
+ )) as TypeOf['inputs'];
}
- // Create datasource
- const datasource = await datasourceService.create(soClient, newData, { user });
- const body: CreateDatasourceResponse = { item: datasource, success: true };
+ // Create package config
+ const packageConfig = await packageConfigService.create(soClient, newData, { user });
+ const body: CreatePackageConfigResponse = { item: packageConfig, success: true };
return response.ok({
body,
});
@@ -139,42 +139,42 @@ export const createDatasourceHandler: RequestHandler<
}
};
-export const updateDatasourceHandler: RequestHandler<
- TypeOf,
+export const updatePackageConfigHandler: RequestHandler<
+ TypeOf,
unknown,
- TypeOf
+ TypeOf
> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
const user = (await appContextService.getSecurity()?.authc.getCurrentUser(request)) || undefined;
try {
- const datasource = await datasourceService.get(soClient, request.params.datasourceId);
+ const packageConfig = await packageConfigService.get(soClient, request.params.packageConfigId);
- if (!datasource) {
- throw Boom.notFound('Datasource not found');
+ if (!packageConfig) {
+ throw Boom.notFound('Package config not found');
}
const newData = { ...request.body };
- const pkg = newData.package || datasource.package;
- const inputs = newData.inputs || datasource.inputs;
+ const pkg = newData.package || packageConfig.package;
+ const inputs = newData.inputs || packageConfig.inputs;
if (pkg && (newData.inputs || newData.package)) {
const pkgInfo = await getPackageInfo({
savedObjectsClient: soClient,
pkgName: pkg.name,
pkgVersion: pkg.version,
});
- newData.inputs = (await datasourceService.assignPackageStream(pkgInfo, inputs)) as TypeOf<
- typeof CreateDatasourceRequestSchema.body
+ newData.inputs = (await packageConfigService.assignPackageStream(pkgInfo, inputs)) as TypeOf<
+ typeof CreatePackageConfigRequestSchema.body
>['inputs'];
}
- const updatedDatasource = await datasourceService.update(
+ const updatedPackageConfig = await packageConfigService.update(
soClient,
- request.params.datasourceId,
+ request.params.packageConfigId,
newData,
{ user }
);
return response.ok({
- body: { item: updatedDatasource, success: true },
+ body: { item: updatedPackageConfig, success: true },
});
} catch (e) {
return response.customError({
@@ -184,17 +184,17 @@ export const updateDatasourceHandler: RequestHandler<
}
};
-export const deleteDatasourceHandler: RequestHandler<
+export const deletePackageConfigHandler: RequestHandler<
unknown,
unknown,
- TypeOf
+ TypeOf
> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
const user = (await appContextService.getSecurity()?.authc.getCurrentUser(request)) || undefined;
try {
- const body: DeleteDatasourcesResponse = await datasourceService.delete(
+ const body: DeletePackageConfigsResponse = await packageConfigService.delete(
soClient,
- request.body.datasourceIds,
+ request.body.packageConfigIds,
{ user }
);
return response.ok({
diff --git a/x-pack/plugins/ingest_manager/server/routes/package_config/index.ts b/x-pack/plugins/ingest_manager/server/routes/package_config/index.ts
new file mode 100644
index 0000000000000..1da045e052997
--- /dev/null
+++ b/x-pack/plugins/ingest_manager/server/routes/package_config/index.ts
@@ -0,0 +1,73 @@
+/*
+ * 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 { IRouter } from 'src/core/server';
+import { PLUGIN_ID, PACKAGE_CONFIG_API_ROUTES } from '../../constants';
+import {
+ GetPackageConfigsRequestSchema,
+ GetOnePackageConfigRequestSchema,
+ CreatePackageConfigRequestSchema,
+ UpdatePackageConfigRequestSchema,
+ DeletePackageConfigsRequestSchema,
+} from '../../types';
+import {
+ getPackageConfigsHandler,
+ getOnePackageConfigHandler,
+ createPackageConfigHandler,
+ updatePackageConfigHandler,
+ deletePackageConfigHandler,
+} from './handlers';
+
+export const registerRoutes = (router: IRouter) => {
+ // List
+ router.get(
+ {
+ path: PACKAGE_CONFIG_API_ROUTES.LIST_PATTERN,
+ validate: GetPackageConfigsRequestSchema,
+ options: { tags: [`access:${PLUGIN_ID}-read`] },
+ },
+ getPackageConfigsHandler
+ );
+
+ // Get one
+ router.get(
+ {
+ path: PACKAGE_CONFIG_API_ROUTES.INFO_PATTERN,
+ validate: GetOnePackageConfigRequestSchema,
+ options: { tags: [`access:${PLUGIN_ID}-read`] },
+ },
+ getOnePackageConfigHandler
+ );
+
+ // Create
+ router.post(
+ {
+ path: PACKAGE_CONFIG_API_ROUTES.CREATE_PATTERN,
+ validate: CreatePackageConfigRequestSchema,
+ options: { tags: [`access:${PLUGIN_ID}-all`] },
+ },
+ createPackageConfigHandler
+ );
+
+ // Update
+ router.put(
+ {
+ path: PACKAGE_CONFIG_API_ROUTES.UPDATE_PATTERN,
+ validate: UpdatePackageConfigRequestSchema,
+ options: { tags: [`access:${PLUGIN_ID}-all`] },
+ },
+ updatePackageConfigHandler
+ );
+
+ // Delete
+ router.post(
+ {
+ path: PACKAGE_CONFIG_API_ROUTES.DELETE_PATTERN,
+ validate: DeletePackageConfigsRequestSchema,
+ options: { tags: [`access:${PLUGIN_ID}`] },
+ },
+ deletePackageConfigHandler
+ );
+};
diff --git a/x-pack/plugins/ingest_manager/server/saved_objects/index.ts b/x-pack/plugins/ingest_manager/server/saved_objects/index.ts
index 1d412937e244f..98de9ac217af9 100644
--- a/x-pack/plugins/ingest_manager/server/saved_objects/index.ts
+++ b/x-pack/plugins/ingest_manager/server/saved_objects/index.ts
@@ -9,7 +9,7 @@ import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objec
import {
OUTPUT_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
- DATASOURCE_SAVED_OBJECT_TYPE,
+ PACKAGE_CONFIG_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
@@ -17,14 +17,13 @@ import {
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
GLOBAL_SETTINGS_SAVED_OBJECT_TYPE,
} from '../constants';
-import { migrateDatasourcesToV790 } from './migrations/datasources_v790';
-import { migrateAgentConfigToV790 } from './migrations/agent_config_v790';
+
/*
* Saved object types and mappings
*
- * Please update typings in `/common/types` if mappings are updated.
+ * Please update typings in `/common/types` as well as
+ * schemas in `/server/types` if mappings are updated.
*/
-
const savedObjectTypes: { [key: string]: SavedObjectsType } = {
[GLOBAL_SETTINGS_SAVED_OBJECT_TYPE]: {
name: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE,
@@ -122,20 +121,17 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = {
properties: {
id: { type: 'keyword' },
name: { type: 'text' },
- is_default: { type: 'boolean' },
- namespace: { type: 'keyword' },
description: { type: 'text' },
+ namespace: { type: 'keyword' },
+ is_default: { type: 'boolean' },
status: { type: 'keyword' },
- datasources: { type: 'keyword' },
+ package_configs: { type: 'keyword' },
updated_at: { type: 'date' },
updated_by: { type: 'keyword' },
revision: { type: 'integer' },
monitoring_enabled: { type: 'keyword', index: false },
},
},
- migrations: {
- '7.9.0': migrateAgentConfigToV790,
- },
},
[ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE]: {
name: ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
@@ -178,8 +174,8 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = {
},
},
},
- [DATASOURCE_SAVED_OBJECT_TYPE]: {
- name: DATASOURCE_SAVED_OBJECT_TYPE,
+ [PACKAGE_CONFIG_SAVED_OBJECT_TYPE]: {
+ name: PACKAGE_CONFIG_SAVED_OBJECT_TYPE,
hidden: false,
namespaceType: 'agnostic',
management: {
@@ -190,8 +186,9 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = {
name: { type: 'keyword' },
description: { type: 'text' },
namespace: { type: 'keyword' },
- config_id: { type: 'keyword' },
enabled: { type: 'boolean' },
+ config_id: { type: 'keyword' },
+ output_id: { type: 'keyword' },
package: {
properties: {
name: { type: 'keyword' },
@@ -199,16 +196,14 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = {
version: { type: 'keyword' },
},
},
- output_id: { type: 'keyword' },
inputs: {
type: 'nested',
enabled: false,
properties: {
type: { type: 'keyword' },
enabled: { type: 'boolean' },
- processors: { type: 'keyword' },
- config: { type: 'flattened' },
vars: { type: 'flattened' },
+ config: { type: 'flattened' },
streams: {
type: 'nested',
properties: {
@@ -220,10 +215,9 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = {
type: { type: 'keyword' },
},
},
- processors: { type: 'keyword' },
- config: { type: 'flattened' },
- agent_stream: { type: 'flattened' },
vars: { type: 'flattened' },
+ config: { type: 'flattened' },
+ compiled_stream: { type: 'flattened' },
},
},
},
@@ -235,9 +229,6 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = {
created_by: { type: 'keyword' },
},
},
- migrations: {
- '7.9.0': migrateDatasourcesToV790,
- },
},
[PACKAGES_SAVED_OBJECT_TYPE]: {
name: PACKAGES_SAVED_OBJECT_TYPE,
diff --git a/x-pack/plugins/ingest_manager/server/saved_objects/migrations/agent_config_v790.ts b/x-pack/plugins/ingest_manager/server/saved_objects/migrations/agent_config_v790.ts
deleted file mode 100644
index 0c850f2c25fbf..0000000000000
--- a/x-pack/plugins/ingest_manager/server/saved_objects/migrations/agent_config_v790.ts
+++ /dev/null
@@ -1,24 +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 { SavedObjectMigrationFn } from 'kibana/server';
-import { cloneDeep } from 'lodash';
-import { AgentConfig } from '../../types';
-
-type Pre790AgentConfig = Exclude & {
- updated_on: string;
-};
-
-export const migrateAgentConfigToV790: SavedObjectMigrationFn = (
- doc
-) => {
- const updatedAgentConfig = cloneDeep(doc);
-
- updatedAgentConfig.attributes.updated_at = doc.attributes.updated_on;
- delete updatedAgentConfig.attributes.updated_on;
-
- return updatedAgentConfig;
-};
diff --git a/x-pack/plugins/ingest_manager/server/saved_objects/migrations/datasources_v790.ts b/x-pack/plugins/ingest_manager/server/saved_objects/migrations/datasources_v790.ts
deleted file mode 100644
index d1e4b29daefc6..0000000000000
--- a/x-pack/plugins/ingest_manager/server/saved_objects/migrations/datasources_v790.ts
+++ /dev/null
@@ -1,43 +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 { SavedObjectMigrationFn } from 'kibana/server';
-import { cloneDeep } from 'lodash';
-import { Datasource, DatasourceInput, DatasourceInputStream } from '../../types';
-
-type Pre790Datasource = Exclude<
- Datasource,
- 'created_at' | 'created_by' | 'updated_at' | 'updated_by'
-> & {
- inputs: Array<
- Exclude & {
- streams: Array<
- Exclude & {
- dataset: string;
- }
- >;
- }
- >;
-};
-
-export const migrateDatasourcesToV790: SavedObjectMigrationFn = (
- doc
-) => {
- const updatedDatasource = cloneDeep(doc);
- const defDate = new Date().toISOString();
-
- updatedDatasource.attributes.created_by = 'system';
- updatedDatasource.attributes.created_at = updatedDatasource?.updated_at ?? defDate;
- updatedDatasource.attributes.updated_by = 'system';
- updatedDatasource.attributes.updated_at = updatedDatasource?.updated_at ?? defDate;
- updatedDatasource.attributes.inputs.forEach((input) => {
- input.streams.forEach((stream) => {
- stream.dataset = { name: (stream.dataset as unknown) as string, type: '' };
- });
- });
-
- return updatedDatasource;
-};
diff --git a/x-pack/plugins/ingest_manager/server/services/agent_config.ts b/x-pack/plugins/ingest_manager/server/services/agent_config.ts
index 9c27e9b7a3a7a..ada35d1825069 100644
--- a/x-pack/plugins/ingest_manager/server/services/agent_config.ts
+++ b/x-pack/plugins/ingest_manager/server/services/agent_config.ts
@@ -12,7 +12,7 @@ import {
AGENT_SAVED_OBJECT_TYPE,
} from '../constants';
import {
- Datasource,
+ PackageConfig,
NewAgentConfig,
AgentConfig,
AgentConfigSOAttributes,
@@ -20,9 +20,9 @@ import {
AgentConfigStatus,
ListWithKuery,
} from '../types';
-import { DeleteAgentConfigResponse, storedDatasourcesToAgentInputs } from '../../common';
+import { DeleteAgentConfigResponse, storedPackageConfigsToAgentInputs } from '../../common';
import { listAgents } from './agents';
-import { datasourceService } from './datasource';
+import { packageConfigService } from './package_config';
import { outputService } from './output';
import { agentConfigUpdateEventHandler } from './agent_config_update';
@@ -115,7 +115,7 @@ class AgentConfigService {
public async get(
soClient: SavedObjectsClientContract,
id: string,
- withDatasources: boolean = true
+ withPackageConfigs: boolean = true
): Promise {
const agentConfigSO = await soClient.get(SAVED_OBJECT_TYPE, id);
if (!agentConfigSO) {
@@ -128,11 +128,11 @@ class AgentConfigService {
const agentConfig = { id: agentConfigSO.id, ...agentConfigSO.attributes };
- if (withDatasources) {
- agentConfig.datasources =
- (await datasourceService.getByIDs(
+ if (withPackageConfigs) {
+ agentConfig.package_configs =
+ (await packageConfigService.getByIDs(
soClient,
- (agentConfigSO.attributes.datasources as string[]) || []
+ (agentConfigSO.attributes.package_configs as string[]) || []
)) || [];
}
@@ -200,15 +200,20 @@ class AgentConfigService {
options
);
- // Copy all datasources
- if (baseAgentConfig.datasources.length) {
- const newDatasources = (baseAgentConfig.datasources as Datasource[]).map(
- (datasource: Datasource) => {
- const { id: datasourceId, ...newDatasource } = datasource;
- return newDatasource;
+ // Copy all package configs
+ if (baseAgentConfig.package_configs.length) {
+ const newPackageConfigs = (baseAgentConfig.package_configs as PackageConfig[]).map(
+ (packageConfig: PackageConfig) => {
+ const { id: packageConfigId, ...newPackageConfig } = packageConfig;
+ return newPackageConfig;
}
);
- await datasourceService.bulkCreate(soClient, newDatasources, newAgentConfig.id, options);
+ await packageConfigService.bulkCreate(
+ soClient,
+ newPackageConfigs,
+ newAgentConfig.id,
+ options
+ );
}
// Get updated config
@@ -228,10 +233,10 @@ class AgentConfigService {
return this._update(soClient, id, {}, options?.user);
}
- public async assignDatasources(
+ public async assignPackageConfigs(
soClient: SavedObjectsClientContract,
id: string,
- datasourceIds: string[],
+ packageConfigIds: string[],
options?: { user?: AuthenticatedUser }
): Promise {
const oldAgentConfig = await this.get(soClient, id, false);
@@ -244,18 +249,18 @@ class AgentConfigService {
soClient,
id,
{
- datasources: uniq(
- [...((oldAgentConfig.datasources || []) as string[])].concat(datasourceIds)
+ package_configs: uniq(
+ [...((oldAgentConfig.package_configs || []) as string[])].concat(packageConfigIds)
),
},
options?.user
);
}
- public async unassignDatasources(
+ public async unassignPackageConfigs(
soClient: SavedObjectsClientContract,
id: string,
- datasourceIds: string[],
+ packageConfigIds: string[],
options?: { user?: AuthenticatedUser }
): Promise {
const oldAgentConfig = await this.get(soClient, id, false);
@@ -269,9 +274,9 @@ class AgentConfigService {
id,
{
...oldAgentConfig,
- datasources: uniq(
- [...((oldAgentConfig.datasources || []) as string[])].filter(
- (dsId) => !datasourceIds.includes(dsId)
+ package_configs: uniq(
+ [...((oldAgentConfig.package_configs || []) as string[])].filter(
+ (pkgConfigId) => !packageConfigIds.includes(pkgConfigId)
)
),
},
@@ -318,8 +323,8 @@ class AgentConfigService {
throw new Error('Cannot delete agent config that is assigned to agent(s)');
}
- if (config.datasources && config.datasources.length) {
- await datasourceService.delete(soClient, config.datasources as string[], {
+ if (config.package_configs && config.package_configs.length) {
+ await packageConfigService.delete(soClient, config.package_configs as string[], {
skipUnassignFromAgentConfigs: true,
});
}
@@ -373,7 +378,7 @@ class AgentConfigService {
{} as FullAgentConfig['outputs']
),
},
- inputs: storedDatasourcesToAgentInputs(config.datasources as Datasource[]),
+ inputs: storedPackageConfigsToAgentInputs(config.package_configs as PackageConfig[]),
revision: config.revision,
...(config.monitoring_enabled && config.monitoring_enabled.length > 0
? {
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.ts b/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.ts
index 0bcb2464f8d74..d697ad0576396 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.ts
@@ -6,9 +6,9 @@
import Handlebars from 'handlebars';
import { safeLoad, safeDump } from 'js-yaml';
-import { DatasourceConfigRecord } from '../../../../common';
+import { PackageConfigConfigRecord } from '../../../../common';
-export function createStream(variables: DatasourceConfigRecord, streamTemplate: string) {
+export function createStream(variables: PackageConfigConfigRecord, streamTemplate: string) {
const { vars, yamlValues } = buildTemplateVariables(variables, streamTemplate);
const template = Handlebars.compile(streamTemplate, { noEscape: true });
@@ -52,7 +52,7 @@ function replaceVariablesInYaml(yamlVariables: { [k: string]: any }, yaml: any)
return yaml;
}
-function buildTemplateVariables(variables: DatasourceConfigRecord, streamTemplate: string) {
+function buildTemplateVariables(variables: PackageConfigConfigRecord, streamTemplate: string) {
const yamlValues: { [k: string]: any } = {};
const vars = Object.entries(variables).reduce((acc, [key, recordEntry]) => {
// support variables with . like key.patterns
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts
index 9b506a2d055a7..94af672d8e29f 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts
@@ -6,12 +6,12 @@
import { SavedObjectsClientContract } from 'src/core/server';
import Boom from 'boom';
-import { PACKAGES_SAVED_OBJECT_TYPE, DATASOURCE_SAVED_OBJECT_TYPE } from '../../../constants';
+import { PACKAGES_SAVED_OBJECT_TYPE, PACKAGE_CONFIG_SAVED_OBJECT_TYPE } from '../../../constants';
import { AssetReference, AssetType, ElasticsearchAssetType } from '../../../types';
import { CallESAsCurrentUser } from '../../../types';
import { getInstallation, savedObjectTypes } from './index';
import { installIndexPatterns } from '../kibana/index_pattern/install';
-import { datasourceService } from '../..';
+import { packageConfigService } from '../..';
export async function removeInstallation(options: {
savedObjectsClient: SavedObjectsClientContract;
@@ -27,15 +27,15 @@ export async function removeInstallation(options: {
throw Boom.badRequest(`${pkgName} is installed by default and cannot be removed`);
const installedObjects = installation.installed || [];
- const { total } = await datasourceService.list(savedObjectsClient, {
- kuery: `${DATASOURCE_SAVED_OBJECT_TYPE}.package.name:${pkgName}`,
+ const { total } = await packageConfigService.list(savedObjectsClient, {
+ kuery: `${PACKAGE_CONFIG_SAVED_OBJECT_TYPE}.package.name:${pkgName}`,
page: 0,
perPage: 0,
});
if (total > 0)
throw Boom.badRequest(
- `unable to remove package with existing datasource(s) in use by agent(s)`
+ `unable to remove package with existing package config(s) in use by agent(s)`
);
// Delete the manager saved object with references to the asset objects
diff --git a/x-pack/plugins/ingest_manager/server/services/index.ts b/x-pack/plugins/ingest_manager/server/services/index.ts
index 49896959f3c3a..74adab09d12eb 100644
--- a/x-pack/plugins/ingest_manager/server/services/index.ts
+++ b/x-pack/plugins/ingest_manager/server/services/index.ts
@@ -59,8 +59,8 @@ export interface AgentService {
}
// Saved object services
-export { datasourceService } from './datasource';
export { agentConfigService } from './agent_config';
+export { packageConfigService } from './package_config';
export { outputService } from './output';
export { settingsService };
diff --git a/x-pack/plugins/ingest_manager/server/services/datasource.test.ts b/x-pack/plugins/ingest_manager/server/services/package_config.test.ts
similarity index 92%
rename from x-pack/plugins/ingest_manager/server/services/datasource.test.ts
rename to x-pack/plugins/ingest_manager/server/services/package_config.test.ts
index 8d98e41c8ae69..f8dd1c65e3e72 100644
--- a/x-pack/plugins/ingest_manager/server/services/datasource.test.ts
+++ b/x-pack/plugins/ingest_manager/server/services/package_config.test.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { datasourceService } from './datasource';
+import { packageConfigService } from './package_config';
import { PackageInfo } from '../types';
async function mockedGetAssetsData(_a: any, _b: any, dataset: string) {
@@ -37,10 +37,10 @@ jest.mock('./epm/registry', () => {
};
});
-describe('Datasource service', () => {
+describe('Package config service', () => {
describe('assignPackageStream', () => {
it('should work with config variables from the stream', async () => {
- const inputs = await datasourceService.assignPackageStream(
+ const inputs = await packageConfigService.assignPackageStream(
({
datasets: [
{
@@ -89,7 +89,7 @@ describe('Datasource service', () => {
value: ['/var/log/set.log'],
},
},
- agent_stream: {
+ compiled_stream: {
metricset: ['dataset1'],
paths: ['/var/log/set.log'],
type: 'log',
@@ -101,7 +101,7 @@ describe('Datasource service', () => {
});
it('should work with config variables at the input level', async () => {
- const inputs = await datasourceService.assignPackageStream(
+ const inputs = await packageConfigService.assignPackageStream(
({
datasets: [
{
@@ -150,7 +150,7 @@ describe('Datasource service', () => {
id: 'dataset01',
dataset: { name: 'package.dataset1', type: 'logs' },
enabled: true,
- agent_stream: {
+ compiled_stream: {
metricset: ['dataset1'],
paths: ['/var/log/set.log'],
type: 'log',
diff --git a/x-pack/plugins/ingest_manager/server/services/datasource.ts b/x-pack/plugins/ingest_manager/server/services/package_config.ts
similarity index 67%
rename from x-pack/plugins/ingest_manager/server/services/datasource.ts
rename to x-pack/plugins/ingest_manager/server/services/package_config.ts
index fecec0c463459..c886f4868ad30 100644
--- a/x-pack/plugins/ingest_manager/server/services/datasource.ts
+++ b/x-pack/plugins/ingest_manager/server/services/package_config.ts
@@ -6,18 +6,18 @@
import { SavedObjectsClientContract } from 'src/core/server';
import { AuthenticatedUser } from '../../../security/server';
import {
- DeleteDatasourcesResponse,
- packageToConfigDatasource,
- DatasourceInput,
- DatasourceInputStream,
+ DeletePackageConfigsResponse,
+ packageToPackageConfig,
+ PackageConfigInput,
+ PackageConfigInputStream,
PackageInfo,
} from '../../common';
-import { DATASOURCE_SAVED_OBJECT_TYPE } from '../constants';
+import { PACKAGE_CONFIG_SAVED_OBJECT_TYPE } from '../constants';
import {
- NewDatasource,
- Datasource,
+ NewPackageConfig,
+ PackageConfig,
ListWithKuery,
- DatasourceSOAttributes,
+ PackageConfigSOAttributes,
RegistryPackage,
} from '../types';
import { agentConfigService } from './agent_config';
@@ -27,23 +27,23 @@ import { getPackageInfo, getInstallation } from './epm/packages';
import { getAssetsData } from './epm/packages/assets';
import { createStream } from './epm/agent/agent';
-const SAVED_OBJECT_TYPE = DATASOURCE_SAVED_OBJECT_TYPE;
+const SAVED_OBJECT_TYPE = PACKAGE_CONFIG_SAVED_OBJECT_TYPE;
function getDataset(st: string) {
return st.split('.')[1];
}
-class DatasourceService {
+class PackageConfigService {
public async create(
soClient: SavedObjectsClientContract,
- datasource: NewDatasource,
+ packageConfig: NewPackageConfig,
options?: { id?: string; user?: AuthenticatedUser }
- ): Promise {
+ ): Promise {
const isoDate = new Date().toISOString();
- const newSo = await soClient.create(
+ const newSo = await soClient.create(
SAVED_OBJECT_TYPE,
{
- ...datasource,
+ ...packageConfig,
revision: 1,
created_at: isoDate,
created_by: options?.user?.username ?? 'system',
@@ -54,7 +54,7 @@ class DatasourceService {
);
// Assign it to the given agent config
- await agentConfigService.assignDatasources(soClient, datasource.config_id, [newSo.id], {
+ await agentConfigService.assignPackageConfigs(soClient, packageConfig.config_id, [newSo.id], {
user: options?.user,
});
@@ -66,16 +66,16 @@ class DatasourceService {
public async bulkCreate(
soClient: SavedObjectsClientContract,
- datasources: NewDatasource[],
+ packageConfigs: NewPackageConfig[],
configId: string,
options?: { user?: AuthenticatedUser }
- ): Promise {
+ ): Promise {
const isoDate = new Date().toISOString();
- const { saved_objects: newSos } = await soClient.bulkCreate>(
- datasources.map((datasource) => ({
+ const { saved_objects: newSos } = await soClient.bulkCreate>(
+ packageConfigs.map((packageConfig) => ({
type: SAVED_OBJECT_TYPE,
attributes: {
- ...datasource,
+ ...packageConfig,
config_id: configId,
revision: 1,
created_at: isoDate,
@@ -87,7 +87,7 @@ class DatasourceService {
);
// Assign it to the given agent config
- await agentConfigService.assignDatasources(
+ await agentConfigService.assignPackageConfigs(
soClient,
configId,
newSos.map((newSo) => newSo.id),
@@ -102,37 +102,40 @@ class DatasourceService {
}));
}
- public async get(soClient: SavedObjectsClientContract, id: string): Promise {
- const datasourceSO = await soClient.get(SAVED_OBJECT_TYPE, id);
- if (!datasourceSO) {
+ public async get(
+ soClient: SavedObjectsClientContract,
+ id: string
+ ): Promise {
+ const packageConfigSO = await soClient.get(SAVED_OBJECT_TYPE, id);
+ if (!packageConfigSO) {
return null;
}
- if (datasourceSO.error) {
- throw new Error(datasourceSO.error.message);
+ if (packageConfigSO.error) {
+ throw new Error(packageConfigSO.error.message);
}
return {
- id: datasourceSO.id,
- ...datasourceSO.attributes,
+ id: packageConfigSO.id,
+ ...packageConfigSO.attributes,
};
}
public async getByIDs(
soClient: SavedObjectsClientContract,
ids: string[]
- ): Promise {
- const datasourceSO = await soClient.bulkGet(
+ ): Promise {
+ const packageConfigSO = await soClient.bulkGet(
ids.map((id) => ({
id,
type: SAVED_OBJECT_TYPE,
}))
);
- if (!datasourceSO) {
+ if (!packageConfigSO) {
return null;
}
- return datasourceSO.saved_objects.map((so) => ({
+ return packageConfigSO.saved_objects.map((so) => ({
id: so.id,
...so.attributes,
}));
@@ -141,10 +144,10 @@ class DatasourceService {
public async list(
soClient: SavedObjectsClientContract,
options: ListWithKuery
- ): Promise<{ items: Datasource[]; total: number; page: number; perPage: number }> {
+ ): Promise<{ items: PackageConfig[]; total: number; page: number; perPage: number }> {
const { page = 1, perPage = 20, kuery } = options;
- const datasources = await soClient.find({
+ const packageConfigs = await soClient.find({
type: SAVED_OBJECT_TYPE,
page,
perPage,
@@ -158,11 +161,11 @@ class DatasourceService {
});
return {
- items: datasources.saved_objects.map((datasourceSO) => ({
- id: datasourceSO.id,
- ...datasourceSO.attributes,
+ items: packageConfigs.saved_objects.map((packageConfigSO) => ({
+ id: packageConfigSO.id,
+ ...packageConfigSO.attributes,
})),
- total: datasources.total,
+ total: packageConfigs.total,
page,
perPage,
};
@@ -171,46 +174,48 @@ class DatasourceService {
public async update(
soClient: SavedObjectsClientContract,
id: string,
- datasource: NewDatasource,
+ packageConfig: NewPackageConfig,
options?: { user?: AuthenticatedUser }
- ): Promise {
- const oldDatasource = await this.get(soClient, id);
+ ): Promise {
+ const oldPackageConfig = await this.get(soClient, id);
- if (!oldDatasource) {
- throw new Error('Datasource not found');
+ if (!oldPackageConfig) {
+ throw new Error('Package config not found');
}
- await soClient.update(SAVED_OBJECT_TYPE, id, {
- ...datasource,
- revision: oldDatasource.revision + 1,
+ await soClient.update(SAVED_OBJECT_TYPE, id, {
+ ...packageConfig,
+ revision: oldPackageConfig.revision + 1,
updated_at: new Date().toISOString(),
updated_by: options?.user?.username ?? 'system',
});
// Bump revision of associated agent config
- await agentConfigService.bumpRevision(soClient, datasource.config_id, { user: options?.user });
+ await agentConfigService.bumpRevision(soClient, packageConfig.config_id, {
+ user: options?.user,
+ });
- return (await this.get(soClient, id)) as Datasource;
+ return (await this.get(soClient, id)) as PackageConfig;
}
public async delete(
soClient: SavedObjectsClientContract,
ids: string[],
options?: { user?: AuthenticatedUser; skipUnassignFromAgentConfigs?: boolean }
- ): Promise {
- const result: DeleteDatasourcesResponse = [];
+ ): Promise {
+ const result: DeletePackageConfigsResponse = [];
for (const id of ids) {
try {
- const oldDatasource = await this.get(soClient, id);
- if (!oldDatasource) {
- throw new Error('Datasource not found');
+ const oldPackageConfig = await this.get(soClient, id);
+ if (!oldPackageConfig) {
+ throw new Error('Package config not found');
}
if (!options?.skipUnassignFromAgentConfigs) {
- await agentConfigService.unassignDatasources(
+ await agentConfigService.unassignPackageConfigs(
soClient,
- oldDatasource.config_id,
- [oldDatasource.id],
+ oldPackageConfig.config_id,
+ [oldPackageConfig.id],
{
user: options?.user,
}
@@ -232,10 +237,10 @@ class DatasourceService {
return result;
}
- public async buildDatasourceFromPackage(
+ public async buildPackageConfigFromPackage(
soClient: SavedObjectsClientContract,
pkgName: string
- ): Promise {
+ ): Promise {
const pkgInstall = await getInstallation({ savedObjectsClient: soClient, pkgName });
if (pkgInstall) {
const [pkgInfo, defaultOutputId] = await Promise.all([
@@ -250,15 +255,15 @@ class DatasourceService {
if (!defaultOutputId) {
throw new Error('Default output is not set');
}
- return packageToConfigDatasource(pkgInfo, '', defaultOutputId);
+ return packageToPackageConfig(pkgInfo, '', defaultOutputId);
}
}
}
public async assignPackageStream(
pkgInfo: PackageInfo,
- inputs: DatasourceInput[]
- ): Promise {
+ inputs: PackageConfigInput[]
+ ): Promise {
const registryPkgInfo = await Registry.fetchInfo(pkgInfo.name, pkgInfo.version);
const inputsPromises = inputs.map((input) =>
_assignPackageStreamToInput(registryPkgInfo, pkgInfo, input)
@@ -271,7 +276,7 @@ class DatasourceService {
async function _assignPackageStreamToInput(
registryPkgInfo: RegistryPackage,
pkgInfo: PackageInfo,
- input: DatasourceInput
+ input: PackageConfigInput
) {
const streamsPromises = input.streams.map((stream) =>
_assignPackageStreamToStream(registryPkgInfo, pkgInfo, input, stream)
@@ -284,11 +289,11 @@ async function _assignPackageStreamToInput(
async function _assignPackageStreamToStream(
registryPkgInfo: RegistryPackage,
pkgInfo: PackageInfo,
- input: DatasourceInput,
- stream: DatasourceInputStream
+ input: PackageConfigInput,
+ stream: PackageConfigInputStream
) {
if (!stream.enabled) {
- return { ...stream, agent_stream: undefined };
+ return { ...stream, compiled_stream: undefined };
}
const datasetPath = getDataset(stream.dataset.name);
const packageDatasets = pkgInfo.datasets;
@@ -332,10 +337,10 @@ async function _assignPackageStreamToStream(
pkgStream.buffer.toString()
);
- stream.agent_stream = yaml;
+ stream.compiled_stream = yaml;
return { ...stream };
}
-export type DatasourceServiceInterface = DatasourceService;
-export const datasourceService = new DatasourceService();
+export type PackageConfigServiceInterface = PackageConfigService;
+export const packageConfigService = new PackageConfigService();
diff --git a/x-pack/plugins/ingest_manager/server/services/setup.ts b/x-pack/plugins/ingest_manager/server/services/setup.ts
index 9cf1e5b368385..61e1d0ad94db8 100644
--- a/x-pack/plugins/ingest_manager/server/services/setup.ts
+++ b/x-pack/plugins/ingest_manager/server/services/setup.ts
@@ -13,8 +13,8 @@ import { outputService } from './output';
import { ensureInstalledDefaultPackages } from './epm/packages/install';
import { ensureDefaultIndices } from './epm/kibana/index_pattern/install';
import {
- packageToConfigDatasource,
- Datasource,
+ packageToPackageConfig,
+ PackageConfig,
AgentConfig,
Installation,
Output,
@@ -22,7 +22,7 @@ import {
decodeCloudId,
} from '../../common';
import { getPackageInfo } from './epm/packages';
-import { datasourceService } from './datasource';
+import { packageConfigService } from './package_config';
import { generateEnrollmentAPIKey } from './api_keys';
import { settingsService } from '.';
import { appContextService } from './app_context';
@@ -86,13 +86,13 @@ export async function setupIngestManager(
]);
// ensure default packages are added to the default conifg
- const configWithDatasource = await agentConfigService.get(soClient, config.id, true);
- if (!configWithDatasource) {
+ const configWithPackageConfigs = await agentConfigService.get(soClient, config.id, true);
+ if (!configWithPackageConfigs) {
throw new Error('Config not found');
}
if (
- configWithDatasource.datasources.length &&
- typeof configWithDatasource.datasources[0] === 'string'
+ configWithPackageConfigs.package_configs.length &&
+ typeof configWithPackageConfigs.package_configs[0] === 'string'
) {
throw new Error('Config not found');
}
@@ -104,11 +104,19 @@ export async function setupIngestManager(
continue;
}
- const isInstalled = configWithDatasource.datasources.some((d: Datasource | string) => {
- return typeof d !== 'string' && d.package?.name === installedPackage.name;
- });
+ const isInstalled = configWithPackageConfigs.package_configs.some(
+ (d: PackageConfig | string) => {
+ return typeof d !== 'string' && d.package?.name === installedPackage.name;
+ }
+ );
+
if (!isInstalled) {
- await addPackageToConfig(soClient, installedPackage, configWithDatasource, defaultOutput);
+ await addPackageToConfig(
+ soClient,
+ installedPackage,
+ configWithPackageConfigs,
+ defaultOutput
+ );
}
}
@@ -194,17 +202,16 @@ async function addPackageToConfig(
pkgVersion: packageToInstall.version,
});
- const newDatasource = packageToConfigDatasource(
+ const newPackageConfig = packageToPackageConfig(
packageInfo,
config.id,
defaultOutput.id,
- undefined,
config.namespace
);
- newDatasource.inputs = await datasourceService.assignPackageStream(
+ newPackageConfig.inputs = await packageConfigService.assignPackageStream(
packageInfo,
- newDatasource.inputs
+ newPackageConfig.inputs
);
- await datasourceService.create(soClient, newDatasource);
+ await packageConfigService.create(soClient, newPackageConfig);
}
diff --git a/x-pack/plugins/ingest_manager/server/types/index.tsx b/x-pack/plugins/ingest_manager/server/types/index.tsx
index eedb5d86abda3..179474d31bc18 100644
--- a/x-pack/plugins/ingest_manager/server/types/index.tsx
+++ b/x-pack/plugins/ingest_manager/server/types/index.tsx
@@ -17,11 +17,11 @@ export {
AgentEventSOAttributes,
AgentAction,
AgentActionSOAttributes,
- Datasource,
- DatasourceInput,
- DatasourceInputStream,
- NewDatasource,
- DatasourceSOAttributes,
+ PackageConfig,
+ PackageConfigInput,
+ PackageConfigInputStream,
+ NewPackageConfig,
+ PackageConfigSOAttributes,
FullAgentConfigInput,
FullAgentConfig,
AgentConfig,
diff --git a/x-pack/plugins/ingest_manager/server/types/models/agent_config.ts b/x-pack/plugins/ingest_manager/server/types/models/agent_config.ts
index ee91813a48e2f..a9e14301cd7c3 100644
--- a/x-pack/plugins/ingest_manager/server/types/models/agent_config.ts
+++ b/x-pack/plugins/ingest_manager/server/types/models/agent_config.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { schema } from '@kbn/config-schema';
-import { DatasourceSchema } from './datasource';
+import { PackageConfigSchema } from './package_config';
import { AgentConfigStatus } from '../../../common';
const AgentConfigBaseSchema = {
@@ -27,7 +27,10 @@ export const AgentConfigSchema = schema.object({
schema.literal(AgentConfigStatus.Active),
schema.literal(AgentConfigStatus.Inactive),
]),
- datasources: schema.oneOf([schema.arrayOf(schema.string()), schema.arrayOf(DatasourceSchema)]),
+ package_configs: schema.oneOf([
+ schema.arrayOf(schema.string()),
+ schema.arrayOf(PackageConfigSchema),
+ ]),
updated_at: schema.string(),
updated_by: schema.string(),
});
diff --git a/x-pack/plugins/ingest_manager/server/types/models/index.ts b/x-pack/plugins/ingest_manager/server/types/models/index.ts
index 7da36c8a18ad2..268e87eb529be 100644
--- a/x-pack/plugins/ingest_manager/server/types/models/index.ts
+++ b/x-pack/plugins/ingest_manager/server/types/models/index.ts
@@ -5,6 +5,6 @@
*/
export * from './agent_config';
export * from './agent';
-export * from './datasource';
+export * from './package_config';
export * from './output';
export * from './enrollment_api_key';
diff --git a/x-pack/plugins/ingest_manager/server/types/models/datasource.ts b/x-pack/plugins/ingest_manager/server/types/models/package_config.ts
similarity index 84%
rename from x-pack/plugins/ingest_manager/server/types/models/datasource.ts
rename to x-pack/plugins/ingest_manager/server/types/models/package_config.ts
index 114986c4a486e..4b9718dfbe165 100644
--- a/x-pack/plugins/ingest_manager/server/types/models/datasource.ts
+++ b/x-pack/plugins/ingest_manager/server/types/models/package_config.ts
@@ -13,7 +13,7 @@ const ConfigRecordSchema = schema.recordOf(
})
);
-const DatasourceBaseSchema = {
+const PackageConfigBaseSchema = {
name: schema.string(),
description: schema.maybe(schema.string()),
namespace: schema.string({ minLength: 1 }),
@@ -31,7 +31,6 @@ const DatasourceBaseSchema = {
schema.object({
type: schema.string(),
enabled: schema.boolean(),
- processors: schema.maybe(schema.arrayOf(schema.string())),
vars: schema.maybe(ConfigRecordSchema),
config: schema.maybe(
schema.recordOf(
@@ -47,7 +46,6 @@ const DatasourceBaseSchema = {
id: schema.string(),
enabled: schema.boolean(),
dataset: schema.object({ name: schema.string(), type: schema.string() }),
- processors: schema.maybe(schema.arrayOf(schema.string())),
vars: schema.maybe(ConfigRecordSchema),
config: schema.maybe(
schema.recordOf(
@@ -64,11 +62,11 @@ const DatasourceBaseSchema = {
),
};
-export const NewDatasourceSchema = schema.object({
- ...DatasourceBaseSchema,
+export const NewPackageConfigSchema = schema.object({
+ ...PackageConfigBaseSchema,
});
-export const DatasourceSchema = schema.object({
- ...DatasourceBaseSchema,
+export const PackageConfigSchema = schema.object({
+ ...PackageConfigBaseSchema,
id: schema.string(),
});
diff --git a/x-pack/plugins/ingest_manager/server/types/rest_spec/datasource.ts b/x-pack/plugins/ingest_manager/server/types/rest_spec/datasource.ts
deleted file mode 100644
index fce2c94b282bd..0000000000000
--- a/x-pack/plugins/ingest_manager/server/types/rest_spec/datasource.ts
+++ /dev/null
@@ -1,33 +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 { schema } from '@kbn/config-schema';
-import { NewDatasourceSchema } from '../models';
-import { ListWithKuerySchema } from './index';
-
-export const GetDatasourcesRequestSchema = {
- query: ListWithKuerySchema,
-};
-
-export const GetOneDatasourceRequestSchema = {
- params: schema.object({
- datasourceId: schema.string(),
- }),
-};
-
-export const CreateDatasourceRequestSchema = {
- body: NewDatasourceSchema,
-};
-
-export const UpdateDatasourceRequestSchema = {
- ...GetOneDatasourceRequestSchema,
- body: NewDatasourceSchema,
-};
-
-export const DeleteDatasourcesRequestSchema = {
- body: schema.object({
- datasourceIds: schema.arrayOf(schema.string()),
- }),
-};
diff --git a/x-pack/plugins/ingest_manager/server/types/rest_spec/index.ts b/x-pack/plugins/ingest_manager/server/types/rest_spec/index.ts
index 7dc3d4f8f1961..f3ee868f43f00 100644
--- a/x-pack/plugins/ingest_manager/server/types/rest_spec/index.ts
+++ b/x-pack/plugins/ingest_manager/server/types/rest_spec/index.ts
@@ -6,7 +6,7 @@
export * from './common';
export * from './agent_config';
export * from './agent';
-export * from './datasource';
+export * from './package_config';
export * from './epm';
export * from './enrollment_api_key';
export * from './install_script';
diff --git a/x-pack/plugins/ingest_manager/server/types/rest_spec/package_config.ts b/x-pack/plugins/ingest_manager/server/types/rest_spec/package_config.ts
new file mode 100644
index 0000000000000..7b7ae1957c15e
--- /dev/null
+++ b/x-pack/plugins/ingest_manager/server/types/rest_spec/package_config.ts
@@ -0,0 +1,33 @@
+/*
+ * 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 { schema } from '@kbn/config-schema';
+import { NewPackageConfigSchema } from '../models';
+import { ListWithKuerySchema } from './index';
+
+export const GetPackageConfigsRequestSchema = {
+ query: ListWithKuerySchema,
+};
+
+export const GetOnePackageConfigRequestSchema = {
+ params: schema.object({
+ packageConfigId: schema.string(),
+ }),
+};
+
+export const CreatePackageConfigRequestSchema = {
+ body: NewPackageConfigSchema,
+};
+
+export const UpdatePackageConfigRequestSchema = {
+ ...GetOnePackageConfigRequestSchema,
+ body: NewPackageConfigSchema,
+};
+
+export const DeletePackageConfigsRequestSchema = {
+ body: schema.object({
+ packageConfigIds: schema.arrayOf(schema.string()),
+ }),
+};
diff --git a/x-pack/plugins/ingest_pipelines/__jest__/client_integration/fixtures.ts b/x-pack/plugins/ingest_pipelines/__jest__/client_integration/fixtures.ts
new file mode 100644
index 0000000000000..8dddb2421f03d
--- /dev/null
+++ b/x-pack/plugins/ingest_pipelines/__jest__/client_integration/fixtures.ts
@@ -0,0 +1,117 @@
+/*
+ * 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 nestedProcessorsErrorFixture = {
+ attributes: {
+ error: {
+ root_cause: [
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ suppressed: [
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ suppressed: [
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'csv',
+ },
+ ],
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ ],
+ },
+ ],
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ suppressed: [
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ suppressed: [
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'csv',
+ },
+ ],
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ {
+ type: 'parse_exception',
+ reason: '[field] required property is missing',
+ property_name: 'field',
+ processor_type: 'circle',
+ },
+ ],
+ },
+ status: 400,
+ },
+};
diff --git a/x-pack/plugins/ingest_pipelines/__jest__/client_integration/helpers/pipeline_form.helpers.ts b/x-pack/plugins/ingest_pipelines/__jest__/client_integration/helpers/pipeline_form.helpers.ts
index 8a14ed13f2022..85848b3d2f73c 100644
--- a/x-pack/plugins/ingest_pipelines/__jest__/client_integration/helpers/pipeline_form.helpers.ts
+++ b/x-pack/plugins/ingest_pipelines/__jest__/client_integration/helpers/pipeline_form.helpers.ts
@@ -42,6 +42,8 @@ export type PipelineFormTestSubjects =
| 'submitButton'
| 'pageTitle'
| 'savePipelineError'
+ | 'savePipelineError.showErrorsButton'
+ | 'savePipelineError.hideErrorsButton'
| 'pipelineForm'
| 'versionToggle'
| 'versionField'
diff --git a/x-pack/plugins/ingest_pipelines/__jest__/client_integration/ingest_pipelines_create.test.tsx b/x-pack/plugins/ingest_pipelines/__jest__/client_integration/ingest_pipelines_create.test.tsx
index 2cfccbdc6d578..813057813f139 100644
--- a/x-pack/plugins/ingest_pipelines/__jest__/client_integration/ingest_pipelines_create.test.tsx
+++ b/x-pack/plugins/ingest_pipelines/__jest__/client_integration/ingest_pipelines_create.test.tsx
@@ -9,6 +9,8 @@ import { act } from 'react-dom/test-utils';
import { setupEnvironment, pageHelpers, nextTick } from './helpers';
import { PipelinesCreateTestBed } from './helpers/pipelines_create.helpers';
+import { nestedProcessorsErrorFixture } from './fixtures';
+
const { setup } = pageHelpers.pipelinesCreate;
jest.mock('@elastic/eui', () => {
@@ -163,6 +165,25 @@ describe('', () => {
expect(exists('savePipelineError')).toBe(true);
expect(find('savePipelineError').text()).toContain(error.message);
});
+
+ test('displays nested pipeline errors as a flat list', async () => {
+ const { actions, find, exists, waitFor } = testBed;
+ httpRequestsMockHelpers.setCreatePipelineResponse(undefined, {
+ body: nestedProcessorsErrorFixture,
+ });
+
+ await act(async () => {
+ actions.clickSubmitButton();
+ await waitFor('savePipelineError');
+ });
+
+ expect(exists('savePipelineError')).toBe(true);
+ expect(exists('savePipelineError.showErrorsButton')).toBe(true);
+ find('savePipelineError.showErrorsButton').simulate('click');
+ expect(exists('savePipelineError.hideErrorsButton')).toBe(true);
+ expect(exists('savePipelineError.showErrorsButton')).toBe(false);
+ expect(find('savePipelineError').find('li').length).toBe(8);
+ });
});
describe('test pipeline', () => {
diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form.tsx
index 05c9f0a08b0c7..a68e667f4ab43 100644
--- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form.tsx
+++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form.tsx
@@ -11,17 +11,18 @@ import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSpacer } from
import { useForm, Form, FormConfig } from '../../../shared_imports';
import { Pipeline } from '../../../../common/types';
-import { PipelineRequestFlyout } from './pipeline_request_flyout';
-import { PipelineTestFlyout } from './pipeline_test_flyout';
-import { PipelineFormFields } from './pipeline_form_fields';
-import { PipelineFormError } from './pipeline_form_error';
-import { pipelineFormSchema } from './schema';
import {
OnUpdateHandlerArg,
OnUpdateHandler,
SerializeResult,
} from '../pipeline_processors_editor';
+import { PipelineRequestFlyout } from './pipeline_request_flyout';
+import { PipelineTestFlyout } from './pipeline_test_flyout';
+import { PipelineFormFields } from './pipeline_form_fields';
+import { PipelineFormError } from './pipeline_form_error';
+import { pipelineFormSchema } from './schema';
+
export interface PipelineFormProps {
onSave: (pipeline: Pipeline) => void;
onCancel: () => void;
@@ -116,7 +117,7 @@ export const PipelineForm: React.FunctionComponent = ({
error={form.getErrors()}
>
{/* Request error */}
- {saveError && }
+ {saveError && }
{/* All form fields */}
= ({ errorMessage }) => {
- return (
- <>
-
- }
- color="danger"
- iconType="alert"
- data-test-subj="savePipelineError"
- >
- {errorMessage}
-
-
- >
- );
-};
diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/error_utils.test.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/error_utils.test.ts
new file mode 100644
index 0000000000000..1739365eb197d
--- /dev/null
+++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/error_utils.test.ts
@@ -0,0 +1,67 @@
+/*
+ * 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 { toKnownError } from './error_utils';
+import { nestedProcessorsErrorFixture } from '../../../../../__jest__/client_integration/fixtures';
+
+describe('toKnownError', () => {
+ test('undefined, null, numbers, arrays and bad objects', () => {
+ expect(toKnownError(undefined)).toEqual({ errors: [{ reason: 'An unknown error occurred.' }] });
+ expect(toKnownError(null)).toEqual({ errors: [{ reason: 'An unknown error occurred.' }] });
+ expect(toKnownError(123)).toEqual({ errors: [{ reason: 'An unknown error occurred.' }] });
+ expect(toKnownError([])).toEqual({ errors: [{ reason: 'An unknown error occurred.' }] });
+ expect(toKnownError({})).toEqual({ errors: [{ reason: 'An unknown error occurred.' }] });
+ expect(toKnownError({ attributes: {} })).toEqual({
+ errors: [{ reason: 'An unknown error occurred.' }],
+ });
+ });
+
+ test('non-processors errors', () => {
+ expect(toKnownError(new Error('my error'))).toEqual({ errors: [{ reason: 'my error' }] });
+ expect(toKnownError({ message: 'my error' })).toEqual({ errors: [{ reason: 'my error' }] });
+ });
+
+ test('processors errors', () => {
+ expect(toKnownError(nestedProcessorsErrorFixture)).toMatchInlineSnapshot(`
+ Object {
+ "errors": Array [
+ Object {
+ "processorType": "circle",
+ "reason": "[field] required property is missing",
+ },
+ Object {
+ "processorType": "circle",
+ "reason": "[field] required property is missing",
+ },
+ Object {
+ "processorType": "circle",
+ "reason": "[field] required property is missing",
+ },
+ Object {
+ "processorType": "csv",
+ "reason": "[field] required property is missing",
+ },
+ Object {
+ "processorType": "circle",
+ "reason": "[field] required property is missing",
+ },
+ Object {
+ "processorType": "circle",
+ "reason": "[field] required property is missing",
+ },
+ Object {
+ "processorType": "circle",
+ "reason": "[field] required property is missing",
+ },
+ Object {
+ "processorType": "circle",
+ "reason": "[field] required property is missing",
+ },
+ ],
+ }
+ `);
+ });
+});
diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/error_utils.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/error_utils.ts
new file mode 100644
index 0000000000000..7f32f962f657c
--- /dev/null
+++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/error_utils.ts
@@ -0,0 +1,85 @@
+/*
+ * 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 * as t from 'io-ts';
+import { flow } from 'fp-ts/lib/function';
+import { isRight } from 'fp-ts/lib/Either';
+
+import { i18nTexts } from './i18n_texts';
+
+export interface PipelineError {
+ reason: string;
+ processorType?: string;
+}
+interface PipelineErrors {
+ errors: PipelineError[];
+}
+
+interface ErrorNode {
+ reason: string;
+ processor_type?: string;
+ suppressed?: ErrorNode[];
+}
+
+// This is a runtime type (RT) for an error node which is a recursive type
+const errorNodeRT = t.recursion('ErrorNode', (ErrorNode) =>
+ t.intersection([
+ t.interface({
+ reason: t.string,
+ }),
+ t.partial({
+ processor_type: t.string,
+ suppressed: t.array(ErrorNode),
+ }),
+ ])
+);
+
+// This is a runtime type for the attributes object we expect to receive from the server
+// for processor errors
+const errorAttributesObjectRT = t.interface({
+ attributes: t.interface({
+ error: t.interface({
+ root_cause: t.array(errorNodeRT),
+ }),
+ }),
+});
+
+const isProcessorsError = flow(errorAttributesObjectRT.decode, isRight);
+
+type ErrorAttributesObject = t.TypeOf;
+
+const flattenErrorsTree = (node: ErrorNode): PipelineError[] => {
+ const result: PipelineError[] = [];
+ const recurse = (_node: ErrorNode) => {
+ result.push({ reason: _node.reason, processorType: _node.processor_type });
+ if (_node.suppressed && Array.isArray(_node.suppressed)) {
+ _node.suppressed.forEach(recurse);
+ }
+ };
+ recurse(node);
+ return result;
+};
+
+export const toKnownError = (error: unknown): PipelineErrors => {
+ if (typeof error === 'object' && error != null && isProcessorsError(error)) {
+ const errorAttributes = error as ErrorAttributesObject;
+ const rootCause = errorAttributes.attributes.error.root_cause[0];
+ return { errors: flattenErrorsTree(rootCause) };
+ }
+
+ if (typeof error === 'string') {
+ return { errors: [{ reason: error }] };
+ }
+
+ if (
+ error instanceof Error ||
+ (typeof error === 'object' && error != null && (error as any).message)
+ ) {
+ return { errors: [{ reason: (error as any).message }] };
+ }
+
+ return { errors: [{ reason: i18nTexts.errors.unknownError }] };
+};
diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/i18n_texts.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/i18n_texts.ts
new file mode 100644
index 0000000000000..e354541db8e7b
--- /dev/null
+++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/i18n_texts.ts
@@ -0,0 +1,38 @@
+/*
+ * 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 { i18n } from '@kbn/i18n';
+
+export const i18nTexts = {
+ title: i18n.translate('xpack.ingestPipelines.form.savePipelineError', {
+ defaultMessage: 'Unable to create pipeline',
+ }),
+ errors: {
+ processor: (processorType: string) =>
+ i18n.translate('xpack.ingestPipelines.form.savePipelineError.processorLabel', {
+ defaultMessage: '{type} processor',
+ values: { type: processorType },
+ }),
+ showErrors: (hiddenErrorsCount: number) =>
+ i18n.translate('xpack.ingestPipelines.form.savePipelineError.showAllButton', {
+ defaultMessage:
+ 'Show {hiddenErrorsCount, plural, one {# more error} other {# more errors}}',
+ values: {
+ hiddenErrorsCount,
+ },
+ }),
+ hideErrors: (hiddenErrorsCount: number) =>
+ i18n.translate('xpack.ingestPipelines.form.savePip10mbelineError.showFewerButton', {
+ defaultMessage: 'Hide {hiddenErrorsCount, plural, one {# error} other {# errors}}',
+ values: {
+ hiddenErrorsCount,
+ },
+ }),
+ unknownError: i18n.translate('xpack.ingestPipelines.form.unknownError', {
+ defaultMessage: 'An unknown error occurred.',
+ }),
+ },
+};
diff --git a/x-pack/plugins/ingest_manager/common/constants/datasource.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/index.ts
similarity index 78%
rename from x-pack/plugins/ingest_manager/common/constants/datasource.ts
rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/index.ts
index 08113cff53bda..656691f639498 100644
--- a/x-pack/plugins/ingest_manager/common/constants/datasource.ts
+++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export const DATASOURCE_SAVED_OBJECT_TYPE = 'ingest-datasources';
+export { PipelineFormError } from './pipeline_form_error';
diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/pipeline_form_error.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/pipeline_form_error.tsx
new file mode 100644
index 0000000000000..23fb9a1648434
--- /dev/null
+++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error/pipeline_form_error.tsx
@@ -0,0 +1,99 @@
+/*
+ * 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 React, { useState, useEffect } from 'react';
+
+import { EuiSpacer, EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
+import { useKibana } from '../../../../shared_imports';
+
+import { i18nTexts } from './i18n_texts';
+import { toKnownError, PipelineError } from './error_utils';
+
+interface Props {
+ error: unknown;
+}
+
+const numberOfErrorsToDisplay = 5;
+
+export const PipelineFormError: React.FunctionComponent = ({ error }) => {
+ const { services } = useKibana();
+ const [isShowingAllErrors, setIsShowingAllErrors] = useState(false);
+ const safeErrorResult = toKnownError(error);
+ const hasMoreErrors = safeErrorResult.errors.length > numberOfErrorsToDisplay;
+ const hiddenErrorsCount = safeErrorResult.errors.length - numberOfErrorsToDisplay;
+ const results = isShowingAllErrors
+ ? safeErrorResult.errors
+ : safeErrorResult.errors.slice(0, numberOfErrorsToDisplay);
+
+ const renderErrorListItem = ({ processorType, reason }: PipelineError) => {
+ return (
+ <>
+ {processorType ? <>{i18nTexts.errors.processor(processorType) + ':'} > : undefined}
+ {reason}
+ >
+ );
+ };
+
+ useEffect(() => {
+ services.notifications.toasts.addDanger({ title: i18nTexts.title });
+ }, [services, error]);
+ return (
+ <>
+
+ {results.length > 1 ? (
+
+ {results.map((e, idx) => (
+ - {renderErrorListItem(e)}
+ ))}
+
+ ) : (
+ renderErrorListItem(results[0])
+ )}
+ {hasMoreErrors ? (
+
+
+ {isShowingAllErrors ? (
+ setIsShowingAllErrors(false)}
+ color="danger"
+ iconSide="right"
+ iconType="arrowUp"
+ data-test-subj="hideErrorsButton"
+ >
+ {i18nTexts.errors.hideErrors(hiddenErrorsCount)}
+
+ ) : (
+ setIsShowingAllErrors(true)}
+ color="danger"
+ iconSide="right"
+ iconType="arrowDown"
+ data-test-subj="showErrorsButton"
+ >
+ {i18nTexts.errors.showErrors(hiddenErrorsCount)}
+
+ )}
+
+
+ ) : undefined}
+
+
+ >
+ );
+};
diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts
index c1ab3852ee784..c2328bcc9d0ab 100644
--- a/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts
+++ b/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts
@@ -10,6 +10,7 @@ import { Pipeline } from '../../../common/types';
import { API_BASE_PATH } from '../../../common/constants';
import { RouteDependencies } from '../../types';
import { pipelineSchema } from './pipeline_schema';
+import { isObjectWithKeys } from './shared';
const bodySchema = schema.object({
name: schema.string(),
@@ -70,7 +71,12 @@ export const registerCreateRoute = ({
if (isEsError(error)) {
return res.customError({
statusCode: error.statusCode,
- body: error,
+ body: isObjectWithKeys(error.body)
+ ? {
+ message: error.message,
+ attributes: error.body,
+ }
+ : error,
});
}
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/types.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/shared/index.ts
similarity index 60%
rename from x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/types.ts
rename to x-pack/plugins/ingest_pipelines/server/routes/api/shared/index.ts
index 10b30a5696d83..1fa794a4fb996 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/types.ts
+++ b/x-pack/plugins/ingest_pipelines/server/routes/api/shared/index.ts
@@ -4,5 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export type CreateDatasourceFrom = 'package' | 'config' | 'edit';
-export type DatasourceFormState = 'VALID' | 'INVALID' | 'CONFIRM' | 'LOADING' | 'SUBMITTED';
+export { isObjectWithKeys } from './is_object_with_keys';
diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/shared/is_object_with_keys.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/shared/is_object_with_keys.ts
new file mode 100644
index 0000000000000..0617bde26cfb6
--- /dev/null
+++ b/x-pack/plugins/ingest_pipelines/server/routes/api/shared/is_object_with_keys.ts
@@ -0,0 +1,9 @@
+/*
+ * 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 isObjectWithKeys = (value: unknown) => {
+ return typeof value === 'object' && !!value && Object.keys(value).length > 0;
+};
diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts
index 214b293a43c6c..cd0e3568f0f60 100644
--- a/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts
+++ b/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts
@@ -8,6 +8,7 @@ import { schema } from '@kbn/config-schema';
import { API_BASE_PATH } from '../../../common/constants';
import { RouteDependencies } from '../../types';
import { pipelineSchema } from './pipeline_schema';
+import { isObjectWithKeys } from './shared';
const bodySchema = schema.object(pipelineSchema);
@@ -52,7 +53,12 @@ export const registerUpdateRoute = ({
if (isEsError(error)) {
return res.customError({
statusCode: error.statusCode,
- body: error,
+ body: isObjectWithKeys(error.body)
+ ? {
+ message: error.message,
+ attributes: error.body,
+ }
+ : error,
});
}
diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx
index a1c084f83e447..e4dbc64184528 100644
--- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx
+++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx
@@ -27,6 +27,14 @@ import { OperationMetadata } from '../../types';
jest.mock('../loader');
jest.mock('../state_helpers');
+jest.mock('lodash', () => {
+ const original = jest.requireActual('lodash');
+
+ return {
+ ...original,
+ debounce: (fn: unknown) => fn,
+ };
+});
const expectedIndexPatterns = {
1: {
diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx
index eb2475756417e..34a4384ec0d40 100644
--- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx
+++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx
@@ -6,7 +6,7 @@
import './popover_editor.scss';
import _ from 'lodash';
-import React, { useState, useMemo } from 'react';
+import React, { useState, useMemo, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiFlexItem,
@@ -56,6 +56,31 @@ function asOperationOptions(operationTypes: OperationType[], compatibleWithCurre
}));
}
+const LabelInput = ({ value, onChange }: { value: string; onChange: (value: string) => void }) => {
+ const [inputValue, setInputValue] = useState(value);
+
+ useEffect(() => {
+ setInputValue(value);
+ }, [value, setInputValue]);
+
+ const onChangeDebounced = useMemo(() => _.debounce(onChange, 256), [onChange]);
+
+ const handleInputChange = (e: React.ChangeEvent) => {
+ const val = String(e.target.value);
+ setInputValue(val);
+ onChangeDebounced(val);
+ };
+
+ return (
+
+ );
+};
+
export function PopoverEditor(props: PopoverEditorProps) {
const {
selectedColumn,
@@ -320,11 +345,9 @@ export function PopoverEditor(props: PopoverEditorProps) {
})}
display="rowCompressed"
>
- {
+ onChange={(value) => {
setState({
...state,
layers: {
@@ -335,7 +358,7 @@ export function PopoverEditor(props: PopoverEditorProps) {
...state.layers[layerId].columns,
[columnId]: {
...selectedColumn,
- label: e.target.value,
+ label: value,
customLabel: true,
},
},
diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.test.ts b/x-pack/plugins/lists/common/schemas/common/schemas.test.ts
index eed5be39b7a03..d426a91e71b9e 100644
--- a/x-pack/plugins/lists/common/schemas/common/schemas.test.ts
+++ b/x-pack/plugins/lists/common/schemas/common/schemas.test.ts
@@ -9,7 +9,7 @@ import { left } from 'fp-ts/lib/Either';
import { foldLeftRight, getPaths } from '../../siem_common_deps';
-import { operator_type as operatorType } from './schemas';
+import { operator, operator_type as operatorType } from './schemas';
describe('Common schemas', () => {
describe('operatorType', () => {
@@ -60,4 +60,35 @@ describe('Common schemas', () => {
expect(keys.length).toEqual(4);
});
});
+
+ describe('operator', () => {
+ test('it should validate for "included"', () => {
+ const payload = 'included';
+ const decoded = operator.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([]);
+ expect(message.schema).toEqual(payload);
+ });
+
+ test('it should validate for "excluded"', () => {
+ const payload = 'excluded';
+ const decoded = operator.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([]);
+ expect(message.schema).toEqual(payload);
+ });
+
+ test('it should contain 2 keys', () => {
+ // Might seem like a weird test, but its meant to
+ // ensure that if operator is updated, you
+ // also update the operatorEnum, a workaround
+ // for io-ts not yet supporting enums
+ // https://github.com/gcanti/io-ts/issues/67
+ const keys = Object.keys(operator.keys);
+
+ expect(keys.length).toEqual(2);
+ });
+ });
});
diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.ts b/x-pack/plugins/lists/common/schemas/common/schemas.ts
index fea8a219bc774..a91f487cfa274 100644
--- a/x-pack/plugins/lists/common/schemas/common/schemas.ts
+++ b/x-pack/plugins/lists/common/schemas/common/schemas.ts
@@ -130,6 +130,10 @@ export type NamespaceType = t.TypeOf;
export const operator = t.keyof({ excluded: null, included: null });
export type Operator = t.TypeOf;
+export enum OperatorEnum {
+ INCLUDED = 'included',
+ EXCLUDED = 'excluded',
+}
export const operator_type = t.keyof({
exists: null,
diff --git a/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.test.tsx b/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.test.ts
similarity index 100%
rename from x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.test.tsx
rename to x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.test.ts
diff --git a/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.tsx b/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.ts
similarity index 100%
rename from x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.tsx
rename to x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.ts
diff --git a/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.test.tsx b/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.test.ts
similarity index 100%
rename from x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.test.tsx
rename to x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.test.ts
diff --git a/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.tsx b/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.ts
similarity index 100%
rename from x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.tsx
rename to x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.ts
diff --git a/x-pack/plugins/lists/public/exceptions/hooks/use_api.test.tsx b/x-pack/plugins/lists/public/exceptions/hooks/use_api.test.ts
similarity index 100%
rename from x-pack/plugins/lists/public/exceptions/hooks/use_api.test.tsx
rename to x-pack/plugins/lists/public/exceptions/hooks/use_api.test.ts
diff --git a/x-pack/plugins/lists/public/exceptions/hooks/use_api.tsx b/x-pack/plugins/lists/public/exceptions/hooks/use_api.ts
similarity index 100%
rename from x-pack/plugins/lists/public/exceptions/hooks/use_api.tsx
rename to x-pack/plugins/lists/public/exceptions/hooks/use_api.ts
diff --git a/x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.test.tsx b/x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.test.ts
similarity index 100%
rename from x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.test.tsx
rename to x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.test.ts
diff --git a/x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.tsx b/x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.ts
similarity index 100%
rename from x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.tsx
rename to x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.ts
diff --git a/x-pack/plugins/lists/server/mocks.ts b/x-pack/plugins/lists/server/mocks.ts
index aad4a25a900a1..ba565216fe431 100644
--- a/x-pack/plugins/lists/server/mocks.ts
+++ b/x-pack/plugins/lists/server/mocks.ts
@@ -18,6 +18,6 @@ const createSetupMock = (): jest.Mocked => {
export const listMock = {
createSetup: createSetupMock,
- getExceptionList: getExceptionListClientMock,
+ getExceptionListClient: getExceptionListClientMock,
getListClient: getListClientMock,
};
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts
index ac455120dca83..a423722d1447a 100644
--- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts
+++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts
@@ -129,7 +129,7 @@ export interface Eval {
export interface RegressionEvaluateResponse {
regression: {
mean_squared_error: {
- error: number;
+ value: number;
};
r_squared: {
value: number;
@@ -410,7 +410,7 @@ export const useRefreshAnalyticsList = (
const DEFAULT_SIG_FIGS = 3;
export function getValuesFromResponse(response: RegressionEvaluateResponse) {
- let meanSquaredError = response?.regression?.mean_squared_error?.error;
+ let meanSquaredError = response?.regression?.mean_squared_error?.value;
if (meanSquaredError) {
meanSquaredError = Number(meanSquaredError.toPrecision(DEFAULT_SIG_FIGS));
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_step/progress_stats.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_step/progress_stats.tsx
index 8cee63d3c4c84..a50254334526c 100644
--- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_step/progress_stats.tsx
+++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_step/progress_stats.tsx
@@ -5,7 +5,14 @@
*/
import React, { FC, useState, useEffect } from 'react';
-import { EuiFlexGroup, EuiFlexItem, EuiProgress, EuiSpacer, EuiText } from '@elastic/eui';
+import {
+ EuiCallOut,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiProgress,
+ EuiSpacer,
+ EuiText,
+} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useMlKibana } from '../../../../../contexts/kibana';
import { getDataFrameAnalyticsProgressPhase } from '../../../analytics_management/components/analytics_list/common';
@@ -14,9 +21,11 @@ import { ml } from '../../../../../services/ml_api_service';
import { DataFrameAnalyticsId } from '../../../../common/analytics';
export const PROGRESS_REFRESH_INTERVAL_MS = 1000;
+const FAILED = 'failed';
export const ProgressStats: FC<{ jobId: DataFrameAnalyticsId }> = ({ jobId }) => {
const [initialized, setInitialized] = useState(false);
+ const [failedJobMessage, setFailedJobMessage] = useState(undefined);
const [currentProgress, setCurrentProgress] = useState<
| {
currentPhase: number;
@@ -44,6 +53,21 @@ export const ProgressStats: FC<{ jobId: DataFrameAnalyticsId }> = ({ jobId }) =>
if (jobStats !== undefined) {
const progressStats = getDataFrameAnalyticsProgressPhase(jobStats);
+
+ if (jobStats.state === FAILED) {
+ clearInterval(interval);
+ setFailedJobMessage(
+ jobStats.failure_reason ||
+ i18n.translate(
+ 'xpack.ml.dataframe.analytics.create.analyticsProgressCalloutMessage',
+ {
+ defaultMessage: 'Analytics job {jobId} has failed.',
+ values: { jobId },
+ }
+ )
+ );
+ }
+
setCurrentProgress(progressStats);
if (
progressStats.currentPhase === progressStats.totalPhases &&
@@ -73,6 +97,25 @@ export const ProgressStats: FC<{ jobId: DataFrameAnalyticsId }> = ({ jobId }) =>
return (
<>
+ {failedJobMessage !== undefined && (
+ <>
+
+ {failedJobMessage}
+
+
+ >
+ )}
{i18n.translate('xpack.ml.dataframe.analytics.create.analyticsProgressTitle', {
diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js
index c087d20a97db1..ba6d0cb926f06 100644
--- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js
+++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js
@@ -77,11 +77,11 @@ export function handleResponse(resp, min, max, shardStats) {
});
}
-export function getIndices(req, esIndexPattern, showSystemIndices = false, shardStats) {
- checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getIndices');
-
- const { min, max } = req.payload.timeRange;
-
+export function buildGetIndicesQuery(
+ esIndexPattern,
+ clusterUuid,
+ { start, end, size, showSystemIndices = false }
+) {
const filters = [];
if (!showSystemIndices) {
filters.push({
@@ -90,14 +90,11 @@ export function getIndices(req, esIndexPattern, showSystemIndices = false, shard
},
});
}
-
- const clusterUuid = req.params.clusterUuid;
const metricFields = ElasticsearchMetric.getMetricFields();
- const config = req.server.config();
- const params = {
+
+ return {
index: esIndexPattern,
- // TODO: composite aggregation
- size: config.get('monitoring.ui.max_bucket_size'),
+ size,
ignoreUnavailable: true,
filterPath: [
// only filter path can filter for inner_hits
@@ -118,8 +115,8 @@ export function getIndices(req, esIndexPattern, showSystemIndices = false, shard
body: {
query: createQuery({
type: 'index_stats',
- start: min,
- end: max,
+ start,
+ end,
clusterUuid,
metric: metricFields,
filters,
@@ -135,9 +132,24 @@ export function getIndices(req, esIndexPattern, showSystemIndices = false, shard
sort: [{ timestamp: { order: 'desc' } }],
},
};
+}
+
+export function getIndices(req, esIndexPattern, showSystemIndices = false, shardStats) {
+ checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getIndices');
+
+ const { min: start, max: end } = req.payload.timeRange;
+
+ const clusterUuid = req.params.clusterUuid;
+ const config = req.server.config();
+ const params = buildGetIndicesQuery(esIndexPattern, clusterUuid, {
+ start,
+ end,
+ showSystemIndices,
+ size: config.get('monitoring.ui.max_bucket_size'),
+ });
const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
return callWithRequest(req, 'search', params).then((resp) =>
- handleResponse(resp, min, max, shardStats)
+ handleResponse(resp, start, end, shardStats)
);
}
diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/index.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/index.js
index 0ac2610bbba62..b07e3511d4804 100644
--- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/index.js
+++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/index.js
@@ -4,5 +4,5 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { getIndices } from './get_indices';
+export { getIndices, buildGetIndicesQuery } from './get_indices';
export { getIndexSummary } from './get_index_summary';
diff --git a/x-pack/plugins/painless_lab/public/plugin.tsx b/x-pack/plugins/painless_lab/public/plugin.tsx
index 1ea6991d6023e..a5e88c8eb7fde 100644
--- a/x-pack/plugins/painless_lab/public/plugin.tsx
+++ b/x-pack/plugins/painless_lab/public/plugin.tsx
@@ -5,10 +5,10 @@
*/
import React from 'react';
-import { i18n } from '@kbn/i18n';
-import { Plugin, CoreStart, CoreSetup } from 'kibana/public';
import { first } from 'rxjs/operators';
import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { Plugin, CoreSetup } from 'src/core/public';
import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public';
@@ -27,7 +27,7 @@ const checkLicenseStatus = (license: ILicense) => {
export class PainlessLabUIPlugin implements Plugin {
languageService = new LanguageService();
- async setup(
+ public setup(
{ http, getStartServices, uiSettings }: CoreSetup,
{ devTools, home, licensing }: PluginDependencies
) {
@@ -70,7 +70,7 @@ export class PainlessLabUIPlugin implements Plugin {
+ mount: async ({ element }) => {
const [core] = await getStartServices();
const {
@@ -115,9 +115,9 @@ export class PainlessLabUIPlugin implements Plugin {
};
export class SearchProfilerUIPlugin implements Plugin {
- constructor(ctx: PluginInitializerContext) {}
-
- async setup(
+ public setup(
{ http, getStartServices }: CoreSetup,
{ devTools, home, licensing }: AppPublicPluginDependencies
) {
@@ -47,7 +45,7 @@ export class SearchProfilerUIPlugin implements Plugin {
+ mount: async (params) => {
const [coreStart] = await getStartServices();
const { notifications, i18n: i18nDep } = coreStart;
const { boot } = await import('./application/boot');
@@ -74,7 +72,7 @@ export class SearchProfilerUIPlugin implements Plugin;
+
+export const authorOrUndefined = t.union([author, t.undefined]);
+export type AuthorOrUndefined = t.TypeOf;
+
+export const building_block_type = t.string;
+export type BuildingBlockType = t.TypeOf;
+
+export const buildingBlockTypeOrUndefined = t.union([building_block_type, t.undefined]);
+export type BuildingBlockTypeOrUndefined = t.TypeOf;
+
export const description = t.string;
export type Description = t.TypeOf;
@@ -111,6 +123,12 @@ export type Language = t.TypeOf;
export const languageOrUndefined = t.union([language, t.undefined]);
export type LanguageOrUndefined = t.TypeOf;
+export const license = t.string;
+export type License = t.TypeOf;
+
+export const licenseOrUndefined = t.union([license, t.undefined]);
+export type LicenseOrUndefined = t.TypeOf;
+
export const objects = t.array(t.type({ rule_id }));
export const output_index = t.string;
@@ -137,6 +155,12 @@ export type TimelineTitle = t.TypeOf;
export const timelineTitleOrUndefined = t.union([timeline_title, t.undefined]);
export type TimelineTitleOrUndefined = t.TypeOf;
+export const timestamp_override = t.string;
+export type TimestampOverride = t.TypeOf;
+
+export const timestampOverrideOrUndefined = t.union([timestamp_override, t.undefined]);
+export type TimestampOverrideOrUndefined = t.TypeOf;
+
export const throttle = t.string;
export type Throttle = t.TypeOf;
@@ -179,18 +203,65 @@ export type Name = t.TypeOf;
export const nameOrUndefined = t.union([name, t.undefined]);
export type NameOrUndefined = t.TypeOf;
+export const operator = t.keyof({
+ equals: null,
+});
+export type Operator = t.TypeOf;
+export enum OperatorEnum {
+ EQUALS = 'equals',
+}
+
export const risk_score = RiskScore;
export type RiskScore = t.TypeOf;
export const riskScoreOrUndefined = t.union([risk_score, t.undefined]);
export type RiskScoreOrUndefined = t.TypeOf;
+export const risk_score_mapping_field = t.string;
+export const risk_score_mapping_value = t.string;
+export const risk_score_mapping_item = t.exact(
+ t.type({
+ field: risk_score_mapping_field,
+ operator,
+ value: risk_score_mapping_value,
+ })
+);
+
+export const risk_score_mapping = t.array(risk_score_mapping_item);
+export type RiskScoreMapping = t.TypeOf;
+
+export const riskScoreMappingOrUndefined = t.union([risk_score_mapping, t.undefined]);
+export type RiskScoreMappingOrUndefined = t.TypeOf;
+
+export const rule_name_override = t.string;
+export type RuleNameOverride = t.TypeOf;
+
+export const ruleNameOverrideOrUndefined = t.union([rule_name_override, t.undefined]);
+export type RuleNameOverrideOrUndefined = t.TypeOf;
+
export const severity = t.keyof({ low: null, medium: null, high: null, critical: null });
export type Severity = t.TypeOf;
export const severityOrUndefined = t.union([severity, t.undefined]);
export type SeverityOrUndefined = t.TypeOf;
+export const severity_mapping_field = t.string;
+export const severity_mapping_value = t.string;
+export const severity_mapping_item = t.exact(
+ t.type({
+ field: severity_mapping_field,
+ operator,
+ value: severity_mapping_value,
+ severity,
+ })
+);
+
+export const severity_mapping = t.array(severity_mapping_item);
+export type SeverityMapping = t.TypeOf;
+
+export const severityMappingOrUndefined = t.union([severity_mapping, t.undefined]);
+export type SeverityMappingOrUndefined = t.TypeOf;
+
export const status = t.keyof({ open: null, closed: null, 'in-progress': null });
export type Status = t.TypeOf;
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts
index 52a210f3a01aa..b666b95ea1e97 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts
@@ -23,12 +23,15 @@ export const getAddPrepackagedRulesSchemaMock = (): AddPrepackagedRulesSchema =>
});
export const getAddPrepackagedRulesSchemaDecodedMock = (): AddPrepackagedRulesSchemaDecoded => ({
+ author: [],
description: 'some description',
name: 'Query with a rule id',
query: 'user.name: root or user.name: admin',
severity: 'high',
+ severity_mapping: [],
type: 'query',
risk_score: 55,
+ risk_score_mapping: [],
language: 'kuery',
references: [],
actions: [],
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts
index 43000f6d36f46..bf96be5e688fa 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts
@@ -37,6 +37,13 @@ import {
query,
rule_id,
version,
+ building_block_type,
+ license,
+ rule_name_override,
+ timestamp_override,
+ Author,
+ RiskScoreMapping,
+ SeverityMapping,
} from '../common/schemas';
/* eslint-enable @typescript-eslint/camelcase */
@@ -52,6 +59,8 @@ import {
DefaultThrottleNull,
DefaultListArray,
ListArray,
+ DefaultRiskScoreMappingArray,
+ DefaultSeverityMappingArray,
} from '../types';
/**
@@ -79,6 +88,8 @@ export const addPrepackagedRulesSchema = t.intersection([
t.partial({
actions: DefaultActionsArray, // defaults to empty actions array if not set during decode
anomaly_threshold, // defaults to undefined if not set during decode
+ author: DefaultStringArray, // defaults to empty array of strings if not set during decode
+ building_block_type, // defaults to undefined if not set during decode
enabled: DefaultBooleanFalse, // defaults to false if not set during decode
false_positives: DefaultStringArray, // defaults to empty string array if not set during decode
filters, // defaults to undefined if not set during decode
@@ -87,16 +98,21 @@ export const addPrepackagedRulesSchema = t.intersection([
interval: DefaultIntervalString, // defaults to "5m" if not set during decode
query, // defaults to undefined if not set during decode
language, // defaults to undefined if not set during decode
+ license, // defaults to "undefined" if not set during decode
saved_id, // defaults to "undefined" if not set during decode
timeline_id, // defaults to "undefined" if not set during decode
timeline_title, // defaults to "undefined" if not set during decode
meta, // defaults to "undefined" if not set during decode
machine_learning_job_id, // defaults to "undefined" if not set during decode
max_signals: DefaultMaxSignalsNumber, // defaults to DEFAULT_MAX_SIGNALS (100) if not set during decode
+ risk_score_mapping: DefaultRiskScoreMappingArray, // defaults to empty risk score mapping array if not set during decode
+ rule_name_override, // defaults to "undefined" if not set during decode
+ severity_mapping: DefaultSeverityMappingArray, // defaults to empty actions array if not set during decode
tags: DefaultStringArray, // defaults to empty string array if not set during decode
to: DefaultToString, // defaults to "now" if not set during decode
threat: DefaultThreatArray, // defaults to empty array if not set during decode
throttle: DefaultThrottleNull, // defaults to "null" if not set during decode
+ timestamp_override, // defaults to "undefined" if not set during decode
references: DefaultStringArray, // defaults to empty array of strings if not set during decode
note, // defaults to "undefined" if not set during decode
exceptions_list: DefaultListArray, // defaults to empty array if not set during decode
@@ -109,6 +125,7 @@ export type AddPrepackagedRulesSchema = t.TypeOf & {
+ author: Author;
references: References;
actions: Actions;
enabled: Enabled;
@@ -129,6 +149,8 @@ export type AddPrepackagedRulesSchemaDecoded = Omit<
from: From;
interval: Interval;
max_signals: MaxSignals;
+ risk_score_mapping: RiskScoreMapping;
+ severity_mapping: SeverityMapping;
tags: Tags;
to: To;
threat: Threat;
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackged_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackged_rules_schema.test.ts
index 47a98166927b4..0c45a7b1ef6bb 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackged_rules_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackged_rules_schema.test.ts
@@ -261,6 +261,9 @@ describe('add prepackaged rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: AddPrepackagedRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -333,6 +336,9 @@ describe('add prepackaged rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: AddPrepackagedRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -430,6 +436,9 @@ describe('add prepackaged rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: AddPrepackagedRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -508,6 +517,9 @@ describe('add prepackaged rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: AddPrepackagedRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -1354,6 +1366,9 @@ describe('add prepackaged rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: AddPrepackagedRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1404,6 +1419,9 @@ describe('add prepackaged rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: AddPrepackagedRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1462,6 +1480,9 @@ describe('add prepackaged rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: AddPrepackagedRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1539,6 +1560,9 @@ describe('add prepackaged rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: AddPrepackagedRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.mock.ts
index 2847bd32df514..f1e87bdb11e75 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.mock.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.mock.ts
@@ -30,6 +30,9 @@ export const getCreateMlRulesSchemaMock = (ruleId = 'rule-1') => {
};
export const getCreateRulesSchemaDecodedMock = (): CreateRulesSchemaDecoded => ({
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
description: 'Detecting root and admin users',
name: 'Query with a rule id',
query: 'user.name: root or user.name: admin',
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.test.ts
index 1648044f5305a..e529cf3fa555c 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.test.ts
@@ -248,6 +248,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -318,6 +321,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -366,6 +372,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -412,6 +421,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -438,6 +450,9 @@ describe('create rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index] does validate', () => {
const payload: CreateRulesSchema = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -456,6 +471,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -535,6 +553,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -1228,6 +1249,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1399,6 +1423,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
type: 'machine_learning',
anomaly_threshold: 50,
machine_learning_job_id: 'linux_anomalous_network_activity_ecs',
@@ -1459,6 +1486,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1516,6 +1546,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1591,6 +1624,9 @@ describe('create rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: CreateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.ts
index d623cff8f1fc3..0debe01e5a4d7 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.ts
@@ -10,6 +10,7 @@ import * as t from 'io-ts';
import {
description,
anomaly_threshold,
+ building_block_type,
filters,
RuleId,
index,
@@ -38,6 +39,12 @@ import {
Interval,
language,
query,
+ license,
+ rule_name_override,
+ timestamp_override,
+ Author,
+ RiskScoreMapping,
+ SeverityMapping,
} from '../common/schemas';
/* eslint-enable @typescript-eslint/camelcase */
@@ -55,6 +62,8 @@ import {
DefaultListArray,
ListArray,
DefaultUuid,
+ DefaultRiskScoreMappingArray,
+ DefaultSeverityMappingArray,
} from '../types';
export const createRulesSchema = t.intersection([
@@ -71,6 +80,8 @@ export const createRulesSchema = t.intersection([
t.partial({
actions: DefaultActionsArray, // defaults to empty actions array if not set during decode
anomaly_threshold, // defaults to undefined if not set during decode
+ author: DefaultStringArray, // defaults to empty array of strings if not set during decode
+ building_block_type, // defaults to undefined if not set during decode
enabled: DefaultBooleanTrue, // defaults to true if not set during decode
false_positives: DefaultStringArray, // defaults to empty string array if not set during decode
filters, // defaults to undefined if not set during decode
@@ -80,6 +91,7 @@ export const createRulesSchema = t.intersection([
interval: DefaultIntervalString, // defaults to "5m" if not set during decode
query, // defaults to undefined if not set during decode
language, // defaults to undefined if not set during decode
+ license, // defaults to "undefined" if not set during decode
// TODO: output_index: This should be removed eventually
output_index, // defaults to "undefined" if not set during decode
saved_id, // defaults to "undefined" if not set during decode
@@ -88,10 +100,14 @@ export const createRulesSchema = t.intersection([
meta, // defaults to "undefined" if not set during decode
machine_learning_job_id, // defaults to "undefined" if not set during decode
max_signals: DefaultMaxSignalsNumber, // defaults to DEFAULT_MAX_SIGNALS (100) if not set during decode
+ risk_score_mapping: DefaultRiskScoreMappingArray, // defaults to empty risk score mapping array if not set during decode
+ rule_name_override, // defaults to "undefined" if not set during decode
+ severity_mapping: DefaultSeverityMappingArray, // defaults to empty actions array if not set during decode
tags: DefaultStringArray, // defaults to empty string array if not set during decode
to: DefaultToString, // defaults to "now" if not set during decode
threat: DefaultThreatArray, // defaults to empty array if not set during decode
throttle: DefaultThrottleNull, // defaults to "null" if not set during decode
+ timestamp_override, // defaults to "undefined" if not set during decode
references: DefaultStringArray, // defaults to empty array of strings if not set during decode
note, // defaults to "undefined" if not set during decode
version: DefaultVersionNumber, // defaults to 1 if not set during decode
@@ -105,6 +121,7 @@ export type CreateRulesSchema = t.TypeOf;
// This type is used after a decode since some things are defaults after a decode.
export type CreateRulesSchemaDecoded = Omit<
CreateRulesSchema,
+ | 'author'
| 'references'
| 'actions'
| 'enabled'
@@ -112,6 +129,8 @@ export type CreateRulesSchemaDecoded = Omit<
| 'from'
| 'interval'
| 'max_signals'
+ | 'risk_score_mapping'
+ | 'severity_mapping'
| 'tags'
| 'to'
| 'threat'
@@ -120,6 +139,7 @@ export type CreateRulesSchemaDecoded = Omit<
| 'exceptions_list'
| 'rule_id'
> & {
+ author: Author;
references: References;
actions: Actions;
enabled: Enabled;
@@ -127,6 +147,8 @@ export type CreateRulesSchemaDecoded = Omit<
from: From;
interval: Interval;
max_signals: MaxSignals;
+ risk_score_mapping: RiskScoreMapping;
+ severity_mapping: SeverityMapping;
tags: Tags;
to: To;
threat: Threat;
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts
index aaeb90ffc5bcf..e3b4196c90c6c 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts
@@ -31,12 +31,15 @@ export const getImportRulesWithIdSchemaMock = (ruleId = 'rule-1'): ImportRulesSc
});
export const getImportRulesSchemaDecodedMock = (): ImportRulesSchemaDecoded => ({
+ author: [],
description: 'some description',
name: 'Query with a rule id',
query: 'user.name: root or user.name: admin',
severity: 'high',
+ severity_mapping: [],
type: 'query',
risk_score: 55,
+ risk_score_mapping: [],
language: 'kuery',
references: [],
actions: [],
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.test.ts
index 12a13ab1a5ed1..bbf0a8debd651 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.test.ts
@@ -253,6 +253,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -324,6 +327,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -373,6 +379,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -420,6 +429,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -465,6 +477,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -545,6 +560,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -1543,6 +1561,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1593,6 +1614,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1651,6 +1675,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1727,6 +1754,9 @@ describe('import rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: ImportRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts
index 7d79861aacf38..f61a1546e3e8a 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts
@@ -44,6 +44,13 @@ import {
updated_at,
created_by,
updated_by,
+ building_block_type,
+ license,
+ rule_name_override,
+ timestamp_override,
+ Author,
+ RiskScoreMapping,
+ SeverityMapping,
} from '../common/schemas';
/* eslint-enable @typescript-eslint/camelcase */
@@ -62,6 +69,8 @@ import {
DefaultStringBooleanFalse,
DefaultListArray,
ListArray,
+ DefaultRiskScoreMappingArray,
+ DefaultSeverityMappingArray,
} from '../types';
/**
@@ -90,6 +99,8 @@ export const importRulesSchema = t.intersection([
id, // defaults to undefined if not set during decode
actions: DefaultActionsArray, // defaults to empty actions array if not set during decode
anomaly_threshold, // defaults to undefined if not set during decode
+ author: DefaultStringArray, // defaults to empty array of strings if not set during decode
+ building_block_type, // defaults to undefined if not set during decode
enabled: DefaultBooleanTrue, // defaults to true if not set during decode
false_positives: DefaultStringArray, // defaults to empty string array if not set during decode
filters, // defaults to undefined if not set during decode
@@ -99,6 +110,7 @@ export const importRulesSchema = t.intersection([
interval: DefaultIntervalString, // defaults to "5m" if not set during decode
query, // defaults to undefined if not set during decode
language, // defaults to undefined if not set during decode
+ license, // defaults to "undefined" if not set during decode
// TODO: output_index: This should be removed eventually
output_index, // defaults to "undefined" if not set during decode
saved_id, // defaults to "undefined" if not set during decode
@@ -107,10 +119,14 @@ export const importRulesSchema = t.intersection([
meta, // defaults to "undefined" if not set during decode
machine_learning_job_id, // defaults to "undefined" if not set during decode
max_signals: DefaultMaxSignalsNumber, // defaults to DEFAULT_MAX_SIGNALS (100) if not set during decode
+ risk_score_mapping: DefaultRiskScoreMappingArray, // defaults to empty risk score mapping array if not set during decode
+ rule_name_override, // defaults to "undefined" if not set during decode
+ severity_mapping: DefaultSeverityMappingArray, // defaults to empty actions array if not set during decode
tags: DefaultStringArray, // defaults to empty string array if not set during decode
to: DefaultToString, // defaults to "now" if not set during decode
threat: DefaultThreatArray, // defaults to empty array if not set during decode
throttle: DefaultThrottleNull, // defaults to "null" if not set during decode
+ timestamp_override, // defaults to "undefined" if not set during decode
references: DefaultStringArray, // defaults to empty array of strings if not set during decode
note, // defaults to "undefined" if not set during decode
version: DefaultVersionNumber, // defaults to 1 if not set during decode
@@ -128,6 +144,7 @@ export type ImportRulesSchema = t.TypeOf;
// This type is used after a decode since some things are defaults after a decode.
export type ImportRulesSchemaDecoded = Omit<
ImportRulesSchema,
+ | 'author'
| 'references'
| 'actions'
| 'enabled'
@@ -135,6 +152,8 @@ export type ImportRulesSchemaDecoded = Omit<
| 'from'
| 'interval'
| 'max_signals'
+ | 'risk_score_mapping'
+ | 'severity_mapping'
| 'tags'
| 'to'
| 'threat'
@@ -144,6 +163,7 @@ export type ImportRulesSchemaDecoded = Omit<
| 'rule_id'
| 'immutable'
> & {
+ author: Author;
references: References;
actions: Actions;
enabled: Enabled;
@@ -151,6 +171,8 @@ export type ImportRulesSchemaDecoded = Omit<
from: From;
interval: Interval;
max_signals: MaxSignals;
+ risk_score_mapping: RiskScoreMapping;
+ severity_mapping: SeverityMapping;
tags: Tags;
to: To;
threat: Threat;
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts
index 29d5467071a3d..070f3ccfd03b0 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts
@@ -39,6 +39,13 @@ import {
language,
query,
id,
+ building_block_type,
+ author,
+ license,
+ rule_name_override,
+ timestamp_override,
+ risk_score_mapping,
+ severity_mapping,
} from '../common/schemas';
import { listArrayOrUndefined } from '../types/lists';
/* eslint-enable @typescript-eslint/camelcase */
@@ -48,6 +55,8 @@ import { listArrayOrUndefined } from '../types/lists';
*/
export const patchRulesSchema = t.exact(
t.partial({
+ author,
+ building_block_type,
description,
risk_score,
name,
@@ -65,6 +74,7 @@ export const patchRulesSchema = t.exact(
interval,
query,
language,
+ license,
// TODO: output_index: This should be removed eventually
output_index,
saved_id,
@@ -73,10 +83,14 @@ export const patchRulesSchema = t.exact(
meta,
machine_learning_job_id,
max_signals,
+ risk_score_mapping,
+ rule_name_override,
+ severity_mapping,
tags,
to,
threat,
throttle,
+ timestamp_override,
references,
note,
version,
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.mock.ts
index b8a99115ba7d5..b3fbf96188352 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.mock.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.mock.ts
@@ -19,12 +19,15 @@ export const getUpdateRulesSchemaMock = (): UpdateRulesSchema => ({
});
export const getUpdateRulesSchemaDecodedMock = (): UpdateRulesSchemaDecoded => ({
+ author: [],
description: 'some description',
name: 'Query with a rule id',
query: 'user.name: root or user.name: admin',
severity: 'high',
+ severity_mapping: [],
type: 'query',
risk_score: 55,
+ risk_score_mapping: [],
language: 'kuery',
references: [],
actions: [],
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.test.ts
index 02f8e7bbeb59b..c15803eee874e 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.test.ts
@@ -248,6 +248,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -317,6 +320,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -364,6 +370,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -409,6 +418,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -452,6 +464,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -530,6 +545,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -1353,6 +1371,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1401,6 +1422,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1457,6 +1481,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -1531,6 +1558,9 @@ describe('update rules schema', () => {
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
const expected: UpdateRulesSchemaDecoded = {
+ author: [],
+ severity_mapping: [],
+ risk_score_mapping: [],
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.ts
index 73078e617efc6..98082c2de838a 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.ts
@@ -40,6 +40,13 @@ import {
language,
query,
id,
+ building_block_type,
+ license,
+ rule_name_override,
+ timestamp_override,
+ Author,
+ RiskScoreMapping,
+ SeverityMapping,
} from '../common/schemas';
/* eslint-enable @typescript-eslint/camelcase */
@@ -55,6 +62,8 @@ import {
DefaultThrottleNull,
DefaultListArray,
ListArray,
+ DefaultRiskScoreMappingArray,
+ DefaultSeverityMappingArray,
} from '../types';
/**
@@ -79,6 +88,8 @@ export const updateRulesSchema = t.intersection([
id, // defaults to "undefined" if not set during decode
actions: DefaultActionsArray, // defaults to empty actions array if not set during decode
anomaly_threshold, // defaults to undefined if not set during decode
+ author: DefaultStringArray, // defaults to empty array of strings if not set during decode
+ building_block_type, // defaults to undefined if not set during decode
enabled: DefaultBooleanTrue, // defaults to true if not set during decode
false_positives: DefaultStringArray, // defaults to empty string array if not set during decode
filters, // defaults to undefined if not set during decode
@@ -88,6 +99,7 @@ export const updateRulesSchema = t.intersection([
interval: DefaultIntervalString, // defaults to "5m" if not set during decode
query, // defaults to undefined if not set during decode
language, // defaults to undefined if not set during decode
+ license, // defaults to "undefined" if not set during decode
// TODO: output_index: This should be removed eventually
output_index, // defaults to "undefined" if not set during decode
saved_id, // defaults to "undefined" if not set during decode
@@ -96,10 +108,14 @@ export const updateRulesSchema = t.intersection([
meta, // defaults to "undefined" if not set during decode
machine_learning_job_id, // defaults to "undefined" if not set during decode
max_signals: DefaultMaxSignalsNumber, // defaults to DEFAULT_MAX_SIGNALS (100) if not set during decode
+ risk_score_mapping: DefaultRiskScoreMappingArray, // defaults to empty risk score mapping array if not set during decode
+ rule_name_override, // defaults to "undefined" if not set during decode
+ severity_mapping: DefaultSeverityMappingArray, // defaults to empty actions array if not set during decode
tags: DefaultStringArray, // defaults to empty string array if not set during decode
to: DefaultToString, // defaults to "now" if not set during decode
threat: DefaultThreatArray, // defaults to empty array if not set during decode
throttle: DefaultThrottleNull, // defaults to "null" if not set during decode
+ timestamp_override, // defaults to "undefined" if not set during decode
references: DefaultStringArray, // defaults to empty array of strings if not set during decode
note, // defaults to "undefined" if not set during decode
version, // defaults to "undefined" if not set during decode
@@ -113,6 +129,7 @@ export type UpdateRulesSchema = t.TypeOf;
// This type is used after a decode since some things are defaults after a decode.
export type UpdateRulesSchemaDecoded = Omit<
UpdateRulesSchema,
+ | 'author'
| 'references'
| 'actions'
| 'enabled'
@@ -120,6 +137,8 @@ export type UpdateRulesSchemaDecoded = Omit<
| 'from'
| 'interval'
| 'max_signals'
+ | 'risk_score_mapping'
+ | 'severity_mapping'
| 'tags'
| 'to'
| 'threat'
@@ -127,6 +146,7 @@ export type UpdateRulesSchemaDecoded = Omit<
| 'exceptions_list'
| 'rule_id'
> & {
+ author: Author;
references: References;
actions: Actions;
enabled: Enabled;
@@ -134,6 +154,8 @@ export type UpdateRulesSchemaDecoded = Omit<
from: From;
interval: Interval;
max_signals: MaxSignals;
+ risk_score_mapping: RiskScoreMapping;
+ severity_mapping: SeverityMapping;
tags: Tags;
to: To;
threat: Threat;
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts
index e63a7ad981e12..ed9fb8930ea1b 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts
@@ -36,6 +36,7 @@ export const getPartialRulesSchemaMock = (): Partial => ({
});
export const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE): RulesSchema => ({
+ author: [],
id: '7a7065d7-6e8b-4aae-8d20-c93613dec9f9',
created_at: new Date(anchorDate).toISOString(),
updated_at: new Date(anchorDate).toISOString(),
@@ -49,6 +50,7 @@ export const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE): RulesSchem
query: 'user.name: root or user.name: admin',
references: ['test 1', 'test 2'],
severity: 'high',
+ severity_mapping: [],
updated_by: 'elastic_kibana',
tags: [],
to: 'now',
@@ -62,6 +64,7 @@ export const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE): RulesSchem
output_index: '.siem-signals-hassanabad-frank-default',
max_signals: 100,
risk_score: 55,
+ risk_score_mapping: [],
language: 'kuery',
rule_id: 'query-rule-id',
interval: '5m',
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts
index 9803a80f57857..c0fec2b2eefc2 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts
@@ -55,8 +55,17 @@ import {
filters,
meta,
note,
+ building_block_type,
+ license,
+ rule_name_override,
+ timestamp_override,
} from '../common/schemas';
import { DefaultListArray } from '../types/lists_default_array';
+import {
+ DefaultStringArray,
+ DefaultRiskScoreMappingArray,
+ DefaultSeverityMappingArray,
+} from '../types';
/**
* This is the required fields for the rules schema response. Put all required properties on
@@ -64,6 +73,7 @@ import { DefaultListArray } from '../types/lists_default_array';
* output schema.
*/
export const requiredRulesSchema = t.type({
+ author: DefaultStringArray,
description,
enabled,
false_positives,
@@ -75,9 +85,11 @@ export const requiredRulesSchema = t.type({
output_index,
max_signals,
risk_score,
+ risk_score_mapping: DefaultRiskScoreMappingArray,
name,
references,
severity,
+ severity_mapping: DefaultSeverityMappingArray,
updated_by,
tags,
to,
@@ -120,9 +132,13 @@ export const dependentRulesSchema = t.partial({
*/
export const partialRulesSchema = t.partial({
actions,
+ building_block_type,
+ license,
throttle,
+ rule_name_override,
status: job_status,
status_date,
+ timestamp_override,
last_success_at,
last_success_message,
last_failure_at,
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_risk_score_mapping_array.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_risk_score_mapping_array.ts
new file mode 100644
index 0000000000000..ba74045b4e32c
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_risk_score_mapping_array.ts
@@ -0,0 +1,24 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import * as t from 'io-ts';
+import { Either } from 'fp-ts/lib/Either';
+// eslint-disable-next-line @typescript-eslint/camelcase
+import { risk_score_mapping, RiskScoreMapping } from '../common/schemas';
+
+/**
+ * Types the DefaultStringArray as:
+ * - If null or undefined, then a default risk_score_mapping array will be set
+ */
+export const DefaultRiskScoreMappingArray = new t.Type(
+ 'DefaultRiskScoreMappingArray',
+ risk_score_mapping.is,
+ (input, context): Either =>
+ input == null ? t.success([]) : risk_score_mapping.validate(input, context),
+ t.identity
+);
+
+export type DefaultRiskScoreMappingArrayC = typeof DefaultRiskScoreMappingArray;
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_severity_mapping_array.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_severity_mapping_array.ts
new file mode 100644
index 0000000000000..8e68b73148af1
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_severity_mapping_array.ts
@@ -0,0 +1,24 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import * as t from 'io-ts';
+import { Either } from 'fp-ts/lib/Either';
+// eslint-disable-next-line @typescript-eslint/camelcase
+import { severity_mapping, SeverityMapping } from '../common/schemas';
+
+/**
+ * Types the DefaultStringArray as:
+ * - If null or undefined, then a default severity_mapping array will be set
+ */
+export const DefaultSeverityMappingArray = new t.Type(
+ 'DefaultSeverityMappingArray',
+ severity_mapping.is,
+ (input, context): Either =>
+ input == null ? t.success([]) : severity_mapping.validate(input, context),
+ t.identity
+);
+
+export type DefaultSeverityMappingArrayC = typeof DefaultSeverityMappingArray;
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/index.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/index.ts
index 368dd4922eec4..aab9a550d25e7 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/index.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/index.ts
@@ -15,6 +15,8 @@ export * from './default_language_string';
export * from './default_max_signals_number';
export * from './default_page';
export * from './default_per_page';
+export * from './default_risk_score_mapping_array';
+export * from './default_severity_mapping_array';
export * from './default_string_array';
export * from './default_string_boolean_false';
export * from './default_threat_array';
diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts
index 984cd7d2506a9..e311e358e6146 100644
--- a/x-pack/plugins/security_solution/common/endpoint/constants.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts
@@ -7,6 +7,5 @@
export const eventsIndexPattern = 'logs-endpoint.events.*';
export const alertsIndexPattern = 'logs-endpoint.alerts-*';
export const metadataIndexPattern = 'metrics-endpoint.metadata-*';
-export const metadataMirrorIndexPattern = 'metrics-endpoint.metadata_mirror-*';
export const policyIndexPattern = 'metrics-endpoint.policy-*';
export const telemetryIndexPattern = 'metrics-endpoint.telemetry-*';
diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts
index 4516007580edc..f64462f71a87b 100644
--- a/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts
@@ -101,6 +101,30 @@ describe('data generator', () => {
expect(processEvent.process.name).not.toBeNull();
});
+ describe('creates events with an empty ancestry array', () => {
+ let tree: Tree;
+ beforeEach(() => {
+ tree = generator.generateTree({
+ alwaysGenMaxChildrenPerNode: true,
+ ancestors: 3,
+ children: 3,
+ generations: 3,
+ percentTerminated: 100,
+ percentWithRelated: 100,
+ relatedEvents: 0,
+ relatedAlerts: 0,
+ ancestryArraySize: 0,
+ });
+ tree.ancestry.delete(tree.origin.id);
+ });
+
+ it('creates all events with an empty ancestry array', () => {
+ for (const event of tree.allEvents) {
+ expect(event.process.Ext.ancestry.length).toEqual(0);
+ }
+ });
+ });
+
describe('creates an origin alert when no related alerts are requested', () => {
let tree: Tree;
beforeEach(() => {
@@ -113,6 +137,7 @@ describe('data generator', () => {
percentWithRelated: 100,
relatedEvents: 0,
relatedAlerts: 0,
+ ancestryArraySize: ANCESTRY_LIMIT,
});
tree.ancestry.delete(tree.origin.id);
});
@@ -150,6 +175,7 @@ describe('data generator', () => {
{ category: RelatedEventCategory.Network, count: 1 },
],
relatedAlerts,
+ ancestryArraySize: ANCESTRY_LIMIT,
});
});
@@ -162,29 +188,46 @@ describe('data generator', () => {
};
const verifyAncestry = (event: Event, genTree: Tree) => {
- if (event.process.Ext.ancestry.length > 0) {
- expect(event.process.parent?.entity_id).toBe(event.process.Ext.ancestry[0]);
+ if (event.process.Ext.ancestry!.length > 0) {
+ expect(event.process.parent?.entity_id).toBe(event.process.Ext.ancestry![0]);
}
- for (let i = 0; i < event.process.Ext.ancestry.length; i++) {
- const ancestor = event.process.Ext.ancestry[i];
+ for (let i = 0; i < event.process.Ext.ancestry!.length; i++) {
+ const ancestor = event.process.Ext.ancestry![i];
const parent = genTree.children.get(ancestor) || genTree.ancestry.get(ancestor);
expect(ancestor).toBe(parent?.lifecycle[0].process.entity_id);
// the next ancestor should be the grandparent
- if (i + 1 < event.process.Ext.ancestry.length) {
- const grandparent = event.process.Ext.ancestry[i + 1];
+ if (i + 1 < event.process.Ext.ancestry!.length) {
+ const grandparent = event.process.Ext.ancestry![i + 1];
expect(grandparent).toBe(parent?.lifecycle[0].process.parent?.entity_id);
}
}
};
it('has ancestry array defined', () => {
- expect(tree.origin.lifecycle[0].process.Ext.ancestry.length).toBe(ANCESTRY_LIMIT);
+ expect(tree.origin.lifecycle[0].process.Ext.ancestry!.length).toBe(ANCESTRY_LIMIT);
for (const event of tree.allEvents) {
verifyAncestry(event, tree);
}
});
+ it('creates the right number childrenLevels', () => {
+ let totalChildren = 0;
+ for (const level of tree.childrenLevels) {
+ totalChildren += level.size;
+ }
+ expect(totalChildren).toEqual(tree.children.size);
+ expect(tree.childrenLevels.length).toEqual(generations);
+ });
+
+ it('has the right nodes in both the childrenLevels and children map', () => {
+ for (const level of tree.childrenLevels) {
+ for (const node of level.values()) {
+ expect(tree.children.get(node.id)).toEqual(node);
+ }
+ }
+ });
+
it('has the right related events for each node', () => {
const checkRelatedEvents = (node: TreeNode) => {
expect(node.relatedEvents.length).toEqual(4);
@@ -290,7 +333,11 @@ describe('data generator', () => {
let events: Event[];
beforeEach(() => {
- events = generator.createAlertEventAncestry(3, 0, 0, 0, 0);
+ events = generator.createAlertEventAncestry({
+ ancestors: 3,
+ percentTerminated: 0,
+ percentWithRelated: 0,
+ });
});
it('with n-1 process events', () => {
@@ -375,7 +422,7 @@ describe('data generator', () => {
const timestamp = new Date().getTime();
const root = generator.generateEvent({ timestamp });
const generations = 2;
- const events = [root, ...generator.descendantsTreeGenerator(root, generations)];
+ const events = [root, ...generator.descendantsTreeGenerator(root, { generations })];
const rootNode = buildResolverTree(events);
const visitedEvents = countResolverEvents(rootNode, generations);
expect(visitedEvents).toEqual(events.length);
diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts
index 563e2e4ccc9f2..6720f3523d5c7 100644
--- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts
@@ -17,6 +17,7 @@ import {
EndpointStatus,
} from './types';
import { factory as policyFactory } from './models/policy_config';
+import { parentEntityId } from './models/event';
export type Event = AlertEvent | EndpointEvent;
/**
@@ -38,6 +39,7 @@ interface EventOptions {
eventCategory?: string | string[];
processName?: string;
ancestry?: string[];
+ ancestryArrayLimit?: number;
pid?: number;
parentPid?: number;
extensions?: object;
@@ -266,6 +268,11 @@ export interface Tree {
* Map of entity_id to node
*/
children: Map