feat: add Linux agent archives to releases and improve version mismatch detection
Release improvements: - Add standalone Linux agent archives (amd64, arm64, armv7, armv6, 386) to releases - Previously only Darwin/Windows had standalone agent downloads Agent version mismatch detection: - New agentVersion.ts utility compares agent versions against server version - DockerHostSummaryTable now shows accurate 'outdated' warnings when agent version is older than the connected Pulse server - Better tooltips explain version status and upgrade instructions
This commit is contained in:
parent
0b65d68682
commit
307bb9f6cc
3 changed files with 186 additions and 10 deletions
|
|
@ -12,6 +12,7 @@ import { getDockerHostStatusIndicator } from '@/utils/status';
|
|||
import { useBreakpoint } from '@/hooks/useBreakpoint';
|
||||
import { ResponsiveMetricCell, MetricText } from '@/components/shared/responsive';
|
||||
import { EnhancedCPUBar } from '@/components/Dashboard/EnhancedCPUBar';
|
||||
import { isAgentOutdated, getAgentVersionTooltip } from '@/utils/agentVersion';
|
||||
|
||||
export interface DockerHostSummary {
|
||||
host: DockerHost;
|
||||
|
|
@ -129,10 +130,7 @@ export const DockerHostSummaryTable: Component<DockerHostSummaryTableProps> = (p
|
|||
return sortDirection() === 'asc' ? '▲' : '▼';
|
||||
};
|
||||
|
||||
const isAgentOutdated = (version?: string) => {
|
||||
if (!version) return false;
|
||||
return version.includes('dev') || version.startsWith('0.1');
|
||||
};
|
||||
// Agent version checking is now done via the shared utility that compares against server version
|
||||
|
||||
return (
|
||||
<Card padding="none" tone="glass" class="mb-4 overflow-hidden">
|
||||
|
|
@ -370,10 +368,7 @@ export const DockerHostSummaryTable: Component<DockerHostSummaryTableProps> = (p
|
|||
? 'px-1.5 py-0.5 rounded bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400 font-medium'
|
||||
: 'px-1.5 py-0.5 rounded bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400 font-medium'
|
||||
}
|
||||
title={`${agentOutdated
|
||||
? 'Agent is outdated on this host'
|
||||
: 'Agent is up to date'
|
||||
}${summary.host.intervalSeconds ? `\nReporting interval: ${summary.host.intervalSeconds}s` : ''}`}
|
||||
title={`${getAgentVersionTooltip(summary.host.agentVersion)}${summary.host.intervalSeconds ? `\nReporting interval: ${summary.host.intervalSeconds}s` : ''}`}
|
||||
>
|
||||
{version()}
|
||||
</span>
|
||||
|
|
|
|||
165
frontend-modern/src/utils/agentVersion.ts
Normal file
165
frontend-modern/src/utils/agentVersion.ts
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/**
|
||||
* Agent version comparison utilities
|
||||
*
|
||||
* Used to detect outdated agents by comparing their version to the server version.
|
||||
*/
|
||||
|
||||
import { updateStore } from '@/stores/updates';
|
||||
|
||||
/**
|
||||
* Parses a version string (e.g., "v5.0.0", "5.0.0-rc.3", "dev") into components
|
||||
*/
|
||||
interface ParsedVersion {
|
||||
major: number;
|
||||
minor: number;
|
||||
patch: number;
|
||||
prerelease: string | null;
|
||||
isValid: boolean;
|
||||
}
|
||||
|
||||
function parseVersion(version: string): ParsedVersion {
|
||||
if (!version || version === 'dev' || version === 'unknown') {
|
||||
return { major: 0, minor: 0, patch: 0, prerelease: null, isValid: false };
|
||||
}
|
||||
|
||||
// Remove leading 'v' if present
|
||||
const cleaned = version.startsWith('v') ? version.slice(1) : version;
|
||||
|
||||
// Split into version and prerelease parts
|
||||
const [versionPart, ...prereleaseParts] = cleaned.split('-');
|
||||
const prerelease = prereleaseParts.length > 0 ? prereleaseParts.join('-') : null;
|
||||
|
||||
// Parse major.minor.patch
|
||||
const parts = versionPart.split('.').map((p) => parseInt(p, 10));
|
||||
|
||||
if (parts.some((p) => isNaN(p))) {
|
||||
return { major: 0, minor: 0, patch: 0, prerelease: null, isValid: false };
|
||||
}
|
||||
|
||||
return {
|
||||
major: parts[0] || 0,
|
||||
minor: parts[1] || 0,
|
||||
patch: parts[2] || 0,
|
||||
prerelease,
|
||||
isValid: true,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two version strings
|
||||
* Returns:
|
||||
* -1 if a < b
|
||||
* 0 if a == b
|
||||
* 1 if a > b
|
||||
*/
|
||||
export function compareVersions(a: string, b: string): number {
|
||||
const va = parseVersion(a);
|
||||
const vb = parseVersion(b);
|
||||
|
||||
// Invalid versions are considered older
|
||||
if (!va.isValid && !vb.isValid) return 0;
|
||||
if (!va.isValid) return -1;
|
||||
if (!vb.isValid) return 1;
|
||||
|
||||
// Compare major.minor.patch
|
||||
if (va.major !== vb.major) return va.major - vb.major;
|
||||
if (va.minor !== vb.minor) return va.minor - vb.minor;
|
||||
if (va.patch !== vb.patch) return va.patch - vb.patch;
|
||||
|
||||
// Same base version, compare prerelease
|
||||
// No prerelease = stable = newer than prerelease
|
||||
if (!va.prerelease && vb.prerelease) return 1;
|
||||
if (va.prerelease && !vb.prerelease) return -1;
|
||||
if (!va.prerelease && !vb.prerelease) return 0;
|
||||
|
||||
// Both have prerelease, compare lexicographically
|
||||
return (va.prerelease || '').localeCompare(vb.prerelease || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current server version from the update store
|
||||
*/
|
||||
export function getServerVersion(): string {
|
||||
const info = updateStore.versionInfo();
|
||||
return info?.version ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an agent version is outdated compared to the server version
|
||||
* Returns an object with the status and details
|
||||
*/
|
||||
export interface AgentVersionStatus {
|
||||
isOutdated: boolean;
|
||||
isDev: boolean;
|
||||
isUnknown: boolean;
|
||||
serverVersion: string;
|
||||
comparisonResult: number; // -1 = older, 0 = same, 1 = newer
|
||||
}
|
||||
|
||||
export function checkAgentVersion(agentVersion?: string): AgentVersionStatus {
|
||||
const result: AgentVersionStatus = {
|
||||
isOutdated: false,
|
||||
isDev: false,
|
||||
isUnknown: false,
|
||||
serverVersion: getServerVersion(),
|
||||
comparisonResult: 0,
|
||||
};
|
||||
|
||||
if (!agentVersion) {
|
||||
result.isUnknown = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Dev versions are always considered potentially outdated
|
||||
if (agentVersion === 'dev' || agentVersion.includes('-dirty')) {
|
||||
result.isDev = true;
|
||||
// Don't mark dev as outdated if server is also dev
|
||||
if (result.serverVersion && !result.serverVersion.includes('dev')) {
|
||||
result.isOutdated = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compare to server version if available
|
||||
if (result.serverVersion) {
|
||||
result.comparisonResult = compareVersions(agentVersion, result.serverVersion);
|
||||
// Agent is outdated if it's older than server
|
||||
result.isOutdated = result.comparisonResult < 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple check for whether an agent should show an outdated warning
|
||||
* This is a convenience wrapper around checkAgentVersion
|
||||
*/
|
||||
export function isAgentOutdated(agentVersion?: string): boolean {
|
||||
const status = checkAgentVersion(agentVersion);
|
||||
return status.isOutdated || status.isDev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a tooltip message explaining the agent version status
|
||||
*/
|
||||
export function getAgentVersionTooltip(agentVersion?: string): string {
|
||||
const status = checkAgentVersion(agentVersion);
|
||||
|
||||
if (status.isUnknown) {
|
||||
return 'Agent version unknown';
|
||||
}
|
||||
|
||||
if (status.isDev) {
|
||||
return 'Development build - consider updating to a release version';
|
||||
}
|
||||
|
||||
if (status.isOutdated && status.serverVersion) {
|
||||
return `Agent is outdated (${agentVersion} < ${status.serverVersion}). Re-run the install script to update.`;
|
||||
}
|
||||
|
||||
if (status.comparisonResult > 0 && status.serverVersion) {
|
||||
return `Agent is newer than server (${agentVersion} > ${status.serverVersion})`;
|
||||
}
|
||||
|
||||
return 'Agent is up to date';
|
||||
}
|
||||
|
|
@ -330,16 +330,32 @@ chmod +x "$universal_dir/bin/pulse-agent"
|
|||
# Add VERSION file
|
||||
echo "$VERSION" > "$universal_dir/VERSION"
|
||||
|
||||
# Package standalone host agent binaries
|
||||
# Package standalone host agent binaries (all platforms)
|
||||
# Linux
|
||||
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-linux-amd64.tar.gz" -C "$BUILD_DIR" pulse-host-agent-linux-amd64
|
||||
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-linux-arm64.tar.gz" -C "$BUILD_DIR" pulse-host-agent-linux-arm64
|
||||
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-linux-armv7.tar.gz" -C "$BUILD_DIR" pulse-host-agent-linux-armv7
|
||||
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-linux-armv6.tar.gz" -C "$BUILD_DIR" pulse-host-agent-linux-armv6
|
||||
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-linux-386.tar.gz" -C "$BUILD_DIR" pulse-host-agent-linux-386
|
||||
# Darwin
|
||||
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-darwin-amd64.tar.gz" -C "$BUILD_DIR" pulse-host-agent-darwin-amd64
|
||||
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-darwin-arm64.tar.gz" -C "$BUILD_DIR" pulse-host-agent-darwin-arm64
|
||||
# Windows
|
||||
zip -j "$RELEASE_DIR/pulse-host-agent-v${VERSION}-windows-amd64.zip" "$BUILD_DIR/pulse-host-agent-windows-amd64.exe"
|
||||
zip -j "$RELEASE_DIR/pulse-host-agent-v${VERSION}-windows-arm64.zip" "$BUILD_DIR/pulse-host-agent-windows-arm64.exe"
|
||||
zip -j "$RELEASE_DIR/pulse-host-agent-v${VERSION}-windows-386.zip" "$BUILD_DIR/pulse-host-agent-windows-386.exe"
|
||||
|
||||
# Package standalone unified agent binaries
|
||||
# Package standalone unified agent binaries (all platforms)
|
||||
# Linux
|
||||
tar -czf "$RELEASE_DIR/pulse-agent-v${VERSION}-linux-amd64.tar.gz" -C "$BUILD_DIR" pulse-agent-linux-amd64
|
||||
tar -czf "$RELEASE_DIR/pulse-agent-v${VERSION}-linux-arm64.tar.gz" -C "$BUILD_DIR" pulse-agent-linux-arm64
|
||||
tar -czf "$RELEASE_DIR/pulse-agent-v${VERSION}-linux-armv7.tar.gz" -C "$BUILD_DIR" pulse-agent-linux-armv7
|
||||
tar -czf "$RELEASE_DIR/pulse-agent-v${VERSION}-linux-armv6.tar.gz" -C "$BUILD_DIR" pulse-agent-linux-armv6
|
||||
tar -czf "$RELEASE_DIR/pulse-agent-v${VERSION}-linux-386.tar.gz" -C "$BUILD_DIR" pulse-agent-linux-386
|
||||
# Darwin
|
||||
tar -czf "$RELEASE_DIR/pulse-agent-v${VERSION}-darwin-amd64.tar.gz" -C "$BUILD_DIR" pulse-agent-darwin-amd64
|
||||
tar -czf "$RELEASE_DIR/pulse-agent-v${VERSION}-darwin-arm64.tar.gz" -C "$BUILD_DIR" pulse-agent-darwin-arm64
|
||||
# Windows
|
||||
zip -j "$RELEASE_DIR/pulse-agent-v${VERSION}-windows-amd64.zip" "$BUILD_DIR/pulse-agent-windows-amd64.exe"
|
||||
zip -j "$RELEASE_DIR/pulse-agent-v${VERSION}-windows-arm64.zip" "$BUILD_DIR/pulse-agent-windows-arm64.exe"
|
||||
zip -j "$RELEASE_DIR/pulse-agent-v${VERSION}-windows-386.zip" "$BUILD_DIR/pulse-agent-windows-386.exe"
|
||||
|
|
|
|||
Loading…
Reference in a new issue