Skip to content

Commit

Permalink
[Fleet] Show warning when download upgrade is failing (#173844)
Browse files Browse the repository at this point in the history
Fixes #173370
Closes #171941

## Summary
Show a warning when download upgrade is failing.

This PR addresses a specific case of `upgrade downloading`: when the
upgrade started but it's failing with an error. In this case, since
8.12, the agent metadata have a `retry_msg` that can be used to
distinguish this case from the regular upgrade.
I'm also fixing one smaller bug that I introduced with
#173253, the tooltip shown in the
case when the agent is not upgradeable was hiding the badge, so I'm
moving the if as the last one in the function.

## Testing
- Have an 8.12 agent installed with Multipass (it needs to be
upgradeable)
- Change the download binary url to something broken: `sourceURI:
https://artifacts.elastic.co/notdownloads/`
- Force upgrade from dev tools:
```
POST kbn:/api/fleet/agents/c3f09103-4e69-4a36-bee2-84223bedef36/upgrade
{
  "version": "8.12.0",
  "force": true
}
```
- Go to agent overview, the badge will show "upgrading" but will also
have a warning icon with a tooltip, showing the retry message and the
`retry_until` time in humanized format (retry until...remaining):
![Screenshot 2024-01-02 at 16 54
20](https://github.com/elastic/kibana/assets/16084106/ac340e7d-5151-4e4e-b6a6-731a113ff984)

This way the message shows the values present in the agent metadata.

- Same is reported in the agent list table:
![Screenshot 2024-01-02 at 16 54
28](https://github.com/elastic/kibana/assets/16084106/1f8823c4-9e5c-4f4c-9cdc-2839b16214bb)


- After a while the retries will be finished and the agent will show the
regular "upgrade failed" badge (this was already implemented):
![Screenshot 2023-12-21 at 12 07
27](https://github.com/elastic/kibana/assets/16084106/c1d5bf67-a4fd-4b04-aa8d-24dc8d4af54e)



### Checklist
- [ ] [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

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
criamico and kibanamachine authored Jan 2, 2024
1 parent 5f40efb commit 1de5cde
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 22 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/types/models/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,5 +449,7 @@ export interface AgentUpgradeDetails {
download_rate?: number; // bytes per second
failed_state?: AgentUpgradeStateType;
error_msg?: string;
retry_error_msg?: string;
retry_until?: string;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react';

import type { Agent, AgentPolicy } from '../../../../../types';
import { useAgentVersion } from '../../../../../hooks';
import { ExperimentalFeaturesService, isAgentUpgradeable } from '../../../../../services';
import {
ExperimentalFeaturesService,
isAgentUpgradeable,
getNotUpgradeableMessage,
} from '../../../../../services';
import { AgentPolicySummaryLine } from '../../../../../components';
import { AgentHealth } from '../../../components';
import { Tags } from '../../../components/tags';
Expand Down Expand Up @@ -186,6 +190,7 @@ export const AgentDetailsOverviewSection: React.FunctionComponent<{
agentUpgradeStartedAt={agent.upgrade_started_at}
agentUpgradedAt={agent.upgraded_at}
agentUpgradeDetails={agent.upgrade_details}
notUpgradeableMessage={getNotUpgradeableMessage(agent, latestAgentVersion)}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { fireEvent, waitFor } from '@testing-library/react';
import React from 'react';
import moment from 'moment';

import { createFleetTestRendererMock } from '../../../../../../mock';

Expand Down Expand Up @@ -176,6 +177,69 @@ describe('AgentUpgradeStatus', () => {
await expectTooltip(results, 'Downloading the new agent artifact version (16.4%).');
});

it('should render UPG_DOWNLOADING with a warning if agent has a retry_message and retry_until', async () => {
const results = render({
agentUpgradeDetails: {
target_version: 'XXX',
action_id: 'xxx',
state: 'UPG_DOWNLOADING',
metadata: {
download_percent: 16.4,
retry_error_msg: 'unable to download',
retry_until: `${moment().add(10, 'minutes').toISOString()}`,
},
},
});

expectUpgradeStatusBadgeLabel(results, 'Upgrade downloading');
fireEvent.mouseOver(results.getByText('Info'));
await waitFor(() => {
const tooltip = results.getByRole('tooltip');
expect(tooltip).toHaveTextContent('Upgrade failing: unable to download. Retrying until:');
expect(tooltip).toHaveTextContent('(00:09 remaining)');
});
});

it('should not render retry_until if the remaining time is negative', async () => {
const results = render({
agentUpgradeDetails: {
target_version: 'XXX',
action_id: 'xxx',
state: 'UPG_DOWNLOADING',
metadata: {
download_percent: 16.4,
retry_error_msg: 'unable to download',
retry_until: `${moment().subtract(10, 'minutes').toISOString()}`,
},
},
});

expectUpgradeStatusBadgeLabel(results, 'Upgrade downloading');
fireEvent.mouseOver(results.getByText('Info'));
await waitFor(() => {
const tooltip = results.getByRole('tooltip');
expect(tooltip).toHaveTextContent('Upgrade failing: unable to download.');
expect(tooltip).not.toHaveTextContent('remaining');
});
});

it('should render UPG_DOWNLOADING with a warning if agent has a retry_message', async () => {
const results = render({
agentUpgradeDetails: {
target_version: 'XXX',
action_id: 'xxx',
state: 'UPG_DOWNLOADING',
metadata: {
download_percent: 16.4,
retry_error_msg: 'unable to download',
},
},
});

expectUpgradeStatusBadgeLabel(results, 'Upgrade downloading');
await expectTooltip(results, 'Upgrade failing: unable to download.');
});

it('should render UPG_EXTRACTING state correctly', async () => {
const results = render({
agentUpgradeDetails: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import React, { useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui';
import moment from 'moment';

import type { AgentUpgradeDetails } from '../../../../../../../common/types';

Expand Down Expand Up @@ -62,6 +63,16 @@ const formatRate = (downloadRate: number) => {
}
return downloadRate.toFixed(1) + byteUnits[i];
};
const formatRetryUntil = (retryUntil: string | undefined) => {
if (!retryUntil) return '';
const eta = new Date(retryUntil).toISOString();
const remainingTime = Date.parse(retryUntil) - Date.now();
const duration = moment
.utc(moment.duration(remainingTime, 'milliseconds').asMilliseconds())
.format('HH:mm');

return remainingTime > 0 ? `Retrying until: ${eta} (${duration} remaining)` : '';
};

function getStatusComponents(agentUpgradeDetails?: AgentUpgradeDetails) {
switch (agentUpgradeDetails?.state) {
Expand Down Expand Up @@ -103,6 +114,28 @@ function getStatusComponents(agentUpgradeDetails?: AgentUpgradeDetails) {
),
};
case 'UPG_DOWNLOADING':
if (agentUpgradeDetails?.metadata?.retry_error_msg) {
return {
Badge: (
<EuiBadge color="accent" iconType="download">
<FormattedMessage
id="xpack.fleet.agentUpgradeStatusBadge.upgradeDownloading"
defaultMessage="Upgrade downloading"
/>
</EuiBadge>
),
WarningTooltipText: (
<FormattedMessage
id="xpack.fleet.agentUpgradeStatusTooltip.upgradeDownloadingFailed"
defaultMessage="Upgrade failing: {retryMsg}. {retryUntil}"
values={{
retryMsg: agentUpgradeDetails?.metadata?.retry_error_msg,
retryUntil: formatRetryUntil(agentUpgradeDetails?.metadata?.retry_until),
}}
/>
),
};
}
return {
Badge: (
<EuiBadge color="accent" iconType="download">
Expand Down Expand Up @@ -252,24 +285,6 @@ export const AgentUpgradeStatus: React.FC<{
const status = useMemo(() => getStatusComponents(agentUpgradeDetails), [agentUpgradeDetails]);
const minVersion = '8.12';

if (!isAgentUpgradable && notUpgradeableMessage) {
return (
<EuiIconTip
type="iInCircle"
content={
<FormattedMessage
id="xpack.fleet.agentUpgradeStatusBadge.notUpgradeable"
defaultMessage="Agent not upgradeable: {reason}"
values={{
reason: notUpgradeableMessage,
}}
/>
}
color="subdued"
/>
);
}

if (isAgentUpgradable) {
return (
<EuiBadge color="hollow" iconType="sortUp">
Expand All @@ -285,9 +300,16 @@ export const AgentUpgradeStatus: React.FC<{
return (
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
<EuiFlexItem grow={false}>{status.Badge}</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiIconTip type="iInCircle" content={status.TooltipText} color="subdued" />
</EuiFlexItem>
{status.TooltipText && (
<EuiFlexItem grow={false}>
<EuiIconTip type="iInCircle" content={status.TooltipText} color="subdued" />
</EuiFlexItem>
)}
{status.WarningTooltipText && (
<EuiFlexItem grow={false}>
<EuiIconTip type="warning" content={status.WarningTooltipText} color="warning" />
</EuiFlexItem>
)}
</EuiFlexGroup>
);
}
Expand All @@ -310,5 +332,23 @@ export const AgentUpgradeStatus: React.FC<{
);
}

if (!isAgentUpgradable && notUpgradeableMessage) {
return (
<EuiIconTip
type="iInCircle"
content={
<FormattedMessage
id="xpack.fleet.agentUpgradeStatusBadge.notUpgradeable"
defaultMessage="Agent not upgradeable: {reason}"
values={{
reason: notUpgradeableMessage,
}}
/>
}
color="subdued"
/>
);
}

return null;
};
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/public/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export {
isValidNamespace,
LicenseService,
isAgentUpgradeable,
getNotUpgradeableMessage,
doesPackageHaveIntegrations,
validatePackagePolicy,
validatePackagePolicyConfig,
Expand Down

0 comments on commit 1de5cde

Please sign in to comment.