Skip to content

Commit

Permalink
[Fleet] Add agent incoming data endpoint and presentational component (
Browse files Browse the repository at this point in the history
…elastic#127177)

* [Fleet] Create endpoint to check if agent has incoming data

* Document new endpoint

* Improvements to component

* Update endpoint schema

* Remove button for now

* Address review comments

* Add dynamic button functionality

* Add option to hide button and improve query

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
criamico and kibanamachine authored Mar 15, 2022
1 parent 6792a03 commit 2f876bc
Show file tree
Hide file tree
Showing 16 changed files with 406 additions and 0 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export const AGENT_API_ROUTES = {
REASSIGN_PATTERN: `${API_ROOT}/agents/{agentId}/reassign`,
BULK_REASSIGN_PATTERN: `${API_ROOT}/agents/bulk_reassign`,
STATUS_PATTERN: `${API_ROOT}/agent_status`,
DATA_PATTERN: `${API_ROOT}/agent_status/data`,
// deprecated since 8.0
STATUS_PATTERN_DEPRECATED: `${API_ROOT}/agent-status`,
UPGRADE_PATTERN: `${API_ROOT}/agents/{agentId}/upgrade`,
Expand Down
45 changes: 45 additions & 0 deletions x-pack/plugins/fleet/common/openapi/bundled.json
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,51 @@
]
}
},
"/agent_status/data": {
"get": {
"summary": "Agents - Get incoming data",
"tags": [],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"data": {
"type": "boolean"
}
}
}
}
}
}
}
}
}
}
},
"operationId": "get-agent-data",
"parameters": [
{
"schema": {
"type": "array"
},
"name": "agentsIds",
"in": "query",
"required": true
}
]
}
},
"/agents": {
"get": {
"summary": "Agents - List",
Expand Down
28 changes: 28 additions & 0 deletions x-pack/plugins/fleet/common/openapi/bundled.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,34 @@ paths:
name: kuery
in: query
required: false
/agent_status/data:
get:
summary: Agents - Get incoming data
tags: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
type: object
additionalProperties:
type: object
properties:
data:
type: boolean
operationId: get-agent-data
parameters:
- schema:
type: array
name: agentsId
in: query
required: true
/agents:
get:
summary: Agents - List
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/openapi/entrypoint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ paths:
$ref: paths/agent_status_deprecated.yaml
/agent_status:
$ref: paths/agent_status.yaml
/agent_status/data:
$ref: paths/[email protected]
/agents:
$ref: paths/agents.yaml
/agents/bulk_upgrade:
Expand Down
27 changes: 27 additions & 0 deletions x-pack/plugins/fleet/common/openapi/paths/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
get:
summary: Agents - Get incoming data
tags: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
type: object
additionalProperties:
type: object
properties:
data:
type: boolean
operationId: get-agent-data
parameters:
- schema:
type: array
name: agentsId
in: query
required: true
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/services/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export const agentRouteService = {
getBulkUpgradePath: () => AGENT_API_ROUTES.BULK_UPGRADE_PATTERN,
getListPath: () => AGENT_API_ROUTES.LIST_PATTERN,
getStatusPath: () => AGENT_API_ROUTES.STATUS_PATTERN,
getIncomingDataPath: () => AGENT_API_ROUTES.DATA_PATTERN,
getCreateActionPath: (agentId: string) =>
AGENT_API_ROUTES.ACTIONS_PATTERN.replace('{agentId}', agentId),
};
Expand Down
13 changes: 13 additions & 0 deletions x-pack/plugins/fleet/common/types/rest_spec/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,16 @@ export interface GetAgentStatusResponse {
updating: number;
};
}

export interface GetAgentIncomingDataRequest {
query: {
agentsIds: string[];
};
}

export interface IncomingDataList {
[key: string]: { data: boolean };
}
export interface GetAgentIncomingDataResponse {
items: IncomingDataList[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { EuiCallOut, EuiText, EuiSpacer, EuiButton } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import type { InstalledIntegrationPolicy } from '../../hooks';
import { useGetAgentIncomingData } from '../../hooks';
interface Props {
agentsIds: string[];
installedPolicy?: InstalledIntegrationPolicy;
}

export const ConfirmIncomingData: React.FunctionComponent<Props> = ({
agentsIds,
installedPolicy,
}) => {
const { enrolledAgents, numAgentsWithData, isLoading, linkButton } = useGetAgentIncomingData(
agentsIds,
installedPolicy
);

return (
<>
{isLoading ? (
<EuiText size="s">
{i18n.translate('xpack.fleet.confirmIncomingData.loading', {
defaultMessage:
'It may take a few minutes for data to arrive in Elasticsearch. If the system is not generating data, it may help to generate some to ensure data is being collected correctly. If you’re having trouble, see our troubleshooting guide. You may close this dialog and check later by viewing our integration assets.',
})}
</EuiText>
) : (
<>
<EuiCallOut
data-test-subj="IncomingDataConfirmedCallOut"
title={i18n.translate('xpack.fleet.confirmIncomingData.title', {
defaultMessage:
'Incoming data received from {numAgentsWithData} of {enrolledAgents} recently enrolled { enrolledAgents, plural, one {agent} other {agents}}.',
values: {
numAgentsWithData,
enrolledAgents,
},
})}
color="success"
iconType="check"
/>
<EuiSpacer size="m" />
<EuiText size="s">
{i18n.translate('xpack.fleet.confirmIncomingData.subtitle', {
defaultMessage: 'Your agent is enrolled successfully and your data is received.',
})}
</EuiText>
</>
)}

<EuiSpacer size="m" />
{installedPolicy && (
<EuiButton
href={linkButton.href}
isDisabled={isLoading}
color="primary"
fill
data-test-subj="IncomingDataConfirmedButton"
>
{linkButton.text}
</EuiButton>
)}
</>
);
};
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/public/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export * from './use_platform';
export * from './use_agent_policy_refresh';
export * from './use_package_installations';
export * from './use_agent_enrollment_flyout_data';
export * from './use_get_agent_incoming_data';
78 changes: 78 additions & 0 deletions x-pack/plugins/fleet/public/hooks/use_get_agent_incoming_data.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useEffect, useState, useMemo } from 'react';
import { i18n } from '@kbn/i18n';

import type { IncomingDataList } from '../../common/types/rest_spec/agent';

import { sendGetAgentIncomingData, useLink } from './index';

export interface InstalledIntegrationPolicy {
name: string;
version: string;
}

export const useGetAgentIncomingData = (
agentsIds: string[],
installedPolicy?: InstalledIntegrationPolicy
) => {
const [isLoading, setIsLoading] = useState<boolean>(true);
const [incomingData, setIncomingData] = useState<IncomingDataList[]>([]);

useEffect(() => {
const getIncomingData = async () => {
const { data } = await sendGetAgentIncomingData({ agentsIds });
if (data?.items) {
setIncomingData(data?.items);
setIsLoading(false);
}
};
if (agentsIds) {
getIncomingData();
}
}, [agentsIds]);

const enrolledAgents = useMemo(() => incomingData.length, [incomingData.length]);
const numAgentsWithData = useMemo(
() =>
incomingData.reduce((acc, curr) => {
const agentData = Object.values(curr)[0];
return !!agentData.data ? acc + 1 : acc;
}, 0),
[incomingData]
);
const { getAbsolutePath, getHref } = useLink();

let href;
let text;
if (!installedPolicy) {
href = '';
text = '';
}

if (installedPolicy?.name === 'apm') {
href = getAbsolutePath('/app/home#/tutorial/apm');
text = i18n.translate('xpack.fleet.confirmIncomingData.installApmAgentButtonText', {
defaultMessage: 'Install APM Agent',
});
} else {
href = getHref('integration_details_assets', {
pkgkey: `${installedPolicy?.name}-${installedPolicy?.version}`,
});
text = i18n.translate('xpack.fleet.confirmIncomingData.viewDataAssetsButtonText', {
defaultMessage: 'View assets',
});
}
const linkButton = { href, text };

return {
enrolledAgents,
numAgentsWithData,
isLoading,
linkButton,
};
};
9 changes: 9 additions & 0 deletions x-pack/plugins/fleet/public/hooks/use_request/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import type {
GetAgentsResponse,
GetAgentStatusRequest,
GetAgentStatusResponse,
GetAgentIncomingDataRequest,
GetAgentIncomingDataResponse,
PostAgentUpgradeRequest,
PostBulkAgentUpgradeRequest,
PostAgentUpgradeResponse,
Expand Down Expand Up @@ -68,6 +70,13 @@ export function useGetAgentStatus(query: GetAgentStatusRequest['query'], options
...options,
});
}
export function sendGetAgentIncomingData(query: GetAgentIncomingDataRequest['query']) {
return sendRequest<GetAgentIncomingDataResponse>({
method: 'get',
path: agentRouteService.getIncomingDataPath(),
query,
});
}

export function sendGetAgentStatus(
query: GetAgentStatusRequest['query'],
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/fleet/public/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export type {
PostBulkAgentUpgradeResponse,
GetAgentStatusRequest,
GetAgentStatusResponse,
GetAgentIncomingDataRequest,
IncomingDataList,
GetAgentIncomingDataResponse,
PutAgentReassignRequest,
PutAgentReassignResponse,
PostBulkAgentReassignRequest,
Expand Down
27 changes: 27 additions & 0 deletions x-pack/plugins/fleet/server/routes/agent/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
UpdateAgentRequestSchema,
DeleteAgentRequestSchema,
GetAgentStatusRequestSchema,
GetAgentDataRequestSchema,
PutAgentReassignRequestSchema,
PostBulkAgentReassignRequestSchema,
} from '../../types';
Expand Down Expand Up @@ -218,3 +219,29 @@ export const getAgentStatusForAgentPolicyHandler: RequestHandler<
return defaultIngestErrorHandler({ error, response });
}
};

export const getAgentDataHandler: RequestHandler<
undefined,
TypeOf<typeof GetAgentDataRequestSchema.query>
> = async (context, request, response) => {
const esClient = context.core.elasticsearch.client.asCurrentUser;
try {
let items;

if (isStringArray(request.query.agentsIds)) {
items = await AgentService.getIncomingDataByAgentsId(esClient, request.query.agentsIds);
} else {
items = await AgentService.getIncomingDataByAgentsId(esClient, [request.query.agentsIds]);
}

const body = { items };

return response.ok({ body });
} catch (error) {
return defaultIngestErrorHandler({ error, response });
}
};

function isStringArray(arr: unknown | string[]): arr is string[] {
return Array.isArray(arr) && arr.every((p) => typeof p === 'string');
}
Loading

0 comments on commit 2f876bc

Please sign in to comment.