[Security Solution] throttle package calls on initial security page load (#103570)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Joey F. Poon 2021-06-29 22:05:30 -05:00 committed by GitHub
parent 428eba425d
commit 699731f25e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 25 deletions

View file

@ -15,7 +15,6 @@ import {
} from '../../../../../common/endpoint/types';
import { ServerApiError } from '../../../../common/types';
import { GetPolicyListResponse } from '../../policy/types';
import { GetPackagesResponse } from '../../../../../../fleet/common';
import { EndpointIndexUIQueryParams, EndpointState } from '../types';
import { IIndexPattern } from '../../../../../../../../src/plugins/data/public';
@ -75,10 +74,9 @@ export interface ServerCancelledPolicyItemsLoading {
type: 'serverCancelledPolicyItemsLoading';
}
export interface ServerReturnedEndpointPackageInfo {
type: 'serverReturnedEndpointPackageInfo';
payload: GetPackagesResponse['response'][0];
}
export type EndpointPackageInfoStateChanged = Action<'endpointPackageInfoStateChanged'> & {
payload: EndpointState['endpointPackageInfo'];
};
export interface ServerReturnedEndpointNonExistingPolicies {
type: 'serverReturnedEndpointNonExistingPolicies';
@ -195,7 +193,7 @@ export type EndpointAction =
| ServerCancelledEndpointListLoading
| ServerReturnedEndpointExistValue
| ServerCancelledPolicyItemsLoading
| ServerReturnedEndpointPackageInfo
| EndpointPackageInfoStateChanged
| ServerReturnedMetadataPatterns
| ServerFailedToReturnMetadataPatterns
| AppRequestedEndpointList

View file

@ -41,7 +41,7 @@ export const initialEndpointPageState = (): Immutable<EndpointState> => {
policyItems: [],
selectedPolicyId: undefined,
policyItemsLoading: false,
endpointPackageInfo: undefined,
endpointPackageInfo: createUninitialisedResourceState(),
nonExistingPolicies: {},
agentPolicies: {},
endpointsExist: true,

View file

@ -64,7 +64,9 @@ describe('EndpointList store concerns', () => {
policyItems: [],
selectedPolicyId: undefined,
policyItemsLoading: false,
endpointPackageInfo: undefined,
endpointPackageInfo: {
type: 'UninitialisedResourceState',
},
nonExistingPolicies: {},
agentPolicies: {},
endpointsExist: true,

View file

@ -36,6 +36,8 @@ import {
getLastLoadedActivityLogData,
detailsData,
getEndpointDetailsFlyoutView,
getIsEndpointPackageInfoPending,
getIsEndpointPackageInfoSuccessful,
} from './selectors';
import { AgentIdsPendingActions, EndpointState, PolicyIds } from '../types';
import {
@ -44,7 +46,7 @@ import {
sendGetAgentPolicyList,
sendGetFleetAgentsWithEndpoint,
} from '../../policy/store/services/ingest';
import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../fleet/common';
import { AGENT_POLICY_SAVED_OBJECT_TYPE, PackageListItem } from '../../../../../../fleet/common';
import {
ENDPOINT_ACTION_LOG_ROUTE,
HOST_METADATA_GET_ROUTE,
@ -61,7 +63,7 @@ import {
import { isolateHost, unIsolateHost } from '../../../../common/lib/endpoint_isolation';
import { AppAction } from '../../../../common/store/actions';
import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables';
import { ServerReturnedEndpointPackageInfo } from './action';
import { EndpointPackageInfoStateChanged } from './action';
import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions';
import { EndpointDetailsTabsTypes } from '../view/details/components/endpoint_details_tabs';
@ -593,20 +595,31 @@ const handleIsolateEndpointHost = async (
async function getEndpointPackageInfo(
state: ImmutableObject<EndpointState>,
dispatch: Dispatch<ServerReturnedEndpointPackageInfo>,
dispatch: Dispatch<EndpointPackageInfoStateChanged>,
coreStart: CoreStart
) {
if (endpointPackageInfo(state)) return;
if (getIsEndpointPackageInfoPending(state) || getIsEndpointPackageInfoSuccessful(state)) return;
dispatch({
type: 'endpointPackageInfoStateChanged',
// Ignore will be fixed with when AsyncResourceState is refactored (#830)
// @ts-ignore
payload: createLoadingResourceState<PackageListItem>(endpointPackageInfo(state)),
});
try {
const packageInfo = await sendGetEndpointSecurityPackage(coreStart.http);
dispatch({
type: 'serverReturnedEndpointPackageInfo',
payload: packageInfo,
type: 'endpointPackageInfoStateChanged',
payload: createLoadedResourceState(packageInfo),
});
} catch (error) {
// Ignore Errors, since this should not hinder the user's ability to use the UI
logError(error);
dispatch({
type: 'endpointPackageInfoStateChanged',
payload: createFailedResourceState(error),
});
}
}

View file

@ -5,7 +5,11 @@
* 2.0.
*/
import { EndpointDetailsActivityLogChanged, EndpointPendingActionsStateChanged } from './action';
import {
EndpointDetailsActivityLogChanged,
EndpointPackageInfoStateChanged,
EndpointPendingActionsStateChanged,
} from './action';
import {
isOnEndpointPage,
hasSelectedEndpoint,
@ -65,6 +69,16 @@ const handleEndpointPendingActionsStateChanged: CaseReducer<EndpointPendingActio
return state;
};
const handleEndpointPackageInfoStateChanged: CaseReducer<EndpointPackageInfoStateChanged> = (
state,
action
) => {
return {
...state,
endpointPackageInfo: action.payload,
};
};
/* eslint-disable-next-line complexity */
export const endpointListReducer: StateReducer = (state = initialEndpointPageState(), action) => {
if (action.type === 'serverReturnedEndpointList') {
@ -231,11 +245,8 @@ export const endpointListReducer: StateReducer = (state = initialEndpointPageSta
...state,
policyItemsLoading: false,
};
} else if (action.type === 'serverReturnedEndpointPackageInfo') {
return {
...state,
endpointPackageInfo: action.payload,
};
} else if (action.type === 'endpointPackageInfoStateChanged') {
return handleEndpointPackageInfoStateChanged(state, action);
} else if (action.type === 'serverReturnedEndpointExistValue') {
return {
...state,

View file

@ -69,6 +69,16 @@ export const policyItemsLoading = (state: Immutable<EndpointState>) => state.pol
export const selectedPolicyId = (state: Immutable<EndpointState>) => state.selectedPolicyId;
export const endpointPackageInfo = (state: Immutable<EndpointState>) => state.endpointPackageInfo;
export const getIsEndpointPackageInfoPending: (
state: Immutable<EndpointState>
) => boolean = createSelector(endpointPackageInfo, (packageInfo) =>
isLoadingResourceState(packageInfo)
);
export const getIsEndpointPackageInfoSuccessful: (
state: Immutable<EndpointState>
) => boolean = createSelector(endpointPackageInfo, (packageInfo) =>
isLoadedResourceState(packageInfo)
);
export const isAutoRefreshEnabled = (state: Immutable<EndpointState>) => state.isAutoRefreshEnabled;
@ -86,9 +96,8 @@ export const agentsWithEndpointsTotalError = (state: Immutable<EndpointState>) =
export const endpointsTotalError = (state: Immutable<EndpointState>) => state.endpointsTotalError;
const queryStrategyVersion = (state: Immutable<EndpointState>) => state.queryStrategyVersion;
export const endpointPackageVersion = createSelector(
endpointPackageInfo,
(info) => info?.version ?? undefined
export const endpointPackageVersion = createSelector(endpointPackageInfo, (info) =>
isLoadedResourceState(info) ? info.data.version : undefined
);
export const isTransformEnabled = createSelector(

View file

@ -70,7 +70,7 @@ export interface EndpointState {
/** the selected policy ID in the onboarding flow */
selectedPolicyId?: string;
/** Endpoint package info */
endpointPackageInfo?: GetPackagesResponse['response'][0];
endpointPackageInfo: AsyncResourceState<GetPackagesResponse['response'][0]>;
/** Tracks the list of policies IDs used in Host metadata that may no longer exist */
nonExistingPolicies: PolicyIds['packagePolicy'];
/** List of Package Policy Ids mapped to an associated Fleet Parent Agent Policy Id*/

View file

@ -762,8 +762,9 @@ describe('When on the Trusted Apps Page', () => {
});
beforeEach(() => {
const priorMockImplementation = coreStart.http.get.getMockImplementation();
// @ts-ignore
coreStart.http.get.mockImplementation(async (path, options) => {
coreStart.http.get.mockImplementation((path, options) => {
if (path === TRUSTED_APPS_LIST_API) {
const { page, per_page: perPage } = options.query as { page: number; per_page: number };
@ -773,6 +774,9 @@ describe('When on the Trusted Apps Page', () => {
return releaseListResponse();
}
}
if (priorMockImplementation) {
return priorMockImplementation(path);
}
});
});