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 Manager] minor code cleanup #69844

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ import { CreateDatasourceFrom } from '../types';
export const CreateDatasourcePageLayout: React.FunctionComponent<{
from: CreateDatasourceFrom;
cancelUrl: string;
cancelOnClick?: React.ReactEventHandler;
onCancel?: React.ReactEventHandler;
agentConfig?: AgentConfig;
packageInfo?: PackageInfo;
'data-test-subj'?: string;
}> = ({
from,
cancelUrl,
cancelOnClick,
onCancel,
agentConfig,
packageInfo,
children,
Expand All @@ -45,7 +45,7 @@ export const CreateDatasourcePageLayout: React.FunctionComponent<{
iconType="arrowLeft"
flush="left"
href={cancelUrl}
onClick={cancelOnClick}
onClick={onCancel}
data-test-subj={`${dataTestSubj}_cancelBackLink`}
>
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export const CreateDatasourcePage: React.FunctionComponent = () => {
const layoutProps = {
from,
cancelUrl,
cancelOnClick: cancelClickHandler,
onCancel: cancelClickHandler,
agentConfig,
packageInfo,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

import { PolicyData } from '../../../../../../common/endpoint/types';
import { ServerApiError } from '../../../../../common/types';
import { GetAgentStatusResponse } from '../../../../../../../ingest_manager/common/types/rest_spec';
import {
GetAgentStatusResponse,
GetPackagesResponse,
} from '../../../../../../../ingest_manager/common';

interface ServerReturnedPolicyListData {
type: 'serverReturnedPolicyListData';
Expand Down Expand Up @@ -53,6 +56,11 @@ interface ServerReturnedPolicyAgentsSummaryForDelete {
payload: { agentStatusSummary: GetAgentStatusResponse['results'] };
}

interface ServerReturnedEndpointPackageInfo {
type: 'serverReturnedEndpointPackageInfo';
payload: GetPackagesResponse['response'][0];
}

export type PolicyListAction =
| ServerReturnedPolicyListData
| ServerFailedToReturnPolicyListData
Expand All @@ -61,4 +69,5 @@ export type PolicyListAction =
| ServerDeletedPolicy
| UserOpenedPolicyListDeleteModal
| ServerReturnedPolicyAgentsSummaryForDeleteFailure
| ServerReturnedPolicyAgentsSummaryForDelete;
| ServerReturnedPolicyAgentsSummaryForDelete
| ServerReturnedEndpointPackageInfo;
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
selectIsLoading,
urlSearchParams,
selectIsDeleting,
endpointPackageVersion,
} from './selectors';
import { DepsStartMock, depsStartMock } from '../../../../../common/mock/endpoint';
import { setPolicyListApiMockImplementation } from './test_mock_utils';
Expand Down Expand Up @@ -254,5 +255,21 @@ describe('policy list store concerns', () => {
page_size: 50,
});
});

it('should load package information only if not already in state', async () => {
dispatchUserChangedUrl('?page_size=10&page_index=10');
await waitForAction('serverReturnedEndpointPackageInfo');
expect(endpointPackageVersion(store.getState())).toEqual('0.5.0');
fakeCoreStart.http.get.mockClear();
dispatchUserChangedUrl('?page_size=10&page_index=11');
expect(fakeCoreStart.http.get).toHaveBeenCalledWith(INGEST_API_DATASOURCES, {
query: {
kuery: `${DATASOURCE_SAVED_OBJECT_TYPE}.package.name: endpoint`,
page: 12,
perPage: 10,
},
});
expect(endpointPackageVersion(store.getState())).toEqual('0.5.0');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import {
sendGetEndpointSpecificDatasources,
sendDeleteDatasource,
sendGetFleetAgentStatusForConfig,
sendGetEndpointSecurityPackage,
} from './services/ingest';
import { isOnPolicyListPage, urlSearchParams } from './selectors';
import { endpointPackageInfo, isOnPolicyListPage, urlSearchParams } from './selectors';
import { ImmutableMiddlewareFactory } from '../../../../../common/store';
import { initialPolicyListState } from './reducer';
import {
Expand All @@ -32,6 +33,25 @@ export const policyListMiddlewareFactory: ImmutableMiddlewareFactory<PolicyListS
(action.type === 'userChangedUrl' && isOnPolicyListPage(state)) ||
action.type === 'serverDeletedPolicy'
) {
if (!endpointPackageInfo(state)) {
// We only need the package information to retrieve the version number,
// and even if we don't have the version, the UI is still ok because we
// handle that condition. Because of this, we retrieve the package information
// in a non-blocking way here and also ignore any API failures (only log it
// to the console)
sendGetEndpointSecurityPackage(http)
.then((packageInfo) => {
dispatch({
type: 'serverReturnedEndpointPackageInfo',
payload: packageInfo,
});
})
.catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
});
}

const { page_index: pageIndex, page_size: pageSize } = urlSearchParams(state);
let response: GetPolicyListResponse;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { PolicyListState } from '../../types';
*/
export const initialPolicyListState: () => Immutable<PolicyListState> = () => ({
policyItems: [],
endpointPackageInfo: undefined,
isLoading: false,
isDeleting: false,
deleteStatus: undefined,
Expand Down Expand Up @@ -95,6 +96,13 @@ export const policyListReducer: ImmutableReducer<PolicyListState, AppAction> = (
};
}

if (action.type === 'serverReturnedEndpointPackageInfo') {
return {
...state,
endpointPackageInfo: action.payload,
};
}

if (action.type === 'userChangedUrl') {
const newState: Immutable<PolicyListState> = {
...state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,17 @@ export const urlSearchParams: (

return searchParams;
});

/**
* Returns package information for Endpoint
* @param state
*/
export const endpointPackageInfo = (state: Immutable<PolicyListState>) => state.endpointPackageInfo;

/**
* Returns the version number for the endpoint package.
*/
export const endpointPackageVersion = createSelector(
endpointPackageInfo,
(info) => info?.version ?? undefined
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { sendGetDatasource, sendGetEndpointSpecificDatasources } from './ingest';
import {
sendGetDatasource,
sendGetEndpointSecurityPackage,
sendGetEndpointSpecificDatasources,
} from './ingest';
import { httpServiceMock } from '../../../../../../../../../../src/core/public/mocks';
import { DATASOURCE_SAVED_OBJECT_TYPE } from '../../../../../../../../ingest_manager/common';

Expand Down Expand Up @@ -37,6 +41,7 @@ describe('ingest service', () => {
});
});
});

describe('sendGetDatasource()', () => {
it('builds correct API path', async () => {
await sendGetDatasource(http, '123');
Expand All @@ -51,4 +56,90 @@ describe('ingest service', () => {
});
});
});

describe('sendGetEndpointSecurityPackage()', () => {
it('should query EPM with category=security', async () => {
http.get.mockResolvedValue({
response: [
{
name: 'endpoint',
title: 'Elastic Endpoint',
version: '0.5.0',
description: 'This is the Elastic Endpoint package.',
type: 'solution',
download: '/epr/endpoint/endpoint-0.5.0.tar.gz',
path: '/package/endpoint/0.5.0',
icons: [
{
src: '/package/endpoint/0.5.0/img/logo-endpoint-64-color.svg',
size: '16x16',
type: 'image/svg+xml',
},
],
status: 'installed',
savedObject: {
type: 'epm-packages',
id: 'endpoint',
attributes: {
installed: [
{ id: '826759f0-7074-11ea-9bc8-6b38f4d29a16', type: 'dashboard' },
{ id: '1cfceda0-728b-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
{ id: '1e525190-7074-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
{ id: '55387750-729c-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
{ id: '92b1edc0-706a-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
{ id: 'a3a3bd10-706b-11ea-9bc8-6b38f4d29a16', type: 'map' },
{ id: 'logs-endpoint.alerts', type: 'index-template' },
{ id: 'events-endpoint', type: 'index-template' },
{ id: 'logs-endpoint.events.file', type: 'index-template' },
{ id: 'logs-endpoint.events.library', type: 'index-template' },
{ id: 'metrics-endpoint.metadata', type: 'index-template' },
{ id: 'metrics-endpoint.metadata_mirror', type: 'index-template' },
{ id: 'logs-endpoint.events.network', type: 'index-template' },
{ id: 'metrics-endpoint.policy', type: 'index-template' },
{ id: 'logs-endpoint.events.process', type: 'index-template' },
{ id: 'logs-endpoint.events.registry', type: 'index-template' },
{ id: 'logs-endpoint.events.security', type: 'index-template' },
{ id: 'metrics-endpoint.telemetry', type: 'index-template' },
],
es_index_patterns: {
alerts: 'logs-endpoint.alerts-*',
events: 'events-endpoint-*',
file: 'logs-endpoint.events.file-*',
library: 'logs-endpoint.events.library-*',
metadata: 'metrics-endpoint.metadata-*',
metadata_mirror: 'metrics-endpoint.metadata_mirror-*',
network: 'logs-endpoint.events.network-*',
policy: 'metrics-endpoint.policy-*',
process: 'logs-endpoint.events.process-*',
registry: 'logs-endpoint.events.registry-*',
security: 'logs-endpoint.events.security-*',
telemetry: 'metrics-endpoint.telemetry-*',
},
name: 'endpoint',
version: '0.5.0',
internal: false,
removable: false,
},
references: [],
updated_at: '2020-06-24T14:41:23.098Z',
version: 'Wzc0LDFd',
score: 0,
},
},
],
success: true,
});
await sendGetEndpointSecurityPackage(http);
expect(http.get).toHaveBeenCalledWith('/api/ingest_manager/epm/packages', {
query: { category: 'security' },
});
});

it('should throw if package is not found', async () => {
http.get.mockResolvedValue({ response: [], success: true });
await expect(async () => {
await sendGetEndpointSecurityPackage(http);
}).rejects.toThrow();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const INGEST_API_ROOT = `/api/ingest_manager`;
export const INGEST_API_DATASOURCES = `${INGEST_API_ROOT}/datasources`;
const INGEST_API_FLEET = `${INGEST_API_ROOT}/fleet`;
const INGEST_API_FLEET_AGENT_STATUS = `${INGEST_API_FLEET}/agent-status`;
const INGEST_API_EPM_PACKAGES = `${INGEST_API_ROOT}/epm/packages`;
export const INGEST_API_EPM_PACKAGES = `${INGEST_API_ROOT}/epm/packages`;
const INGEST_API_DELETE_DATASOURCE = `${INGEST_API_DATASOURCES}/delete`;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
*/

import { HttpStart } from 'kibana/public';
import { INGEST_API_DATASOURCES } from './services/ingest';
import { INGEST_API_DATASOURCES, INGEST_API_EPM_PACKAGES } from './services/ingest';
import { EndpointDocGenerator } from '../../../../../../common/endpoint/generate_data';
import { GetPolicyListResponse } from '../../types';
import {
AssetReference,
GetPackagesResponse,
InstallationStatus,
} from '../../../../../../../ingest_manager/common';

const generator = new EndpointDocGenerator('policy-list');

Expand All @@ -32,6 +37,78 @@ export const setPolicyListApiMockImplementation = (
success: true,
});
}

if (path === INGEST_API_EPM_PACKAGES) {
return Promise.resolve<GetPackagesResponse>({
response: [
{
name: 'endpoint',
title: 'Elastic Endpoint',
version: '0.5.0',
description: 'This is the Elastic Endpoint package.',
type: 'solution',
download: '/epr/endpoint/endpoint-0.5.0.tar.gz',
path: '/package/endpoint/0.5.0',
icons: [
{
src: '/package/endpoint/0.5.0/img/logo-endpoint-64-color.svg',
size: '16x16',
type: 'image/svg+xml',
},
],
status: 'installed' as InstallationStatus,
savedObject: {
type: 'epm-packages',
id: 'endpoint',
attributes: {
installed: [
{ id: '826759f0-7074-11ea-9bc8-6b38f4d29a16', type: 'dashboard' },
{ id: '1cfceda0-728b-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
{ id: '1e525190-7074-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
{ id: '55387750-729c-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
{ id: '92b1edc0-706a-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
{ id: 'a3a3bd10-706b-11ea-9bc8-6b38f4d29a16', type: 'map' },
{ id: 'logs-endpoint.alerts', type: 'index-template' },
{ id: 'events-endpoint', type: 'index-template' },
{ id: 'logs-endpoint.events.file', type: 'index-template' },
{ id: 'logs-endpoint.events.library', type: 'index-template' },
{ id: 'metrics-endpoint.metadata', type: 'index-template' },
{ id: 'metrics-endpoint.metadata_mirror', type: 'index-template' },
{ id: 'logs-endpoint.events.network', type: 'index-template' },
{ id: 'metrics-endpoint.policy', type: 'index-template' },
{ id: 'logs-endpoint.events.process', type: 'index-template' },
{ id: 'logs-endpoint.events.registry', type: 'index-template' },
{ id: 'logs-endpoint.events.security', type: 'index-template' },
{ id: 'metrics-endpoint.telemetry', type: 'index-template' },
] as AssetReference[],
es_index_patterns: {
alerts: 'logs-endpoint.alerts-*',
events: 'events-endpoint-*',
file: 'logs-endpoint.events.file-*',
library: 'logs-endpoint.events.library-*',
metadata: 'metrics-endpoint.metadata-*',
metadata_mirror: 'metrics-endpoint.metadata_mirror-*',
network: 'logs-endpoint.events.network-*',
policy: 'metrics-endpoint.policy-*',
process: 'logs-endpoint.events.process-*',
registry: 'logs-endpoint.events.registry-*',
security: 'logs-endpoint.events.security-*',
telemetry: 'metrics-endpoint.telemetry-*',
},
name: 'endpoint',
version: '0.5.0',
internal: false,
removable: false,
},
references: [],
updated_at: '2020-06-24T14:41:23.098Z',
version: 'Wzc0LDFd',
},
},
],
success: true,
});
}
}
return Promise.reject(new Error(`MOCK: unknown policy list api: ${path}`));
});
Expand Down
Loading