diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts index 0b41dc5608fe..bed9c2880440 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -380,12 +380,12 @@ export enum HostStatus { * Default state of the host when no host information is present or host information cannot * be retrieved. e.g. API error */ - ERROR = 'error', + UNHEALTHY = 'unhealthy', /** * Host is online as indicated by its checkin status during the last checkin window */ - ONLINE = 'online', + HEALTHY = 'healthy', /** * Host is offline as indicated by its checkin status during the last checkin window @@ -393,9 +393,14 @@ export enum HostStatus { OFFLINE = 'offline', /** - * Host is unenrolling as indicated by its checkin status during the last checkin window + * Host is unenrolling, enrolling or updating as indicated by its checkin status during the last checkin window */ - UNENROLLING = 'unenrolling', + UPDATING = 'updating', + + /** + * Host is inactive as indicated by its checkin status during the last checkin window + */ + INACTIVE = 'inactive', } export enum MetadataQueryStrategyVersions { diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts index 404ee0cd4aa2..40b843a676d9 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts @@ -54,7 +54,7 @@ export const mockEndpointResultList: (options?: { for (let index = 0; index < actualCountToReturn; index++) { hosts.push({ metadata: generator.generateHostMetadata(), - host_status: HostStatus.ERROR, + host_status: HostStatus.UNHEALTHY, query_strategy_version: queryStrategyVersion, }); } @@ -74,7 +74,7 @@ export const mockEndpointResultList: (options?: { export const mockEndpointDetailsApiResult = (): HostInfo => { return { metadata: generator.generateHostMetadata(), - host_status: HostStatus.ERROR, + host_status: HostStatus.UNHEALTHY, query_strategy_version: MetadataQueryStrategyVersions.VERSION_2, }; }; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts index 17ce24e7cda7..eec4de640014 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts @@ -231,7 +231,7 @@ export const showView: (state: EndpointState) => 'policy_response' | 'details' = export const hostStatusInfo: (state: Immutable) => HostStatus = createSelector( (state) => state.hostStatus, (hostStatus) => { - return hostStatus ? hostStatus : HostStatus.ERROR; + return hostStatus ? hostStatus : HostStatus.UNHEALTHY; } ); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx index eb3e534ba427..c97e097ea9b7 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx @@ -8,7 +8,6 @@ import styled from 'styled-components'; import { EuiDescriptionList, - EuiHealth, EuiHorizontalRule, EuiListGroup, EuiListGroupItem, @@ -17,6 +16,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiBadge, + EuiSpacer, } from '@elastic/eui'; import React, { memo, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -26,11 +26,7 @@ import { HostInfo, HostMetadata, HostStatus } from '../../../../../../common/end import { useEndpointSelector, useAgentDetailsIngestUrl } from '../hooks'; import { useNavigateToAppEventHandler } from '../../../../../common/hooks/endpoint/use_navigate_to_app_event_handler'; import { policyResponseStatus, uiQueryParams } from '../../store/selectors'; -import { - POLICY_STATUS_TO_HEALTH_COLOR, - POLICY_STATUS_TO_BADGE_COLOR, - HOST_STATUS_TO_HEALTH_COLOR, -} from '../host_constants'; +import { POLICY_STATUS_TO_BADGE_COLOR, HOST_STATUS_TO_BADGE_COLOR } from '../host_constants'; import { FormattedDateAndTime } from '../../../../../common/components/endpoint/formatted_date_time'; import { useNavigateByRouterEventHandler } from '../../../../../common/hooks/endpoint/use_navigate_by_router_event_handler'; import { LinkToApp } from '../../../../../common/components/endpoint/link_to_app'; @@ -48,17 +44,6 @@ const HostIds = styled(EuiListGroupItem)` } `; -const LinkToExternalApp = styled.div` - margin-top: ${(props) => props.theme.eui.ruleMargins.marginMedium}; - .linkToAppIcon { - margin-right: ${(props) => props.theme.eui.ruleMargins.marginXSmall}; - vertical-align: top; - } - .linkToAppPopoutIcon { - margin-left: ${(props) => props.theme.eui.ruleMargins.marginXSmall}; - } -`; - const openReassignFlyoutSearch = '?openReassignFlyout=true'; export const EndpointDetails = memo( @@ -80,7 +65,7 @@ export const EndpointDetails = memo( const queryParams = useEndpointSelector(uiQueryParams); const policyStatus = useEndpointSelector( policyResponseStatus - ) as keyof typeof POLICY_STATUS_TO_HEALTH_COLOR; + ) as keyof typeof POLICY_STATUS_TO_BADGE_COLOR; const { formatUrl } = useFormatUrl(SecurityPageName.administration); const detailsResultsUpper = useMemo(() => { @@ -89,32 +74,37 @@ export const EndpointDetails = memo( title: i18n.translate('xpack.securitySolution.endpoint.details.os', { defaultMessage: 'OS', }), - description: details.host.os.full, + description: {details.host.os.full}, }, { title: i18n.translate('xpack.securitySolution.endpoint.details.agentStatus', { defaultMessage: 'Agent Status', }), description: ( - - + ), }, { title: i18n.translate('xpack.securitySolution.endpoint.details.lastSeen', { defaultMessage: 'Last Seen', }), - description: , + description: ( + + {' '} + + + ), }, ]; }, [details, hostStatus]); @@ -169,12 +159,14 @@ export const EndpointDetails = memo( description: ( - - {details.Endpoint.policy.applied.name} - + + + {details.Endpoint.policy.applied.name} + + {details.Endpoint.policy.applied.endpoint_policy_version && ( @@ -241,9 +233,11 @@ export const EndpointDetails = memo( }), description: ( - {details.host.ip.map((ip: string, index: number) => ( - - ))} + + {details.host.ip.map((ip: string, index: number) => ( + + ))} + ), }, @@ -251,13 +245,13 @@ export const EndpointDetails = memo( title: i18n.translate('xpack.securitySolution.endpoint.details.hostname', { defaultMessage: 'Hostname', }), - description: details.host.hostname, + description: {details.host.hostname}, }, { title: i18n.translate('xpack.securitySolution.endpoint.details.endpointVersion', { defaultMessage: 'Endpoint Version', }), - description: details.agent.version, + description: {details.agent.version}, }, ]; }, [details.agent.version, details.host.hostname, details.host.ip]); @@ -275,22 +269,36 @@ export const EndpointDetails = memo( listItems={detailsResultsPolicy} data-test-subj="endpointDetailsPolicyList" /> - - + + - - - - - + + + + + + + + + + + + + ({ - [HostStatus.ERROR]: 'danger', - [HostStatus.ONLINE]: 'success', - [HostStatus.OFFLINE]: 'subdued', - [HostStatus.UNENROLLING]: 'warning', + [HostStatus.HEALTHY]: 'secondary', + [HostStatus.UNHEALTHY]: 'warning', + [HostStatus.UPDATING]: 'primary', + [HostStatus.OFFLINE]: 'default', + [HostStatus.INACTIVE]: 'default', }); export const POLICY_STATUS_TO_HEALTH_COLOR = Object.freeze< { [key in keyof typeof HostPolicyResponseActionStatus]: string } >({ - success: 'success', + success: 'secondary', warning: 'warning', failure: 'danger', - unsupported: 'subdued', + unsupported: 'default', }); export const POLICY_STATUS_TO_BADGE_COLOR = Object.freeze< diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx index 79e91fdeb813..17ebff603ccf 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx @@ -25,7 +25,7 @@ import { MetadataQueryStrategyVersions, } from '../../../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; -import { POLICY_STATUS_TO_HEALTH_COLOR, POLICY_STATUS_TO_TEXT } from './host_constants'; +import { POLICY_STATUS_TO_TEXT } from './host_constants'; import { mockPolicyResultList } from '../../policy/store/test_mock_utils'; // not sure why this can't be imported from '../../../../common/mock/formatted_relative'; @@ -232,9 +232,10 @@ describe('when on the list page', () => { > = []; let firstPolicyID: string; let firstPolicyRev: number; + beforeEach(() => { reactTestingLibrary.act(() => { - const mockedEndpointData = mockEndpointResultList({ total: 4 }); + const mockedEndpointData = mockEndpointResultList({ total: 5 }); const hostListData = mockedEndpointData.hosts; const queryStrategyVersion = mockedEndpointData.query_strategy_version; @@ -259,9 +260,9 @@ describe('when on the list page', () => { }; [ - { status: HostStatus.ERROR, policy: (p: Policy) => p }, + { status: HostStatus.UNHEALTHY, policy: (p: Policy) => p }, { - status: HostStatus.ONLINE, + status: HostStatus.HEALTHY, policy: (p: Policy) => { p.endpoint.id = 'xyz'; // represents change in endpoint policy assignment p.endpoint.revision = 1; @@ -276,7 +277,14 @@ describe('when on the list page', () => { }, }, { - status: HostStatus.UNENROLLING, + status: HostStatus.UPDATING, + policy: (p: Policy) => { + p.agent.configured.revision += 1; // agent policy change, not propagated to agent yet + return p; + }, + }, + { + status: HostStatus.INACTIVE, policy: (p: Policy) => { p.agent.configured.revision += 1; // agent policy change, not propagated to agent yet return p; @@ -317,7 +325,7 @@ describe('when on the list page', () => { await middlewareSpy.waitForAction('serverReturnedEndpointList'); }); const rows = await renderResult.findAllByRole('row'); - expect(rows).toHaveLength(5); + expect(rows).toHaveLength(6); }); it('should show total', async () => { const renderResult = render(); @@ -325,7 +333,7 @@ describe('when on the list page', () => { await middlewareSpy.waitForAction('serverReturnedEndpointList'); }); const total = await renderResult.findByTestId('endpointListTableTotal'); - expect(total.textContent).toEqual('4 Hosts'); + expect(total.textContent).toEqual('5 Hosts'); }); it('should display correct status', async () => { const renderResult = render(); @@ -334,23 +342,30 @@ describe('when on the list page', () => { }); const hostStatuses = await renderResult.findAllByTestId('rowHostStatus'); - expect(hostStatuses[0].textContent).toEqual('Error'); - expect(hostStatuses[0].querySelector('[data-euiicon-type][color="danger"]')).not.toBeNull(); + expect(hostStatuses[0].textContent).toEqual('Unhealthy'); + expect(hostStatuses[0].getAttribute('style')).toMatch( + /background-color\: rgb\(241\, 216\, 111\)\;/ + ); - expect(hostStatuses[1].textContent).toEqual('Online'); - expect( - hostStatuses[1].querySelector('[data-euiicon-type][color="success"]') - ).not.toBeNull(); + expect(hostStatuses[1].textContent).toEqual('Healthy'); + expect(hostStatuses[1].getAttribute('style')).toMatch( + /background-color\: rgb\(109\, 204\, 177\)\;/ + ); expect(hostStatuses[2].textContent).toEqual('Offline'); - expect( - hostStatuses[2].querySelector('[data-euiicon-type][color="subdued"]') - ).not.toBeNull(); + expect(hostStatuses[2].getAttribute('style')).toMatch( + /background-color\: rgb\(211\, 218\, 230\)\;/ + ); - expect(hostStatuses[3].textContent).toEqual('Unenrolling'); - expect( - hostStatuses[3].querySelector('[data-euiicon-type][color="warning"]') - ).not.toBeNull(); + expect(hostStatuses[3].textContent).toEqual('Updating'); + expect(hostStatuses[3].getAttribute('style')).toMatch( + /background-color\: rgb\(121\, 170\, 217\)\;/ + ); + + expect(hostStatuses[4].textContent).toEqual('Inactive'); + expect(hostStatuses[4].getAttribute('style')).toMatch( + /background-color\: rgb\(211\, 218\, 230\)\;/ + ); }); it('should display correct policy status', async () => { @@ -361,14 +376,18 @@ describe('when on the list page', () => { const policyStatuses = await renderResult.findAllByTestId('rowPolicyStatus'); policyStatuses.forEach((status, index) => { + const policyStatusToRGBColor: Array<[string, string]> = [ + ['Success', 'background-color: rgb(109, 204, 177);'], + ['Warning', 'background-color: rgb(241, 216, 111);'], + ['Failure', 'background-color: rgb(255, 126, 98);'], + ['Unsupported', 'background-color: rgb(211, 218, 230);'], + ]; + const policyStatusStyleMap: ReadonlyMap = new Map( + policyStatusToRGBColor + ); + const expectedStatusColor: string = policyStatusStyleMap.get(status.textContent!) ?? ''; expect(status.textContent).toEqual(POLICY_STATUS_TO_TEXT[generatedPolicyStatuses[index]]); - expect( - status.querySelector( - `[data-euiicon-type][color=${ - POLICY_STATUS_TO_HEALTH_COLOR[generatedPolicyStatuses[index]] - }]` - ) - ).not.toBeNull(); + expect(status.getAttribute('style')).toMatch(expectedStatusColor); }); }); @@ -378,7 +397,7 @@ describe('when on the list page', () => { await middlewareSpy.waitForAction('serverReturnedEndpointList'); }); const outOfDates = await renderResult.findAllByTestId('rowPolicyOutOfDate'); - expect(outOfDates).toHaveLength(3); + expect(outOfDates).toHaveLength(4); outOfDates.forEach((item, index) => { expect(item.textContent).toEqual('Out-of-date'); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx index c4c27bd49395..d28bf6b38fd3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx @@ -5,14 +5,14 @@ * 2.0. */ -import React, { useMemo, useCallback, memo, useState } from 'react'; +import React, { useMemo, useCallback, memo, useState, useContext } from 'react'; import { EuiHorizontalRule, EuiBasicTable, EuiBasicTableColumn, EuiText, EuiLink, - EuiHealth, + EuiBadge, EuiToolTip, EuiSelectableProps, EuiSuperDatePicker, @@ -33,13 +33,14 @@ import { createStructuredSelector } from 'reselect'; import { useDispatch } from 'react-redux'; import { EuiContextMenuItemProps } from '@elastic/eui/src/components/context_menu/context_menu_item'; import { NavigateToAppOptions } from 'kibana/public'; +import { ThemeContext } from 'styled-components'; import { EndpointDetailsFlyout } from './details'; import * as selectors from '../store/selectors'; import { useEndpointSelector } from './hooks'; import { isPolicyOutOfDate } from '../utils'; import { - HOST_STATUS_TO_HEALTH_COLOR, - POLICY_STATUS_TO_HEALTH_COLOR, + HOST_STATUS_TO_BADGE_COLOR, + POLICY_STATUS_TO_BADGE_COLOR, POLICY_STATUS_TO_TEXT, } from './host_constants'; import { useNavigateByRouterEventHandler } from '../../../../common/hooks/endpoint/use_navigate_by_router_event_handler'; @@ -72,11 +73,24 @@ const EndpointListNavLink = memo<{ name: string; href: string; route: string; + isBadge?: boolean; dataTestSubj: string; -}>(({ name, href, route, dataTestSubj }) => { +}>(({ name, href, route, isBadge = false, dataTestSubj }) => { const clickHandler = useNavigateByRouterEventHandler(route); + const theme = useContext(ThemeContext); - return ( + return isBadge ? ( + // eslint-disable-next-line @elastic/eui/href-or-on-click + + {name} + + ) : ( // eslint-disable-next-line @elastic/eui/href-or-on-click { // eslint-disable-next-line react/display-name render: (hostStatus: HostInfo['host_status']) => { return ( - - + ); }, }, @@ -375,8 +389,8 @@ export const EndpointList = () => { }); const toRouteUrl = formatUrl(toRoutePath); return ( - @@ -384,9 +398,10 @@ export const EndpointList = () => { name={POLICY_STATUS_TO_TEXT[policy.status]} href={toRouteUrl} route={toRoutePath} + isBadge dataTestSubj="policyStatusCellLink" /> - + ); }, }, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts index cd439db6070d..960f3abda819 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts @@ -54,7 +54,7 @@ describe('test document enrichment', () => { }); }); - it('should return host online for online agent', async () => { + it('should return host healthy for online agent', async () => { statusFn.mockImplementation(() => 'online'); const enrichedHostList = await enrichHostMetadata( @@ -62,7 +62,7 @@ describe('test document enrichment', () => { metaReqCtx, MetadataQueryStrategyVersions.VERSION_2 ); - expect(enrichedHostList.host_status).toEqual(HostStatus.ONLINE); + expect(enrichedHostList.host_status).toEqual(HostStatus.HEALTHY); }); it('should return host offline for offline agent', async () => { @@ -76,7 +76,7 @@ describe('test document enrichment', () => { expect(enrichedHostList.host_status).toEqual(HostStatus.OFFLINE); }); - it('should return host unenrolling for unenrolling agent', async () => { + it('should return host updating for unenrolling agent', async () => { statusFn.mockImplementation(() => 'unenrolling'); const enrichedHostList = await enrichHostMetadata( @@ -84,10 +84,10 @@ describe('test document enrichment', () => { metaReqCtx, MetadataQueryStrategyVersions.VERSION_2 ); - expect(enrichedHostList.host_status).toEqual(HostStatus.UNENROLLING); + expect(enrichedHostList.host_status).toEqual(HostStatus.UPDATING); }); - it('should return host error for degraded agent', async () => { + it('should return host unhealthy for degraded agent', async () => { statusFn.mockImplementation(() => 'degraded'); const enrichedHostList = await enrichHostMetadata( @@ -95,10 +95,10 @@ describe('test document enrichment', () => { metaReqCtx, MetadataQueryStrategyVersions.VERSION_2 ); - expect(enrichedHostList.host_status).toEqual(HostStatus.ERROR); + expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY); }); - it('should return host error for erroring agent', async () => { + it('should return host unhealthy for erroring agent', async () => { statusFn.mockImplementation(() => 'error'); const enrichedHostList = await enrichHostMetadata( @@ -106,10 +106,10 @@ describe('test document enrichment', () => { metaReqCtx, MetadataQueryStrategyVersions.VERSION_2 ); - expect(enrichedHostList.host_status).toEqual(HostStatus.ERROR); + expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY); }); - it('should return host error for warning agent', async () => { + it('should return host unhealthy for warning agent', async () => { statusFn.mockImplementation(() => 'warning'); const enrichedHostList = await enrichHostMetadata( @@ -117,10 +117,10 @@ describe('test document enrichment', () => { metaReqCtx, MetadataQueryStrategyVersions.VERSION_2 ); - expect(enrichedHostList.host_status).toEqual(HostStatus.ERROR); + expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY); }); - it('should return host error for invalid agent', async () => { + it('should return host unhealthy for invalid agent', async () => { statusFn.mockImplementation(() => 'asliduasofb'); const enrichedHostList = await enrichHostMetadata( @@ -128,7 +128,7 @@ describe('test document enrichment', () => { metaReqCtx, MetadataQueryStrategyVersions.VERSION_2 ); - expect(enrichedHostList.host_status).toEqual(HostStatus.ERROR); + expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY); }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts index d3ba16ffe006..e6a676454a27 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts @@ -33,9 +33,15 @@ export interface MetadataRequestContext { } const HOST_STATUS_MAPPING = new Map([ - ['online', HostStatus.ONLINE], + ['online', HostStatus.HEALTHY], ['offline', HostStatus.OFFLINE], - ['unenrolling', HostStatus.UNENROLLING], + ['inactive', HostStatus.INACTIVE], + ['unenrolling', HostStatus.UPDATING], + ['enrolling', HostStatus.UPDATING], + ['updating', HostStatus.UPDATING], + ['warning', HostStatus.UNHEALTHY], + ['error', HostStatus.UNHEALTHY], + ['degraded', HostStatus.UNHEALTHY], ]); /** @@ -257,7 +263,7 @@ export async function enrichHostMetadata( metadataRequestContext: MetadataRequestContext, metadataQueryStrategyVersion: MetadataQueryStrategyVersions ): Promise { - let hostStatus = HostStatus.ERROR; + let hostStatus = HostStatus.UNHEALTHY; let elasticAgentId = hostMetadata?.elastic?.agent?.id; const log = metadataRequestContext.logger; try { @@ -276,7 +282,7 @@ export async function enrichHostMetadata( metadataRequestContext.requestHandlerContext.core.elasticsearch.client.asCurrentUser, elasticAgentId ); - hostStatus = HOST_STATUS_MAPPING.get(status!) || HostStatus.ERROR; + hostStatus = HOST_STATUS_MAPPING.get(status!) || HostStatus.UNHEALTHY; } catch (e) { if (e instanceof AgentNotFoundError) { log.warn(`agent with id ${elasticAgentId} not found`); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts index 900cfc39b4af..44db86f85cf5 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts @@ -24,10 +24,11 @@ export const endpointFilters = schema.object({ host_status: schema.nullable( schema.arrayOf( schema.oneOf([ - schema.literal(HostStatus.ONLINE.toString()), + schema.literal(HostStatus.HEALTHY.toString()), schema.literal(HostStatus.OFFLINE.toString()), - schema.literal(HostStatus.UNENROLLING.toString()), - schema.literal(HostStatus.ERROR.toString()), + schema.literal(HostStatus.UPDATING.toString()), + schema.literal(HostStatus.UNHEALTHY.toString()), + schema.literal(HostStatus.INACTIVE.toString()), ]) ) ), diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts index f98142486e0d..e052a653242b 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts @@ -131,7 +131,7 @@ describe('test endpoint route', () => { ); }); - it('should return a single endpoint with status online', async () => { + it('should return a single endpoint with status healthy', async () => { const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); const mockRequest = httpServerMock.createKibanaRequest({ params: { id: response.hits.hits[0]._id }, @@ -161,7 +161,7 @@ describe('test endpoint route', () => { expect(mockResponse.ok).toBeCalled(); const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; expect(result).toHaveProperty('metadata.Endpoint'); - expect(result.host_status).toEqual(HostStatus.ONLINE); + expect(result.host_status).toEqual(HostStatus.HEALTHY); expect(result.query_strategy_version).toEqual(MetadataQueryStrategyVersions.VERSION_1); }); }); @@ -406,7 +406,7 @@ describe('test endpoint route', () => { expect(message).toEqual('Endpoint Not Found'); }); - it('should return a single endpoint with status online', async () => { + it('should return a single endpoint with status healthy', async () => { const response = createV2SearchResponse(new EndpointDocGenerator().generateHostMetadata()); const mockRequest = httpServerMock.createKibanaRequest({ params: { id: response.hits.hits[0]._id }, @@ -436,11 +436,11 @@ describe('test endpoint route', () => { expect(mockResponse.ok).toBeCalled(); const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; expect(result).toHaveProperty('metadata.Endpoint'); - expect(result.host_status).toEqual(HostStatus.ONLINE); + expect(result.host_status).toEqual(HostStatus.HEALTHY); expect(result.query_strategy_version).toEqual(MetadataQueryStrategyVersions.VERSION_2); }); - it('should return a single endpoint with status error when AgentService throw 404', async () => { + it('should return a single endpoint with status unhealthy when AgentService throw 404', async () => { const response = createV2SearchResponse(new EndpointDocGenerator().generateHostMetadata()); const mockRequest = httpServerMock.createKibanaRequest({ @@ -474,10 +474,10 @@ describe('test endpoint route', () => { }); expect(mockResponse.ok).toBeCalled(); const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; - expect(result.host_status).toEqual(HostStatus.ERROR); + expect(result.host_status).toEqual(HostStatus.UNHEALTHY); }); - it('should return a single endpoint with status error when status is not offline, online or enrolling', async () => { + it('should return a single endpoint with status unhealthy when status is not offline, online or enrolling', async () => { const response = createV2SearchResponse(new EndpointDocGenerator().generateHostMetadata()); const mockRequest = httpServerMock.createKibanaRequest({ @@ -507,7 +507,7 @@ describe('test endpoint route', () => { }); expect(mockResponse.ok).toBeCalled(); const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; - expect(result.host_status).toEqual(HostStatus.ERROR); + expect(result.host_status).toEqual(HostStatus.UNHEALTHY); }); it('should throw error when endpoint agent is not active', async () => { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts index 4a9f67ebd56a..97b0dd7f1509 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts @@ -293,7 +293,7 @@ describe('test endpoint route v1', () => { expect(message).toEqual('Endpoint Not Found'); }); - it('should return a single endpoint with status online', async () => { + it('should return a single endpoint with status healthy', async () => { const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); const mockRequest = httpServerMock.createKibanaRequest({ params: { id: response.hits.hits[0]._id }, @@ -323,10 +323,10 @@ describe('test endpoint route v1', () => { expect(mockResponse.ok).toBeCalled(); const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; expect(result).toHaveProperty('metadata.Endpoint'); - expect(result.host_status).toEqual(HostStatus.ONLINE); + expect(result.host_status).toEqual(HostStatus.HEALTHY); }); - it('should return a single endpoint with status error when AgentService throw 404', async () => { + it('should return a single endpoint with status unhealthy when AgentService throw 404', async () => { const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); const mockRequest = httpServerMock.createKibanaRequest({ @@ -360,10 +360,10 @@ describe('test endpoint route v1', () => { }); expect(mockResponse.ok).toBeCalled(); const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; - expect(result.host_status).toEqual(HostStatus.ERROR); + expect(result.host_status).toEqual(HostStatus.UNHEALTHY); }); - it('should return a single endpoint with status error when status is not offline, online or enrolling', async () => { + it('should return a single endpoint with status unhealthy when status is not offline, online or enrolling', async () => { const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); const mockRequest = httpServerMock.createKibanaRequest({ @@ -393,7 +393,7 @@ describe('test endpoint route v1', () => { }); expect(mockResponse.ok).toBeCalled(); const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; - expect(result.host_status).toEqual(HostStatus.ERROR); + expect(result.host_status).toEqual(HostStatus.UNHEALTHY); }); it('should throw error when endpoint agent is not active', async () => { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/agent_status.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/agent_status.test.ts index f65578f223be..ffe194ed1978 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/agent_status.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/agent_status.test.ts @@ -40,7 +40,7 @@ describe('test filtering endpoint hosts by agent status', () => { mockAgentService, mockSavedObjectClient, mockElasticsearchClient, - ['online'] + ['healthy'] ); expect(result).toBeDefined(); }); @@ -101,9 +101,9 @@ describe('test filtering endpoint hosts by agent status', () => { mockAgentService, mockSavedObjectClient, mockElasticsearchClient, - ['unenrolling', 'error'] + ['updating', 'unhealthy'] ); - const unenrollKuery = AgentStatusKueryHelper.buildKueryForUnenrollingAgents(); + const unenrollKuery = AgentStatusKueryHelper.buildKueryForUpdatingAgents(); const errorKuery = AgentStatusKueryHelper.buildKueryForErrorAgents(); expect(mockAgentService.listAgents.mock.calls[0][1].kuery).toEqual( expect.stringContaining(`${unenrollKuery} OR ${errorKuery}`) diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/agent_status.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/agent_status.ts index 8f5229804d2d..7b08dc1488e7 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/agent_status.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/agent_status.ts @@ -12,10 +12,11 @@ import { Agent } from '../../../../../../fleet/common/types/models'; import { HostStatus } from '../../../../../common/endpoint/types'; const STATUS_QUERY_MAP = new Map([ - [HostStatus.ONLINE.toString(), AgentStatusKueryHelper.buildKueryForOnlineAgents()], + [HostStatus.HEALTHY.toString(), AgentStatusKueryHelper.buildKueryForOnlineAgents()], [HostStatus.OFFLINE.toString(), AgentStatusKueryHelper.buildKueryForOfflineAgents()], - [HostStatus.ERROR.toString(), AgentStatusKueryHelper.buildKueryForErrorAgents()], - [HostStatus.UNENROLLING.toString(), AgentStatusKueryHelper.buildKueryForUnenrollingAgents()], + [HostStatus.UNHEALTHY.toString(), AgentStatusKueryHelper.buildKueryForErrorAgents()], + [HostStatus.UPDATING.toString(), AgentStatusKueryHelper.buildKueryForUpdatingAgents()], + [HostStatus.INACTIVE.toString(), AgentStatusKueryHelper.buildKueryForInactiveAgents()], ]); export async function findAgentIDsByStatus( diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts index f2a41a2fa070..9f9b24683dd1 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts @@ -32,7 +32,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ], [ 'rezzani-7.example.com', - 'Error', + 'Unhealthy', 'Default', 'Failure', 'windows 10.0', @@ -43,7 +43,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ], [ 'cadmann-4.example.com', - 'Error', + 'Unhealthy', 'Default', 'Failure', 'windows 10.0', @@ -54,7 +54,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ], [ 'thurlow-9.example.com', - 'Error', + 'Unhealthy', 'Default', 'Success', 'windows 10.0', @@ -268,7 +268,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ], [ 'cadmann-4.example.com', - 'Error', + 'Unhealthy', 'Default', 'Failure', 'windows 10.0', @@ -279,7 +279,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ], [ 'thurlow-9.example.com', - 'Error', + 'Unhealthy', 'Default', 'Success', 'windows 10.0', diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts index b171497159b0..07b046b0a95f 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts @@ -251,7 +251,7 @@ export default function ({ getService }: FtrProviderContext) { expect(Array.from(statuses)).to.eql(['failure']); }); - it('metadata api should return the endpoint based on the elastic agent id, and status should be error', async () => { + it('metadata api should return the endpoint based on the elastic agent id, and status should be unhealthy', async () => { const targetEndpointId = 'fc0ff548-feba-41b6-8367-65e8790d0eaf'; const targetElasticAgentId = '023fa40c-411d-4188-a941-4147bfadd095'; const { body } = await supertest @@ -269,7 +269,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resultHostId).to.eql(targetEndpointId); expect(resultElasticAgentId).to.eql(targetElasticAgentId); expect(body.hosts[0].metadata.event.created).to.eql(1579881969541); - expect(body.hosts[0].host_status).to.eql('error'); + expect(body.hosts[0].host_status).to.eql('unhealthy'); expect(body.hosts.length).to.eql(1); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(0); diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts index 30e65a764ee3..0e90b5c615c2 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts @@ -240,7 +240,7 @@ export default function ({ getService }: FtrProviderContext) { expect(Array.from(statuses)).to.eql(['failure']); }); - it('metadata api should return the endpoint based on the elastic agent id, and status should be error', async () => { + it('metadata api should return the endpoint based on the elastic agent id, and status should be unhealthy', async () => { const targetEndpointId = 'fc0ff548-feba-41b6-8367-65e8790d0eaf'; const targetElasticAgentId = '023fa40c-411d-4188-a941-4147bfadd095'; const { body } = await supertest @@ -258,7 +258,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resultHostId).to.eql(targetEndpointId); expect(resultElasticAgentId).to.eql(targetElasticAgentId); expect(body.hosts[0].metadata.event.created).to.eql(1579881969541); - expect(body.hosts[0].host_status).to.eql('error'); + expect(body.hosts[0].host_status).to.eql('unhealthy'); expect(body.hosts.length).to.eql(1); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(0);