mirror of https://github.com/portainer/portainer
feat(edge/stacks): info for old agent status [EE-5792] (#10012)
parent
f5cc245c63
commit
faa1387110
|
@ -50,7 +50,7 @@ func (store *Store) MigrateData() error {
|
|||
if err != nil {
|
||||
err = errors.Wrap(err, "failed to migrate database")
|
||||
|
||||
log.Warn().Msg("migration failed, restoring database to previous version")
|
||||
log.Warn().Err(err).Msg("migration failed, restoring database to previous version")
|
||||
err = store.restoreWithOptions(&BackupOptions{BackupPath: backupPath})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to restore database")
|
||||
|
|
|
@ -115,10 +115,16 @@ func (m *Migrator) updateEdgeStackStatusForDB100() error {
|
|||
}
|
||||
|
||||
if environmentStatus.Details.Ok {
|
||||
statusArray = append(statusArray, portainer.EdgeStackDeploymentStatus{
|
||||
Type: portainer.EdgeStackStatusRunning,
|
||||
Time: time.Now().Unix(),
|
||||
})
|
||||
statusArray = append(statusArray,
|
||||
portainer.EdgeStackDeploymentStatus{
|
||||
Type: portainer.EdgeStackStatusDeploymentReceived,
|
||||
Time: time.Now().Unix(),
|
||||
},
|
||||
portainer.EdgeStackDeploymentStatus{
|
||||
Type: portainer.EdgeStackStatusRunning,
|
||||
Time: time.Now().Unix(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if environmentStatus.Details.ImagesPulled {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { semverCompare } from './utils';
|
||||
import { semverCompare } from './semver-utils';
|
||||
|
||||
describe('semverCompare', () => {
|
||||
test('sort array', () => {
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Compares two semver strings.
|
||||
*
|
||||
* returns:
|
||||
* - `-1` if `a < b`
|
||||
* - `0` if `a == b`
|
||||
* - `1` if `a > b`
|
||||
*/
|
||||
export function semverCompare(a: string, b: string) {
|
||||
if (a.startsWith(`${b}-`)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b.startsWith(`${a}-`)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return a.localeCompare(b, undefined, {
|
||||
numeric: true,
|
||||
sensitivity: 'case',
|
||||
caseFirst: 'upper',
|
||||
});
|
||||
}
|
||||
|
||||
export function isVersionSmaller(a: string, b: string) {
|
||||
return semverCompare(a, b) < 0;
|
||||
}
|
|
@ -5,9 +5,14 @@ import {
|
|||
type Icon as IconType,
|
||||
Loader2,
|
||||
XCircle,
|
||||
MinusCircle,
|
||||
} from 'lucide-react';
|
||||
|
||||
import { useEnvironmentList } from '@/react/portainer/environments/queries';
|
||||
import { isVersionSmaller } from '@/react/common/semver-utils';
|
||||
|
||||
import { Icon, IconMode } from '@@/Icon';
|
||||
import { Tooltip } from '@@/Tip/Tooltip';
|
||||
|
||||
import { DeploymentStatus, EdgeStack, StatusType } from '../../types';
|
||||
|
||||
|
@ -15,28 +20,51 @@ export function EdgeStackStatus({ edgeStack }: { edgeStack: EdgeStack }) {
|
|||
const status = Object.values(edgeStack.Status);
|
||||
const lastStatus = _.compact(status.map((s) => _.last(s.Status)));
|
||||
|
||||
const { icon, label, mode, spin } = getStatus(
|
||||
const environmentsQuery = useEnvironmentList({ edgeStackId: edgeStack.Id });
|
||||
|
||||
if (environmentsQuery.isLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hasOldVersion = environmentsQuery.environments.some((env) =>
|
||||
isVersionSmaller(env.Agent.Version, '2.19.0')
|
||||
);
|
||||
|
||||
const { icon, label, mode, spin, tooltip } = getStatus(
|
||||
edgeStack.NumDeployments,
|
||||
lastStatus
|
||||
lastStatus,
|
||||
hasOldVersion
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx-auto inline-flex items-center gap-2">
|
||||
{icon && <Icon icon={icon} spin={spin} mode={mode} />}
|
||||
{label}
|
||||
{tooltip && <Tooltip message={tooltip} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getStatus(
|
||||
numDeployments: number,
|
||||
envStatus: Array<DeploymentStatus>
|
||||
envStatus: Array<DeploymentStatus>,
|
||||
hasOldVersion: boolean
|
||||
): {
|
||||
label: string;
|
||||
icon?: IconType;
|
||||
spin?: boolean;
|
||||
mode?: IconMode;
|
||||
tooltip?: string;
|
||||
} {
|
||||
if (!numDeployments || hasOldVersion) {
|
||||
return {
|
||||
label: 'Unavailable',
|
||||
icon: MinusCircle,
|
||||
mode: 'secondary',
|
||||
tooltip: getUnavailableTooltip(),
|
||||
};
|
||||
}
|
||||
|
||||
if (envStatus.length < numDeployments) {
|
||||
return {
|
||||
label: 'Deploying',
|
||||
|
@ -56,7 +84,11 @@ function getStatus(
|
|||
};
|
||||
}
|
||||
|
||||
const allRunning = envStatus.every((s) => s.Type === StatusType.Running);
|
||||
const allRunning = envStatus.every(
|
||||
(s) =>
|
||||
s.Type === StatusType.Running ||
|
||||
(s.Type === StatusType.DeploymentReceived && hasOldVersion)
|
||||
);
|
||||
|
||||
if (allRunning) {
|
||||
return {
|
||||
|
@ -84,4 +116,16 @@ function getStatus(
|
|||
spin: true,
|
||||
mode: 'primary',
|
||||
};
|
||||
|
||||
function getUnavailableTooltip() {
|
||||
if (!numDeployments) {
|
||||
return 'Your edge stack is currently unavailable due to the absence of an available environment in your edge group';
|
||||
}
|
||||
|
||||
if (hasOldVersion) {
|
||||
return 'Please note that the new status feature for the Edge stack is only available for Edge Agent versions 2.19.0 and above. To access the status of your edge stack, it is essential to upgrade your Edge Agent to a corresponding version that is compatible with your Portainer server.';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,13 +45,19 @@ export const columns = _.compact([
|
|||
(item) => item.aggregatedStatus[StatusType.ImagesPulled] || 0,
|
||||
{
|
||||
header: 'Images pre-pulled',
|
||||
cell: ({ getValue, row }) => (
|
||||
<DeploymentCounter
|
||||
count={getValue()}
|
||||
type={StatusType.ImagesPulled}
|
||||
total={row.original.NumDeployments}
|
||||
/>
|
||||
),
|
||||
cell: ({ getValue, row: { original: item } }) => {
|
||||
if (!item.PrePullImage) {
|
||||
return <div className="text-center">-</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<DeploymentCounter
|
||||
count={getValue()}
|
||||
type={StatusType.ImagesPulled}
|
||||
total={item.NumDeployments}
|
||||
/>
|
||||
);
|
||||
},
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
meta: {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
import { Environment } from '@/react/portainer/environments/types';
|
||||
import { semverCompare } from '@/react/common/semver-utils';
|
||||
|
||||
import { TextTip } from '@@/Tip/TextTip';
|
||||
|
||||
import { VersionSelect } from './VersionSelect';
|
||||
import { ScheduledTimeField } from './ScheduledTimeField';
|
||||
import { semverCompare } from './utils';
|
||||
|
||||
interface Props {
|
||||
environments: Environment[];
|
||||
|
|
|
@ -1,18 +1,4 @@
|
|||
export function semverCompare(a: string, b: string) {
|
||||
if (a.startsWith(`${b}-`)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b.startsWith(`${a}-`)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return a.localeCompare(b, undefined, {
|
||||
numeric: true,
|
||||
sensitivity: 'case',
|
||||
caseFirst: 'upper',
|
||||
});
|
||||
}
|
||||
import { semverCompare } from '@/react/common/semver-utils';
|
||||
|
||||
export function compareVersion(
|
||||
currentVersion: string,
|
||||
|
|
|
@ -2,8 +2,7 @@ import { useQuery } from 'react-query';
|
|||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { withError } from '@/react-tools/react-query';
|
||||
|
||||
import { semverCompare } from '../common/utils';
|
||||
import { semverCompare } from '@/react/common/semver-utils';
|
||||
|
||||
import { queryKeys } from './query-keys';
|
||||
import { buildUrl } from './urls';
|
||||
|
|
Loading…
Reference in New Issue