Skip to content

Commit 9a932c0

Browse files
authored
[Fleet] Filter non automatic upgrade failed from automatic upgrade status (#240328)
1 parent 8bb3ebc commit 9a932c0

File tree

10 files changed

+169
-14
lines changed

10 files changed

+169
-14
lines changed

oas_docs/bundle.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16266,6 +16266,12 @@
1626616266
"agents": {
1626716267
"type": "number"
1626816268
},
16269+
"failedUpgradeActionIds": {
16270+
"items": {
16271+
"type": "string"
16272+
},
16273+
"type": "array"
16274+
},
1626916275
"failedUpgradeAgents": {
1627016276
"type": "number"
1627116277
},

oas_docs/bundle.serverless.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16266,6 +16266,12 @@
1626616266
"agents": {
1626716267
"type": "number"
1626816268
},
16269+
"failedUpgradeActionIds": {
16270+
"items": {
16271+
"type": "string"
16272+
},
16273+
"type": "array"
16274+
},
1626916275
"failedUpgradeAgents": {
1627016276
"type": "number"
1627116277
},

oas_docs/output/kibana.serverless.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23291,6 +23291,10 @@ paths:
2329123291
properties:
2329223292
agents:
2329323293
type: number
23294+
failedUpgradeActionIds:
23295+
items:
23296+
type: string
23297+
type: array
2329423298
failedUpgradeAgents:
2329523299
type: number
2329623300
version:

oas_docs/output/kibana.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27035,6 +27035,10 @@ paths:
2703527035
properties:
2703627036
agents:
2703727037
type: number
27038+
failedUpgradeActionIds:
27039+
items:
27040+
type: string
27041+
type: array
2703827042
failedUpgradeAgents:
2703927043
type: number
2704027044
version:

x-pack/platform/plugins/shared/fleet/common/types/rest_spec/agent_policy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface CurrentVersionCount {
4141
version: string;
4242
agents: number;
4343
failedUpgradeAgents: number;
44+
failedUpgradeActionIds?: string[];
4445
}
4546

4647
export interface GetAutoUpgradeAgentsStatusResponse {

x-pack/platform/plugins/shared/fleet/public/applications/fleet/sections/agents/components/manage_auto_upgrade_agents_modal/status_column.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,23 @@ export const StatusColumn: React.FunctionComponent<{
2727
const { data: autoUpgradeAgentsStatus } = useGetAutoUpgradeAgentsStatusQuery(agentPolicyId);
2828
const getAgentsHref = useCallback(
2929
(failed?: boolean): string => {
30+
const currentVersionAgentStatus = autoUpgradeAgentsStatus?.currentVersions.find(
31+
(value) => value.version === version
32+
);
3033
const kuery = failed
31-
? `policy_id:"${agentPolicyId}" AND upgrade_details.state:"UPG_FAILED" AND upgrade_details.target_version:"${version}"`
34+
? `policy_id:"${agentPolicyId}" AND upgrade_details.state:"UPG_FAILED" AND upgrade_details.target_version:"${version}"${
35+
currentVersionAgentStatus && currentVersionAgentStatus.failedUpgradeActionIds?.length
36+
? ` AND (${currentVersionAgentStatus.failedUpgradeActionIds
37+
.map((id) => `upgrade_details.action_id:"${id}"`)
38+
.join(' OR ')})`
39+
: ''
40+
}`
3241
: `policy_id:"${agentPolicyId}" AND agent.version:"${version}"`;
3342
return getHref('agent_list', {
3443
kuery: encodeURIComponent(kuery),
3544
});
3645
},
37-
[getHref, agentPolicyId, version]
46+
[getHref, agentPolicyId, version, autoUpgradeAgentsStatus]
3847
);
3948

4049
const calcPercentage = useCallback(

x-pack/platform/plugins/shared/fleet/server/services/agents/auto_upgrade_agents_status.test.ts

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,31 @@
55
* 2.0.
66
*/
77

8+
import { createAppContextStartContractMock } from '../../mocks';
9+
import { appContextService } from '../app_context';
10+
11+
import { getAgentActions } from './actions';
12+
813
import { getAutoUpgradeAgentsStatus } from './auto_upgrade_agents_status';
914

15+
jest.mock('./actions');
16+
1017
describe('getAutoUpgradeAgentsStatus', () => {
18+
beforeEach(() => {
19+
appContextService.start(createAppContextStartContractMock());
20+
jest.mocked(getAgentActions).mockImplementation(async (_: any, actionId: string) => {
21+
if (actionId === 'action-1') {
22+
return [{ id: 'action-1', is_automatic: true }];
23+
} else {
24+
return [{ id: 'action-2', is_automatic: false }];
25+
}
26+
});
27+
});
1128
it('should kuery with active agents filter when listing agents', async () => {
1229
const agentClient = {
1330
listAgents: jest.fn().mockResolvedValue({
1431
aggregations: {
15-
versions: {
32+
action_id_versions: {
1633
buckets: [],
1734
},
1835
},
@@ -35,4 +52,51 @@ describe('getAutoUpgradeAgentsStatus', () => {
3552
})
3653
);
3754
});
55+
56+
it('should return only failed agents from automatic upgrade actions', async () => {
57+
const agentClient = {
58+
listAgents: jest
59+
.fn()
60+
.mockResolvedValueOnce({
61+
total: 5,
62+
})
63+
.mockResolvedValueOnce({
64+
aggregations: {
65+
action_id_versions: {
66+
buckets: [
67+
{
68+
key: ['1.0.0', 'action-1'],
69+
doc_count: 10,
70+
},
71+
{
72+
key: ['1.0.0', 'action-2'],
73+
doc_count: 5,
74+
},
75+
],
76+
},
77+
},
78+
total: 15,
79+
}),
80+
} as any;
81+
82+
const agentPolicyId = 'test-policy-id';
83+
84+
const res = await getAutoUpgradeAgentsStatus(agentClient, agentPolicyId);
85+
86+
expect(res).toMatchInlineSnapshot(`
87+
Object {
88+
"currentVersions": Array [
89+
Object {
90+
"agents": 0,
91+
"failedUpgradeActionIds": Array [
92+
"action-1",
93+
],
94+
"failedUpgradeAgents": 10,
95+
"version": "1.0.0",
96+
},
97+
],
98+
"totalAgents": 5,
99+
}
100+
`);
101+
});
38102
});

x-pack/platform/plugins/shared/fleet/server/services/agents/auto_upgrade_agents_status.ts

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@
55
* 2.0.
66
*/
77

8+
import pMap from 'p-map';
9+
810
import { AGENTS_PREFIX } from '../../../common';
911
import { AgentStatusKueryHelper } from '../../../common/services';
1012
import type {
1113
CurrentVersionCount,
1214
GetAutoUpgradeAgentsStatusResponse,
1315
} from '../../../common/types/rest_spec/agent_policy';
16+
import { appContextService } from '../app_context';
17+
import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants';
1418

19+
import { getAgentActions } from './actions';
1520
import type { AgentClient } from './agent_service';
1621

1722
export async function getAutoUpgradeAgentsStatus(
@@ -55,22 +60,61 @@ export async function getAutoUpgradeAgentsStatus(
5560
perPage: 0,
5661
kuery: `${AgentStatusKueryHelper.buildKueryForActiveAgents()} AND ${AGENTS_PREFIX}.policy_id:"${agentPolicyId}" AND ${AGENTS_PREFIX}.upgrade_details.state:"UPG_FAILED"`,
5762
aggregations: {
58-
versions: {
59-
terms: {
60-
field: 'upgrade_details.target_version.keyword',
63+
action_id_versions: {
64+
multi_terms: {
65+
terms: [
66+
{
67+
field: 'upgrade_details.target_version.keyword',
68+
},
69+
{
70+
field: 'upgrade_details.action_id',
71+
},
72+
],
6173
size: 1000,
6274
},
6375
},
6476
},
6577
})
66-
.then((result) => {
67-
(result.aggregations?.versions as any)?.buckets.forEach(
68-
(bucket: { key: string; doc_count: number }) =>
69-
(currentVersionsMap[bucket.key] = {
70-
version: bucket.key,
71-
agents: currentVersionsMap[bucket.key]?.agents ?? 0,
72-
failedUpgradeAgents: bucket.doc_count,
73-
})
78+
.then(async (result) => {
79+
if (!result.aggregations?.action_id_versions) {
80+
return;
81+
}
82+
83+
const actionCacheIsAutomatic = new Map<string, boolean>();
84+
85+
await pMap(
86+
(result.aggregations.action_id_versions as any)?.buckets ?? [],
87+
async (bucket: { key: string[]; doc_count: number }) => {
88+
const version = bucket.key[0];
89+
const actionId = bucket.key[1];
90+
91+
let isAutomatic = actionCacheIsAutomatic.get(actionId);
92+
if (isAutomatic === undefined) {
93+
const actions = await getAgentActions(
94+
appContextService.getInternalUserESClient(),
95+
actionId
96+
);
97+
isAutomatic = actions?.some((action) => action.is_automatic) ?? false;
98+
actionCacheIsAutomatic.set(actionId, isAutomatic);
99+
}
100+
101+
if (isAutomatic) {
102+
if (!currentVersionsMap[version]) {
103+
currentVersionsMap[version] = {
104+
version,
105+
agents: 0,
106+
failedUpgradeAgents: 0,
107+
};
108+
}
109+
110+
currentVersionsMap[version].failedUpgradeAgents += bucket.doc_count;
111+
if (!currentVersionsMap[version].failedUpgradeActionIds) {
112+
currentVersionsMap[version].failedUpgradeActionIds = [];
113+
}
114+
currentVersionsMap[version].failedUpgradeActionIds!.push(actionId);
115+
}
116+
},
117+
{ concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 }
74118
);
75119
});
76120

x-pack/platform/plugins/shared/fleet/server/types/models/agent_policy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ export const GetAutoUpgradeAgentsStatusResponseSchema = schema.object({
337337
version: schema.string(),
338338
agents: schema.number(),
339339
failedUpgradeAgents: schema.number(),
340+
failedUpgradeActionIds: schema.maybe(schema.arrayOf(schema.string())),
340341
})
341342
),
342343
totalAgents: schema.number(),

x-pack/platform/test/fleet_api_integration/apis/agent_policy/agent_policy.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,6 +2143,7 @@ export default function (providerContext: FtrProviderContext) {
21432143
await generateAgent(providerContext, 'healhty', 'agent-2', policyWithAgents.id, '8.16.1', {
21442144
state: 'UPG_FAILED',
21452145
target_version: '8.16.3',
2146+
action_id: 'test-action-automatic',
21462147
});
21472148
await generateAgent(
21482149
providerContext,
@@ -2151,6 +2152,20 @@ export default function (providerContext: FtrProviderContext) {
21512152
policyWithAgents.id,
21522153
'8.16.1'
21532154
);
2155+
await es.index({
2156+
index: '.fleet-actions',
2157+
refresh: 'wait_for',
2158+
body: {
2159+
'@timestamp': new Date().toISOString(),
2160+
expiration: new Date().toISOString(),
2161+
agents: ['agent-2'],
2162+
action_id: 'test-action-automatic',
2163+
data: {},
2164+
is_automatic: true,
2165+
type: 'UPGRADE',
2166+
},
2167+
});
2168+
21542169
const { body } = await supertest
21552170
.get(`/api/fleet/agent_policies/${policyWithAgents.id}/auto_upgrade_agents_status`)
21562171
.set('kbn-xsrf', 'xxx')
@@ -2167,6 +2182,7 @@ export default function (providerContext: FtrProviderContext) {
21672182
agents: 0,
21682183
failedUpgradeAgents: 1,
21692184
version: '8.16.3',
2185+
failedUpgradeActionIds: ['test-action-automatic'],
21702186
},
21712187
],
21722188
totalAgents: 2,

0 commit comments

Comments
 (0)