Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions oas_docs/bundle.json
Original file line number Diff line number Diff line change
Expand Up @@ -16266,6 +16266,12 @@
"agents": {
"type": "number"
},
"failedUpgradeActionIds": {
"items": {
"type": "string"
},
"type": "array"
},
"failedUpgradeAgents": {
"type": "number"
},
Expand Down
6 changes: 6 additions & 0 deletions oas_docs/bundle.serverless.json
Original file line number Diff line number Diff line change
Expand Up @@ -16266,6 +16266,12 @@
"agents": {
"type": "number"
},
"failedUpgradeActionIds": {
"items": {
"type": "string"
},
"type": "array"
},
"failedUpgradeAgents": {
"type": "number"
},
Expand Down
4 changes: 4 additions & 0 deletions oas_docs/output/kibana.serverless.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23291,6 +23291,10 @@ paths:
properties:
agents:
type: number
failedUpgradeActionIds:
items:
type: string
type: array
failedUpgradeAgents:
type: number
version:
Expand Down
4 changes: 4 additions & 0 deletions oas_docs/output/kibana.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27035,6 +27035,10 @@ paths:
properties:
agents:
type: number
failedUpgradeActionIds:
items:
type: string
type: array
failedUpgradeAgents:
type: number
version:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface CurrentVersionCount {
version: string;
agents: number;
failedUpgradeAgents: number;
failedUpgradeActionIds?: string[];
}

export interface GetAutoUpgradeAgentsStatusResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,23 @@ export const StatusColumn: React.FunctionComponent<{
const { data: autoUpgradeAgentsStatus } = useGetAutoUpgradeAgentsStatusQuery(agentPolicyId);
const getAgentsHref = useCallback(
(failed?: boolean): string => {
const currentVersionAgentStatus = autoUpgradeAgentsStatus?.currentVersions.find(
(value) => value.version === version
);
const kuery = failed
? `policy_id:"${agentPolicyId}" AND upgrade_details.state:"UPG_FAILED" AND upgrade_details.target_version:"${version}"`
? `policy_id:"${agentPolicyId}" AND upgrade_details.state:"UPG_FAILED" AND upgrade_details.target_version:"${version}"${
currentVersionAgentStatus && currentVersionAgentStatus.failedUpgradeActionIds?.length
? ` AND (${currentVersionAgentStatus.failedUpgradeActionIds
.map((id) => `upgrade_details.action_id:"${id}"`)
.join(' OR ')})`
: ''
}`
: `policy_id:"${agentPolicyId}" AND agent.version:"${version}"`;
return getHref('agent_list', {
kuery: encodeURIComponent(kuery),
});
},
[getHref, agentPolicyId, version]
[getHref, agentPolicyId, version, autoUpgradeAgentsStatus]
);

const calcPercentage = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,31 @@
* 2.0.
*/

import { createAppContextStartContractMock } from '../../mocks';
import { appContextService } from '../app_context';

import { getAgentActions } from './actions';

import { getAutoUpgradeAgentsStatus } from './auto_upgrade_agents_status';

jest.mock('./actions');

describe('getAutoUpgradeAgentsStatus', () => {
beforeEach(() => {
appContextService.start(createAppContextStartContractMock());
jest.mocked(getAgentActions).mockImplementation(async (_: any, actionId: string) => {
if (actionId === 'action-1') {
return [{ id: 'action-1', is_automatic: true }];
} else {
return [{ id: 'action-2', is_automatic: false }];
}
});
});
it('should kuery with active agents filter when listing agents', async () => {
const agentClient = {
listAgents: jest.fn().mockResolvedValue({
aggregations: {
versions: {
action_id_versions: {
buckets: [],
},
},
Expand All @@ -35,4 +52,51 @@ describe('getAutoUpgradeAgentsStatus', () => {
})
);
});

it('should return only failed agents from automatic upgrade actions', async () => {
const agentClient = {
listAgents: jest
.fn()
.mockResolvedValueOnce({
total: 5,
})
.mockResolvedValueOnce({
aggregations: {
action_id_versions: {
buckets: [
{
key: ['1.0.0', 'action-1'],
doc_count: 10,
},
{
key: ['1.0.0', 'action-2'],
doc_count: 5,
},
],
},
},
total: 15,
}),
} as any;

const agentPolicyId = 'test-policy-id';

const res = await getAutoUpgradeAgentsStatus(agentClient, agentPolicyId);

expect(res).toMatchInlineSnapshot(`
Object {
"currentVersions": Array [
Object {
"agents": 0,
"failedUpgradeActionIds": Array [
"action-1",
],
"failedUpgradeAgents": 10,
"version": "1.0.0",
},
],
"totalAgents": 5,
}
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
* 2.0.
*/

import pMap from 'p-map';

import { AGENTS_PREFIX } from '../../../common';
import { AgentStatusKueryHelper } from '../../../common/services';
import type {
CurrentVersionCount,
GetAutoUpgradeAgentsStatusResponse,
} from '../../../common/types/rest_spec/agent_policy';
import { appContextService } from '../app_context';
import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants';

import { getAgentActions } from './actions';
import type { AgentClient } from './agent_service';

export async function getAutoUpgradeAgentsStatus(
Expand Down Expand Up @@ -55,22 +60,61 @@ export async function getAutoUpgradeAgentsStatus(
perPage: 0,
kuery: `${AgentStatusKueryHelper.buildKueryForActiveAgents()} AND ${AGENTS_PREFIX}.policy_id:"${agentPolicyId}" AND ${AGENTS_PREFIX}.upgrade_details.state:"UPG_FAILED"`,
aggregations: {
versions: {
terms: {
field: 'upgrade_details.target_version.keyword',
action_id_versions: {
multi_terms: {
terms: [
{
field: 'upgrade_details.target_version.keyword',
},
{
field: 'upgrade_details.action_id',
},
],
size: 1000,
},
},
},
})
.then((result) => {
(result.aggregations?.versions as any)?.buckets.forEach(
(bucket: { key: string; doc_count: number }) =>
(currentVersionsMap[bucket.key] = {
version: bucket.key,
agents: currentVersionsMap[bucket.key]?.agents ?? 0,
failedUpgradeAgents: bucket.doc_count,
})
.then(async (result) => {
if (!result.aggregations?.action_id_versions) {
return;
}

const actionCacheIsAutomatic = new Map<string, boolean>();

await pMap(
(result.aggregations.action_id_versions as any)?.buckets ?? [],
async (bucket: { key: string[]; doc_count: number }) => {
const version = bucket.key[0];
const actionId = bucket.key[1];

let isAutomatic = actionCacheIsAutomatic.get(actionId);
if (isAutomatic === undefined) {
const actions = await getAgentActions(
appContextService.getInternalUserESClient(),
actionId
);
isAutomatic = actions?.some((action) => action.is_automatic) ?? false;
actionCacheIsAutomatic.set(actionId, isAutomatic);
}

if (isAutomatic) {
if (!currentVersionsMap[version]) {
currentVersionsMap[version] = {
version,
agents: 0,
failedUpgradeAgents: 0,
};
}

currentVersionsMap[version].failedUpgradeAgents += bucket.doc_count;
if (!currentVersionsMap[version].failedUpgradeActionIds) {
currentVersionsMap[version].failedUpgradeActionIds = [];
}
currentVersionsMap[version].failedUpgradeActionIds!.push(actionId);
}
},
{ concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 }
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ export const GetAutoUpgradeAgentsStatusResponseSchema = schema.object({
version: schema.string(),
agents: schema.number(),
failedUpgradeAgents: schema.number(),
failedUpgradeActionIds: schema.maybe(schema.arrayOf(schema.string())),
})
),
totalAgents: schema.number(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2143,6 +2143,7 @@ export default function (providerContext: FtrProviderContext) {
await generateAgent(providerContext, 'healhty', 'agent-2', policyWithAgents.id, '8.16.1', {
state: 'UPG_FAILED',
target_version: '8.16.3',
action_id: 'test-action-automatic',
});
await generateAgent(
providerContext,
Expand All @@ -2151,6 +2152,20 @@ export default function (providerContext: FtrProviderContext) {
policyWithAgents.id,
'8.16.1'
);
await es.index({
index: '.fleet-actions',
refresh: 'wait_for',
body: {
'@timestamp': new Date().toISOString(),
expiration: new Date().toISOString(),
agents: ['agent-2'],
action_id: 'test-action-automatic',
data: {},
is_automatic: true,
type: 'UPGRADE',
},
});

const { body } = await supertest
.get(`/api/fleet/agent_policies/${policyWithAgents.id}/auto_upgrade_agents_status`)
.set('kbn-xsrf', 'xxx')
Expand All @@ -2167,6 +2182,7 @@ export default function (providerContext: FtrProviderContext) {
agents: 0,
failedUpgradeAgents: 1,
version: '8.16.3',
failedUpgradeActionIds: ['test-action-automatic'],
},
],
totalAgents: 2,
Expand Down
Loading