mirror of
https://github.com/9technologygroup/patchmon.net.git
synced 2025-11-21 06:58:20 +00:00
fixing host route of version checking for other architectures
This commit is contained in:
@@ -242,10 +242,11 @@ router.get("/hosts", authenticateToken, requireViewHosts, async (_req, res) => {
|
|||||||
orderBy: { last_update: "desc" },
|
orderBy: { last_update: "desc" },
|
||||||
});
|
});
|
||||||
|
|
||||||
// OPTIMIZATION: Get all package counts in 2 batch queries instead of N*2 queries
|
// OPTIMIZATION: Get all package counts in 3 batch queries instead of N*3 queries
|
||||||
const hostIds = hosts.map((h) => h.id);
|
const hostIds = hosts.map((h) => h.id);
|
||||||
|
|
||||||
const [updateCounts, totalCounts] = await Promise.all([
|
const [updateCounts, securityUpdateCounts, totalCounts] = await Promise.all(
|
||||||
|
[
|
||||||
// Get update counts for all hosts at once
|
// Get update counts for all hosts at once
|
||||||
prisma.host_packages.groupBy({
|
prisma.host_packages.groupBy({
|
||||||
by: ["host_id"],
|
by: ["host_id"],
|
||||||
@@ -255,6 +256,16 @@ router.get("/hosts", authenticateToken, requireViewHosts, async (_req, res) => {
|
|||||||
},
|
},
|
||||||
_count: { id: true },
|
_count: { id: true },
|
||||||
}),
|
}),
|
||||||
|
// Get security update counts for all hosts at once
|
||||||
|
prisma.host_packages.groupBy({
|
||||||
|
by: ["host_id"],
|
||||||
|
where: {
|
||||||
|
host_id: { in: hostIds },
|
||||||
|
needs_update: true,
|
||||||
|
is_security_update: true,
|
||||||
|
},
|
||||||
|
_count: { id: true },
|
||||||
|
}),
|
||||||
// Get total counts for all hosts at once
|
// Get total counts for all hosts at once
|
||||||
prisma.host_packages.groupBy({
|
prisma.host_packages.groupBy({
|
||||||
by: ["host_id"],
|
by: ["host_id"],
|
||||||
@@ -263,12 +274,16 @@ router.get("/hosts", authenticateToken, requireViewHosts, async (_req, res) => {
|
|||||||
},
|
},
|
||||||
_count: { id: true },
|
_count: { id: true },
|
||||||
}),
|
}),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
|
|
||||||
// Create lookup maps for O(1) access
|
// Create lookup maps for O(1) access
|
||||||
const updateCountMap = new Map(
|
const updateCountMap = new Map(
|
||||||
updateCounts.map((item) => [item.host_id, item._count.id]),
|
updateCounts.map((item) => [item.host_id, item._count.id]),
|
||||||
);
|
);
|
||||||
|
const securityUpdateCountMap = new Map(
|
||||||
|
securityUpdateCounts.map((item) => [item.host_id, item._count.id]),
|
||||||
|
);
|
||||||
const totalCountMap = new Map(
|
const totalCountMap = new Map(
|
||||||
totalCounts.map((item) => [item.host_id, item._count.id]),
|
totalCounts.map((item) => [item.host_id, item._count.id]),
|
||||||
);
|
);
|
||||||
@@ -276,6 +291,7 @@ router.get("/hosts", authenticateToken, requireViewHosts, async (_req, res) => {
|
|||||||
// Process hosts with counts from maps (no more DB queries!)
|
// Process hosts with counts from maps (no more DB queries!)
|
||||||
const hostsWithUpdateInfo = hosts.map((host) => {
|
const hostsWithUpdateInfo = hosts.map((host) => {
|
||||||
const updatesCount = updateCountMap.get(host.id) || 0;
|
const updatesCount = updateCountMap.get(host.id) || 0;
|
||||||
|
const securityUpdatesCount = securityUpdateCountMap.get(host.id) || 0;
|
||||||
const totalPackagesCount = totalCountMap.get(host.id) || 0;
|
const totalPackagesCount = totalCountMap.get(host.id) || 0;
|
||||||
|
|
||||||
// Calculate effective status based on reporting interval
|
// Calculate effective status based on reporting interval
|
||||||
@@ -292,6 +308,7 @@ router.get("/hosts", authenticateToken, requireViewHosts, async (_req, res) => {
|
|||||||
return {
|
return {
|
||||||
...host,
|
...host,
|
||||||
updatesCount,
|
updatesCount,
|
||||||
|
securityUpdatesCount,
|
||||||
totalPackagesCount,
|
totalPackagesCount,
|
||||||
isStale,
|
isStale,
|
||||||
effectiveStatus,
|
effectiveStatus,
|
||||||
|
|||||||
@@ -181,6 +181,9 @@ router.get("/agent/version", async (req, res) => {
|
|||||||
|
|
||||||
if (fs.existsSync(binaryPath)) {
|
if (fs.existsSync(binaryPath)) {
|
||||||
// Binary exists in server's agents folder - use its version
|
// Binary exists in server's agents folder - use its version
|
||||||
|
let serverVersion = null;
|
||||||
|
|
||||||
|
// Try method 1: Execute binary (works for same architecture)
|
||||||
try {
|
try {
|
||||||
const { stdout } = await execAsync(`${binaryPath} --help`, {
|
const { stdout } = await execAsync(`${binaryPath} --help`, {
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
@@ -192,7 +195,42 @@ router.get("/agent/version", async (req, res) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (versionMatch) {
|
if (versionMatch) {
|
||||||
const serverVersion = versionMatch[1];
|
serverVersion = versionMatch[1];
|
||||||
|
}
|
||||||
|
} catch (execError) {
|
||||||
|
// Execution failed (likely cross-architecture) - try alternative method
|
||||||
|
console.warn(
|
||||||
|
`Failed to execute binary ${binaryName} to get version (may be cross-architecture): ${execError.message}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try method 2: Extract version using strings command (works for cross-architecture)
|
||||||
|
try {
|
||||||
|
const { stdout: stringsOutput } = await execAsync(
|
||||||
|
`strings "${binaryPath}" | grep -E "PatchMon Agent v[0-9]+\\.[0-9]+\\.[0-9]+" | head -1`,
|
||||||
|
{
|
||||||
|
timeout: 10000,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const versionMatch = stringsOutput.match(
|
||||||
|
/PatchMon Agent v([0-9]+\.[0-9]+\.[0-9]+)/i,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (versionMatch) {
|
||||||
|
serverVersion = versionMatch[1];
|
||||||
|
console.log(
|
||||||
|
`✅ Extracted version ${serverVersion} from binary using strings command`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (stringsError) {
|
||||||
|
console.warn(
|
||||||
|
`Failed to extract version using strings command: ${stringsError.message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we successfully got the version, return it
|
||||||
|
if (serverVersion) {
|
||||||
const agentVersion = req.query.currentVersion || serverVersion;
|
const agentVersion = req.query.currentVersion || serverVersion;
|
||||||
|
|
||||||
// Proper semantic version comparison: only update if server version is NEWER
|
// Proper semantic version comparison: only update if server version is NEWER
|
||||||
@@ -209,13 +247,11 @@ router.get("/agent/version", async (req, res) => {
|
|||||||
agentType: "go",
|
agentType: "go",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (execError) {
|
|
||||||
// Execution failed, but binary exists - try to get version another way
|
// If we couldn't get version, fall through to error response
|
||||||
console.warn(
|
console.warn(
|
||||||
`Failed to execute binary ${binaryName} to get version: ${execError.message}`,
|
`Could not determine version for binary ${binaryName} using any method`,
|
||||||
);
|
);
|
||||||
// Fall through to error response
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binary doesn't exist or couldn't get version - return error
|
// Binary doesn't exist or couldn't get version - return error
|
||||||
|
|||||||
@@ -335,9 +335,15 @@ const Hosts = () => {
|
|||||||
{ id: "status", label: "Status", visible: true, order: 10 },
|
{ id: "status", label: "Status", visible: true, order: 10 },
|
||||||
{ id: "needs_reboot", label: "Reboot", visible: true, order: 11 },
|
{ id: "needs_reboot", label: "Reboot", visible: true, order: 11 },
|
||||||
{ id: "updates", label: "Updates", visible: true, order: 12 },
|
{ id: "updates", label: "Updates", visible: true, order: 12 },
|
||||||
{ id: "notes", label: "Notes", visible: false, order: 13 },
|
{
|
||||||
{ id: "last_update", label: "Last Update", visible: true, order: 14 },
|
id: "security_updates",
|
||||||
{ id: "actions", label: "Actions", visible: true, order: 15 },
|
label: "Security Updates",
|
||||||
|
visible: true,
|
||||||
|
order: 13,
|
||||||
|
},
|
||||||
|
{ id: "notes", label: "Notes", visible: false, order: 14 },
|
||||||
|
{ id: "last_update", label: "Last Update", visible: true, order: 15 },
|
||||||
|
{ id: "actions", label: "Actions", visible: true, order: 16 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const saved = localStorage.getItem("hosts-column-config");
|
const saved = localStorage.getItem("hosts-column-config");
|
||||||
@@ -781,6 +787,10 @@ const Hosts = () => {
|
|||||||
aValue = a.updatesCount || 0;
|
aValue = a.updatesCount || 0;
|
||||||
bValue = b.updatesCount || 0;
|
bValue = b.updatesCount || 0;
|
||||||
break;
|
break;
|
||||||
|
case "security_updates":
|
||||||
|
aValue = a.securityUpdatesCount || 0;
|
||||||
|
bValue = b.securityUpdatesCount || 0;
|
||||||
|
break;
|
||||||
case "needs_reboot":
|
case "needs_reboot":
|
||||||
// Sort by boolean: false (0) comes before true (1)
|
// Sort by boolean: false (0) comes before true (1)
|
||||||
aValue = a.needs_reboot ? 1 : 0;
|
aValue = a.needs_reboot ? 1 : 0;
|
||||||
@@ -947,9 +957,15 @@ const Hosts = () => {
|
|||||||
{ id: "status", label: "Status", visible: true, order: 10 },
|
{ id: "status", label: "Status", visible: true, order: 10 },
|
||||||
{ id: "needs_reboot", label: "Reboot", visible: true, order: 11 },
|
{ id: "needs_reboot", label: "Reboot", visible: true, order: 11 },
|
||||||
{ id: "updates", label: "Updates", visible: true, order: 12 },
|
{ id: "updates", label: "Updates", visible: true, order: 12 },
|
||||||
{ id: "notes", label: "Notes", visible: false, order: 13 },
|
{
|
||||||
{ id: "last_update", label: "Last Update", visible: true, order: 14 },
|
id: "security_updates",
|
||||||
{ id: "actions", label: "Actions", visible: true, order: 15 },
|
label: "Security Updates",
|
||||||
|
visible: true,
|
||||||
|
order: 13,
|
||||||
|
},
|
||||||
|
{ id: "notes", label: "Notes", visible: false, order: 14 },
|
||||||
|
{ id: "last_update", label: "Last Update", visible: true, order: 15 },
|
||||||
|
{ id: "actions", label: "Actions", visible: true, order: 16 },
|
||||||
];
|
];
|
||||||
updateColumnConfig(defaultConfig);
|
updateColumnConfig(defaultConfig);
|
||||||
};
|
};
|
||||||
@@ -1135,6 +1151,19 @@ const Hosts = () => {
|
|||||||
{host.updatesCount || 0}
|
{host.updatesCount || 0}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
case "security_updates":
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
navigate(`/packages?host=${host.id}&filter=security-updates`)
|
||||||
|
}
|
||||||
|
className="text-sm text-red-600 hover:text-red-900 dark:text-red-400 dark:hover:text-red-300 font-medium hover:underline"
|
||||||
|
title="View security updates for this host"
|
||||||
|
>
|
||||||
|
{host.securityUpdatesCount || 0}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
case "last_update":
|
case "last_update":
|
||||||
return (
|
return (
|
||||||
<div className="text-sm text-secondary-500 dark:text-secondary-300">
|
<div className="text-sm text-secondary-500 dark:text-secondary-300">
|
||||||
@@ -1731,6 +1760,17 @@ const Hosts = () => {
|
|||||||
{column.label}
|
{column.label}
|
||||||
{getSortIcon("updates")}
|
{getSortIcon("updates")}
|
||||||
</button>
|
</button>
|
||||||
|
) : column.id === "security_updates" ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
handleSort("security_updates")
|
||||||
|
}
|
||||||
|
className="flex items-center gap-2 hover:text-secondary-700"
|
||||||
|
>
|
||||||
|
{column.label}
|
||||||
|
{getSortIcon("security_updates")}
|
||||||
|
</button>
|
||||||
) : column.id === "needs_reboot" ? (
|
) : column.id === "needs_reboot" ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
Reference in New Issue
Block a user