Skip to content

Commit

Permalink
[Fleet] Show reason for agent/endpoint uninstall (elastic#205815)
Browse files Browse the repository at this point in the history
## Summary

Closes elastic#197731 

- Using the new `audit_unenroll_reason`, added `Orphaned` and
`Uninstalled` Badges to the table UI to make those entries distinct from
the normal `offline` entries
- Added conditional rendering on the labels at the top of the table to
only show up when the matches are greater than zero
- Updated `offline` counts to be distinct from the `orphaned` and
`uninstalled` items in those labels
- Added Orphaned and Uninstalled filters to status filter dropdown

Screenshot of new: 

![image](https://github.com/user-attachments/assets/9126f50d-03e4-4a67-9a20-b5b358478054)


### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

### Identify risks

n/a


## Release Note
Improves filtering & visibility of `Uninstalled` and `Orphaned` Agents
in Fleet, by differentiating them from `Offline` agents. Status filters
have been added for both `Uninstalled` and `Orphaned` agents. Agent
`status` runtime field has been updated to return accordingly when an
agent is `uninstalled` or `orphaned`. Additionally, improved UI by
hiding agent labels with `0` agent matches.

---------

Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
3 people authored Jan 14, 2025
1 parent 87d349b commit 5803366
Show file tree
Hide file tree
Showing 25 changed files with 235 additions and 44 deletions.
18 changes: 15 additions & 3 deletions oas_docs/bundle.json
Original file line number Diff line number Diff line change
Expand Up @@ -15406,12 +15406,18 @@
"online": {
"type": "number"
},
"orphaned": {
"type": "number"
},
"other": {
"type": "number"
},
"unenrolled": {
"type": "number"
},
"uninstalled": {
"type": "number"
},
"updating": {
"type": "number"
}
Expand Down Expand Up @@ -15946,7 +15952,9 @@
"unenrolling",
"unenrolled",
"updating",
"degraded"
"degraded",
"uninstalled",
"orphaned"
],
"type": "string"
},
Expand Down Expand Up @@ -17959,7 +17967,9 @@
"unenrolling",
"unenrolled",
"updating",
"degraded"
"degraded",
"uninstalled",
"orphaned"
],
"type": "string"
},
Expand Down Expand Up @@ -18439,7 +18449,9 @@
"unenrolling",
"unenrolled",
"updating",
"degraded"
"degraded",
"uninstalled",
"orphaned"
],
"type": "string"
},
Expand Down
18 changes: 15 additions & 3 deletions oas_docs/bundle.serverless.json
Original file line number Diff line number Diff line change
Expand Up @@ -15406,12 +15406,18 @@
"online": {
"type": "number"
},
"orphaned": {
"type": "number"
},
"other": {
"type": "number"
},
"unenrolled": {
"type": "number"
},
"uninstalled": {
"type": "number"
},
"updating": {
"type": "number"
}
Expand Down Expand Up @@ -15946,7 +15952,9 @@
"unenrolling",
"unenrolled",
"updating",
"degraded"
"degraded",
"uninstalled",
"orphaned"
],
"type": "string"
},
Expand Down Expand Up @@ -17959,7 +17967,9 @@
"unenrolling",
"unenrolled",
"updating",
"degraded"
"degraded",
"uninstalled",
"orphaned"
],
"type": "string"
},
Expand Down Expand Up @@ -18439,7 +18449,9 @@
"unenrolling",
"unenrolled",
"updating",
"degraded"
"degraded",
"uninstalled",
"orphaned"
],
"type": "string"
},
Expand Down
10 changes: 10 additions & 0 deletions oas_docs/output/kibana.serverless.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15901,10 +15901,14 @@ paths:
type: number
online:
type: number
orphaned:
type: number
other:
type: number
unenrolled:
type: number
uninstalled:
type: number
updating:
type: number
required:
Expand Down Expand Up @@ -16270,6 +16274,8 @@ paths:
- unenrolled
- updating
- degraded
- uninstalled
- orphaned
type: string
tags:
items:
Expand Down Expand Up @@ -16717,6 +16723,8 @@ paths:
- unenrolled
- updating
- degraded
- uninstalled
- orphaned
type: string
tags:
items:
Expand Down Expand Up @@ -17056,6 +17064,8 @@ paths:
- unenrolled
- updating
- degraded
- uninstalled
- orphaned
type: string
tags:
items:
Expand Down
10 changes: 10 additions & 0 deletions oas_docs/output/kibana.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18031,10 +18031,14 @@ paths:
type: number
online:
type: number
orphaned:
type: number
other:
type: number
unenrolled:
type: number
uninstalled:
type: number
updating:
type: number
required:
Expand Down Expand Up @@ -18398,6 +18402,8 @@ paths:
- unenrolled
- updating
- degraded
- uninstalled
- orphaned
type: string
tags:
items:
Expand Down Expand Up @@ -18842,6 +18848,8 @@ paths:
- unenrolled
- updating
- degraded
- uninstalled
- orphaned
type: string
tags:
items:
Expand Down Expand Up @@ -19180,6 +19188,8 @@ paths:
- unenrolled
- updating
- degraded
- uninstalled
- orphaned
type: string
tags:
items:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export const AgentStatuses = [
'unenrolled',
'updating',
'degraded',
'uninstalled',
'orphaned',
] as const;

// Kueries for finding unprivileged and privileged agents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export function getPreviousAgentStatusForOfflineAgents(
export function buildKueryForUnenrolledAgents(): string {
return 'status:unenrolled';
}
export function buildKueryForUninstalledAgents(): string {
return 'status:uninstalled';
}
export function buildKueryForOrphanedAgents(): string {
return 'status:orphaned';
}

export function buildKueryForOnlineAgents(): string {
return 'status:online';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ describe('agentStatusesToSummary', () => {
enrolling: 7,
unenrolling: 8,
unenrolled: 9,
orphaned: 0,
uninstalled: 0,
})
).toEqual({
healthy: 1,
unhealthy: 5,
orphaned: 0,
inactive: 4,
offline: 5,
updating: 21,
unenrolled: 9,
uninstalled: 0,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ export function agentStatusesToSummary(
offline: statuses.offline,
updating: statuses.updating + statuses.enrolling + statuses.unenrolling,
unenrolled: statuses.unenrolled,
orphaned: statuses.orphaned,
uninstalled: statuses.uninstalled,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ export type AgentStatus = AgentStatusTuple[number];
export type SimplifiedAgentStatus =
| 'healthy'
| 'unhealthy'
| 'orphaned'
| 'updating'
| 'offline'
| 'inactive'
| 'unenrolled';
| 'unenrolled'
| 'uninstalled';

export type AgentActionType =
| 'UNENROLL'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ describe('View agents list', () => {
updating: 0,
other: 0,
events: 0,
orphaned: 0,
uninstalled: 0,
});
cy.intercept('GET', /\/api\/fleet\/agents/).as('getAgents');
});
Expand Down Expand Up @@ -210,10 +212,11 @@ describe('View agents list', () => {
cy.get('li').contains('Unhealthy').click();
cy.get('li').contains('Updating').click();
cy.get('li').contains('Offline').click();
cy.get('li').contains('Orphaned').click();
cy.getBySel(FLEET_AGENT_LIST_PAGE.STATUS_FILTER).click();
cy.wait('@getAgents');
};
it('should filter on healthy (16 result)', () => {
it('should filter on healthy (18 results)', () => {
cy.visit('/app/fleet/agents');
clearFilters();
cy.getBySel(FLEET_AGENT_LIST_PAGE.STATUS_FILTER).click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ const statusFilters = [
defaultMessage: 'Unhealthy',
}),
},
{
status: 'orphaned',
label: i18n.translate('xpack.fleet.agentList.statusOrphanedFilterText', {
defaultMessage: 'Orphaned',
}),
},
{
status: 'updating',
label: i18n.translate('xpack.fleet.agentList.statusUpdatingFilterText', {
Expand All @@ -63,6 +69,12 @@ const statusFilters = [
defaultMessage: 'Unenrolled',
}),
},
{
status: 'uninstalled',
label: i18n.translate('xpack.fleet.agentList.statusUninstalledFilterText', {
defaultMessage: 'Uninstalled',
}),
},
];

const LeftpaddedNotificationBadge = styled(EuiNotificationBadge)`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,13 @@ describe('useFetchAgentsData', () => {
const { result } = renderer.renderHook(() => useFetchAgentsData());
await waitFor(() => new Promise((resolve) => resolve(null)));

expect(result?.current.selectedStatus).toEqual(['healthy', 'unhealthy', 'updating', 'offline']);
expect(result?.current.selectedStatus).toEqual([
'healthy',
'unhealthy',
'orphaned',
'updating',
'offline',
]);
expect(result?.current.allAgentPolicies).toEqual([
{
id: 'agent-policy-1',
Expand All @@ -144,7 +150,7 @@ describe('useFetchAgentsData', () => {
},
});
expect(result?.current.kuery).toEqual(
'status:online or (status:error or status:degraded) or (status:updating or status:unenrolling or status:enrolling) or status:offline'
'status:online or (status:error or status:degraded) or status:orphaned or (status:updating or status:unenrolling or status:enrolling) or status:offline'
);
expect(result?.current.currentRequestRef).toEqual({ current: 2 });
expect(result?.current.pagination).toEqual({ currentPage: 1, pageSize: 5 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export function useFetchAgentsData() {
const [selectedStatus, setSelectedStatus] = useState<string[]>([
'healthy',
'unhealthy',
'orphaned',
'updating',
'offline',
...(urlHasInactive ? ['inactive'] : []),
Expand Down Expand Up @@ -235,7 +236,6 @@ export function useFetchAgentsData() {
perPage: MAX_AGENT_ACTIONS,
}),
]);

// Return if a newer request has been triggered
if (currentRequestRef.current !== currentRequest) {
return;
Expand Down Expand Up @@ -263,6 +263,7 @@ export function useFetchAgentsData() {
}

const statusSummary = agentsResponse.data.statusSummary;

if (!statusSummary) {
throw new Error('Invalid GET /agents response - no status summary');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,17 @@ export const getKuery = ({
return AgentStatusKueryHelper.buildKueryForInactiveAgents();
case 'unenrolled':
return AgentStatusKueryHelper.buildKueryForUnenrolledAgents();
case 'orphaned':
return AgentStatusKueryHelper.buildKueryForOrphanedAgents();
case 'uninstalled':
return AgentStatusKueryHelper.buildKueryForUninstalledAgents();
}

return undefined;
})

.filter((statusKuery) => statusKuery !== undefined)
.join(' or ');

if (kueryBuilder) {
kueryBuilder = `(${kueryBuilder}) and (${kueryStatus})`;
} else {
Expand Down
Loading

0 comments on commit 5803366

Please sign in to comment.