Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENDPOINT][INGEST]Task/endpoint ingest update #67234

Merged
merged 25 commits into from
Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e300f90
endpoint advanced config. changed message
parkiino May 18, 2020
11c3837
add edit mode
parkiino May 20, 2020
0cf3ae9
no more endpoint
parkiino May 21, 2020
82b20af
wow it werks but after going down the wrong path
parkiino May 21, 2020
2b0fa3e
fix type script error
parkiino May 21, 2020
4ccc118
rename linky
parkiino May 26, 2020
3398ed6
Merge remote-tracking branch 'upstream/master' into task/endpoint-inj…
parkiino May 26, 2020
f232a7c
use navigatetoapp, no refresh
parkiino May 26, 2020
b1777d9
Merge branch 'master' into task/endpoint-injest-update
elasticmachine May 26, 2020
8444aec
fixed wording
parkiino May 27, 2020
057f440
Merge branch 'task/endpoint-injest-update' of github.com:parkiino/kib…
parkiino May 27, 2020
f9852af
POC for custom configure data source panel from outside plugin
jen-huang May 28, 2020
ad71c88
added security text
parkiino May 29, 2020
3efce1c
Merge remote-tracking branch 'upstream/master' into task/endpoint-inj…
parkiino May 29, 2020
8586e3b
it werks
parkiino May 29, 2020
412f5e0
Merge remote-tracking branch 'upstream/master' into task/endpoint-inj…
parkiino Jun 1, 2020
7583c48
removed redundant import, type error
parkiino Jun 1, 2020
04dee90
i18n fix
parkiino Jun 1, 2020
2208beb
remove unused file
parkiino Jun 1, 2020
b43801e
grab policyId from datasource
parkiino Jun 2, 2020
9ee8750
Merge remote-tracking branch 'upstream/master' into task/endpoint-inj…
parkiino Jun 2, 2020
4f4e14c
update doc comments
parkiino Jun 2, 2020
635d035
pauls comments
parkiino Jun 2, 2020
ac2441d
registerDatasource from plugin lifecycle
parkiino Jun 3, 2020
165c0fb
Merge remote-tracking branch 'upstream/master' into task/endpoint-inj…
parkiino Jun 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

export { useCapabilities } from './use_capabilities';
export { useCore, CoreContext } from './use_core';
export { useCore } from './use_core';
export { useConfig, ConfigContext } from './use_config';
export { useSetupDeps, useStartDeps, DepsContext } from './use_deps';
export { useBreadcrumbs } from './use_breadcrumbs';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useContext } from 'react';
import { CoreStart } from 'src/core/public';
import { CoreStart } from 'kibana/public';
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';

export const CoreContext = React.createContext<CoreStart | null>(null);

export function useCore() {
const core = useContext(CoreContext);
if (core === null) {
throw new Error('CoreContext not initialized');
export function useCore(): CoreStart {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated useCore() to use the new useKibana hook

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty cool, I didn't know that kibana_react had these kind of components/hooks now

const { services } = useKibana();
if (services === null) {
throw new Error('KibanaContextProvider not initialized');
}
return core;
return services;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will return the same thing that core returned. could be renamed to say core if that clears up any confusion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind keeping it as services here for now as it's largely an abstraction anyway. On our team's side we can consider renaming useCore as tech debt

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import { PAGE_ROUTING_PATHS } from './constants';
import { DefaultLayout, WithoutHeaderLayout } from './layouts';
import { Loading, Error } from './components';
import { IngestManagerOverview, EPMApp, AgentConfigApp, FleetApp, DataStreamApp } from './sections';
import { CoreContext, DepsContext, ConfigContext, setHttpClient, useConfig } from './hooks';
import { DepsContext, ConfigContext, setHttpClient, useConfig } from './hooks';
import { PackageInstallProvider } from './sections/epm/hooks';
import { useCore, sendSetup, sendGetPermissionsCheck } from './hooks';
import { FleetStatusProvider } from './hooks/use_fleet_status';
import './index.scss';
import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public';

export interface ProtectedRouteProps extends RouteProps {
isAllowed?: boolean;
Expand Down Expand Up @@ -229,15 +230,15 @@ const IngestManagerApp = ({
const isDarkMode = useObservable<boolean>(coreStart.uiSettings.get$('theme:darkMode'));
return (
<coreStart.i18n.Context>
<CoreContext.Provider value={coreStart}>
<KibanaContextProvider services={{ ...coreStart }}>
Copy link
Contributor Author

@parkiino parkiino May 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uses the newer KibanaContextProvider in place of CoreContext provider, which also exposes coreStart and allows use to use the <LinkToApp> component in the Siem/Endpoint app

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ingest Team: FYI: I actually learned about this functionality from Kibana from one of you - maybe @jfsiii 😄

<DepsContext.Provider value={{ setup: setupDeps, start: startDeps }}>
<ConfigContext.Provider value={config}>
<EuiThemeProvider darkMode={isDarkMode}>
<IngestManagerRoutes basepath={basepath} />
</EuiThemeProvider>
</ConfigContext.Provider>
</DepsContext.Provider>
</CoreContext.Provider>
</KibanaContextProvider>
</coreStart.i18n.Context>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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 from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiEmptyPrompt, EuiText } from '@elastic/eui';
import { NewDatasource } from '../../../../types';
import { CreateDatasourceFrom } from '../types';

export interface CustomConfigureDatasourceProps {
packageName: string;
from: CreateDatasourceFrom;
datasource: NewDatasource | (NewDatasource & { id: string });
}

/**
* Custom content type that external plugins can provide to Ingest's
* Datasource configuration.
*/
export type CustomConfigureDatasourceContent = React.FC<CustomConfigureDatasourceProps>;

type AllowedDatasourceKey = 'endpoint';
const ConfigureDatasourceMapping: {
[key: string]: CustomConfigureDatasourceContent;
} = {};

/**
* Plugins can call this function from the start lifecycle to
* register a custom component in the Ingest Datasource configuration.
*/
export function registerDatasource(
key: AllowedDatasourceKey,
value: CustomConfigureDatasourceContent
) {
ConfigureDatasourceMapping[key] = value;
}

const EmptyConfigureDatasource: CustomConfigureDatasourceContent = () => (
<EuiEmptyPrompt
iconType="checkInCircleFilled"
iconColor="secondary"
body={
<EuiText>
<p>
<FormattedMessage
id="xpack.ingestManager.createDatasource.stepConfigure.noConfigOptionsMessage"
defaultMessage="Nothing to configure"
/>
</p>
</EuiText>
}
/>
);

export const CustomConfigureDatasource = (props: CustomConfigureDatasourceProps) => {
const ConfigureDatasourceContent =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jen-huang The package definition has a flag called solution whose comment indicates that it should be the trigger for displaying a custom configuration UI - see: https://github.com/elastic/package-storage/blob/master/packages/endpoint/0.1.0/manifest.yml#L23

I don't see that property defined in Datasources type, so I assume that is future functionality?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we need to implement that on the ingest management side. Could you make an issue for it? I wasn't aware that flag was already implemented on registry side :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jen-huang . Created #67939 to track

ConfigureDatasourceMapping[props.packageName] || EmptyConfigureDatasource;
return <ConfigureDatasourceContent {...props} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
export { CreateDatasourcePageLayout } from './layout';
export { DatasourceInputPanel } from './datasource_input_panel';
export { DatasourceInputVarField } from './datasource_input_var_field';
export { CustomConfigureDatasource } from './custom_configure_datasource';
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,29 @@
*/
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiPanel,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiEmptyPrompt,
EuiText,
EuiCallOut,
} from '@elastic/eui';
import { EuiPanel, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiCallOut } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { PackageInfo, NewDatasource, DatasourceInput } from '../../../types';
import { Loading } from '../../../components';
import { DatasourceValidationResults, validationHasErrors } from './services';
import { DatasourceInputPanel } from './components';
import { DatasourceInputPanel, CustomConfigureDatasource } from './components';
import { CreateDatasourceFrom } from './types';

export const StepConfigureDatasource: React.FunctionComponent<{
from?: CreateDatasourceFrom;
packageInfo: PackageInfo;
datasource: NewDatasource;
datasource: NewDatasource | (NewDatasource & { id: string });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe? 😬

If also export the CustomConfigureDatasourceProps, then you can:

Suggested change
datasource: NewDatasource | (NewDatasource & { id: string });
datasource: CustomConfigureDatasourceProps['datasource'];

updateDatasource: (fields: Partial<NewDatasource>) => void;
validationResults: DatasourceValidationResults;
submitAttempted: boolean;
}> = ({ packageInfo, datasource, updateDatasource, validationResults, submitAttempted }) => {
}> = ({
from = 'config',
packageInfo,
datasource,
updateDatasource,
validationResults,
submitAttempted,
}) => {
const hasErrors = validationResults ? validationHasErrors(validationResults) : false;

// Configure inputs (and their streams)
Expand Down Expand Up @@ -68,19 +69,10 @@ export const StepConfigureDatasource: React.FunctionComponent<{
</EuiFlexGroup>
) : (
<EuiPanel>
<EuiEmptyPrompt
iconType="checkInCircleFilled"
iconColor="secondary"
body={
<EuiText>
<p>
<FormattedMessage
id="xpack.ingestManager.createDatasource.stepConfigure.noConfigOptionsMessage"
defaultMessage="Nothing to configure"
/>
</p>
</EuiText>
}
<CustomConfigureDatasource
packageName={packageInfo.name}
datasource={datasource}
from={from}
/>
</EuiPanel>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
const [loadingError, setLoadingError] = useState<Error>();
const [agentConfig, setAgentConfig] = useState<AgentConfig>();
const [packageInfo, setPackageInfo] = useState<PackageInfo>();
const [datasource, setDatasource] = useState<NewDatasource>({
const [datasource, setDatasource] = useState<NewDatasource & { id: string }>({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here for the type, if you like 😃

id: '',
name: '',
description: '',
config_id: '',
Expand All @@ -93,7 +94,6 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
}
if (datasourceData?.item) {
const {
id,
revision,
inputs,
created_by,
Expand Down Expand Up @@ -299,6 +299,7 @@ export const EditDatasourcePage: React.FunctionComponent = () => {
),
children: (
<StepConfigureDatasource
from={'edit'}
packageInfo={packageInfo}
datasource={datasource}
updateDatasource={updateDatasource}
Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/ingest_manager/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ export { IngestManagerStart } from './plugin';
export const plugin = (initializerContext: PluginInitializerContext) => {
return new IngestManagerPlugin(initializerContext);
};

export {
CustomConfigureDatasourceContent,
CustomConfigureDatasourceProps,
registerDatasource,
} from './applications/ingest_manager/sections/agent_config/create_datasource_page/components/custom_configure_datasource';

export { NewDatasource } from './applications/ingest_manager/types';
10 changes: 8 additions & 2 deletions x-pack/plugins/ingest_manager/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { PLUGIN_ID } from '../common/constants';

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';

export { IngestManagerConfigType } from '../common/types';

Expand All @@ -26,6 +27,7 @@ export type IngestManagerSetup = void;
* Describes public IngestManager plugin contract returned at the `start` stage.
*/
export interface IngestManagerStart {
registerDatasource: typeof registerDatasource;
success: boolean;
error?: {
message: string;
Expand Down Expand Up @@ -80,12 +82,16 @@ export class IngestManagerPlugin
const permissionsResponse = await core.http.get(appRoutesService.getCheckPermissionsPath());
if (permissionsResponse.success) {
const { isInitialized: success } = await core.http.post(setupRouteService.getSetupPath());
return { success };
return { success, registerDatasource };
} else {
throw new Error(permissionsResponse.error);
}
} catch (error) {
return { success: false, error: { message: error.body?.message || 'Unknown error' } };
return {
success: false,
error: { message: error.body?.message || 'Unknown error' },
registerDatasource,
};
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { IngestManagerStart } from '../../../../../ingest_manager/public';
import { IngestManagerStart, registerDatasource } from '../../../../../ingest_manager/public';
import {
dataPluginMock,
Start as DataPublicStartMock,
Expand Down Expand Up @@ -56,6 +56,6 @@ export const depsStartMock: () => DepsStartMock = () => {

return {
data: dataMock,
ingestManager: { success: true },
ingestManager: { success: true, registerDatasource },
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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, { memo } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiEmptyPrompt, EuiText } from '@elastic/eui';
import { useKibana } from '../../../../../../../../../src/plugins/kibana_react/public';
import { LinkToApp } from '../../../../../common/components/endpoint/link_to_app';
import {
CustomConfigureDatasourceContent,
CustomConfigureDatasourceProps,
NewDatasource,
} from '../../../../../../../ingest_manager/public';
import { getManagementUrl } from '../../../..';

type DatasourceWithId = NewDatasource & { id: string };

/**
* Exports Endpoint-specific datasource configuration instructions
* for use in the Ingest app create / edit datasource config
*/
export const ConfigureEndpointDatasource = memo<CustomConfigureDatasourceContent>(
({
from,
datasource,
}: {
from: string;
datasource: CustomConfigureDatasourceProps['datasource'];
}) => {
const { services } = useKibana();
let policyUrl = '';
if (from === 'edit') {
policyUrl = getManagementUrl({
name: 'policyDetails',
policyId: (datasource as DatasourceWithId).id,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this cast safe? or should you be checking if datasource has an id? (just asking, not familiar w/ the code.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oatkiller The cast is safe and necessary since tsserver doesn't realize that datasource does have an id if it's coming from the edit flow. the edit flow always sends in the id of the datasource

});
}

return (
<EuiEmptyPrompt
body={
<EuiText>
<p>
{from === 'edit' ? (
<LinkToApp
appId="siem"
appPath={policyUrl}
href={`${services.application.getUrlForApp('siem')}${policyUrl}`}
>
<FormattedMessage
id="xpack.siem.endpoint.ingestManager.editDatasource.stepConfigure"
defaultMessage="View and configure Security Policy"
/>
</LinkToApp>
) : (
<FormattedMessage
id="xpack.siem.endpoint.ingestManager.createDatasource.stepConfigure"
defaultMessage="The recommended Security Policy has been associated with this data source. The Security Policy can be edited in the Security application once your data source has been saved."
/>
)}
</p>
</EuiText>
}
/>
);
}
);

ConfigureEndpointDatasource.displayName = 'ConfigureEndpointDatasource';
2 changes: 2 additions & 0 deletions x-pack/plugins/siem/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { KibanaServices } from './common/lib/kibana/services';
import { serviceNowActionType, jiraActionType } from './common/lib/connectors';
import { PluginSetup, PluginStart, SetupPlugins, StartPlugins, StartServices } from './types';
import { APP_ID, APP_NAME, APP_ICON, APP_PATH } from '../common/constants';
import { ConfigureEndpointDatasource } from './management/pages/policy/view/ingest_manager_integration/configure_datasource';

export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, StartPlugins> {
private kibanaVersion: string;
Expand Down Expand Up @@ -131,6 +132,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S

public start(core: CoreStart, plugins: StartPlugins) {
KibanaServices.init({ ...core, ...plugins, kibanaVersion: this.kibanaVersion });
plugins.ingestManager.registerDatasource('endpoint', ConfigureEndpointDatasource);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is cool


return {};
}
Expand Down