Files
Checkmate/client/src/Pages/Infrastructure/Details/Components/ContainerStats/ContainerStatBoxes.jsx
T
gorkem-bwl e9da602af6 feat: Add Proxmox LXC container monitoring support
## Summary
Add support for monitoring Proxmox LXC containers through the Capture agent's
/api/v1/metrics/proxmox endpoint. This feature is opt-in via a new setting
in the infrastructure monitor configuration.

## Backend Changes
- Add enableProxmoxContainers field to Monitor schema and types
- Update networkService to conditionally fetch Proxmox metrics
- Handle HTTP 207 multi-status responses and merge errors
- Add containers field to Check schema for storing container data
- Update validation schemas for the new setting

## Frontend Changes
- Add ContainerStats component with charts and stat boxes
- Add Containers tab to infrastructure monitor details (conditional)
- Add enableProxmoxContainers switch in monitor create/edit form
- Fix chart colors for disk I/O and network I/O to be distinct
- Add dotColor2 prop to InfrastructureTooltip for multi-series charts
- Add translation keys to all 16 locale files

## How It Works
1. User enables "Proxmox container monitoring" in monitor settings
2. Checkmate appends /proxmox to the metrics URL when fetching
3. Container data is displayed in a dedicated tab with:
   - CPU, memory, disk, swap, and uptime stat boxes
   - Interactive charts for CPU, memory, disk I/O, network I/O
4. Errors from Capture are merged and logged appropriately
2026-01-16 19:07:49 -05:00

131 lines
3.3 KiB
React

import PropTypes from "prop-types";
import StatusBoxes from "@/Components/v1/StatusBoxes/index.jsx";
import StatBox from "@/Components/v1/StatBox/index.jsx";
import { Typography } from "@mui/material";
import { useTranslation } from "react-i18next";
import { useHardwareUtils } from "../../Hooks/useHardwareUtils.jsx";
const formatUptime = (seconds) => {
if (!seconds || seconds === 0) return "0s";
const days = Math.floor(seconds / 86400);
const hours = Math.floor((seconds % 86400) / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
if (days > 0) {
return `${days}d ${hours}h`;
} else if (hours > 0) {
return `${hours}h ${minutes}m`;
} else if (minutes > 0) {
return `${minutes}m`;
}
return `${Math.floor(seconds)}s`;
};
const formatPercentage = (value) => {
if (value === undefined || value === null) return "0%";
return `${(value * 100).toFixed(1)}%`;
};
// Map container status to Checkmate monitor status for theming
const containerStatusToMonitorStatus = (status) => {
if (status === "running") return "up";
if (status === "stopped") return "down";
return "pending";
};
const ContainerStatBoxes = ({ shouldRender, container }) => {
const { t } = useTranslation();
const { formatBytes } = useHardwareUtils();
if (!container) {
return <Typography>{t("noContainerSelected")}</Typography>;
}
const monitorStatus = containerStatusToMonitorStatus(container.status);
return (
<StatusBoxes
shouldRender={shouldRender}
flexWrap="wrap"
>
<StatBox
gradient={true}
status={monitorStatus}
heading={t("status")}
subHeading={container.status || "unknown"}
/>
<StatBox
heading={t("type")}
subHeading={
<Typography component="span">
{(container.type || "lxc").toUpperCase()}
</Typography>
}
/>
<StatBox
heading={t("uptime")}
subHeading={formatUptime(container.uptime)}
/>
<StatBox
heading={t("cpuUsage")}
subHeading={
<>
{formatPercentage(container.cpu_usage)}
<Typography component="span">
({container.cpu_cores || 0} {t("cores")})
</Typography>
</>
}
/>
<StatBox
heading={t("memoryUsage")}
subHeading={
<>
{formatBytes(container.memory_used)}
<Typography component="span"> / </Typography>
{formatBytes(container.memory_total)}
</>
}
/>
<StatBox
heading={t("diskUsage")}
subHeading={
<>
{formatBytes(container.disk_used)}
<Typography component="span"> / </Typography>
{formatBytes(container.disk_total)}
</>
}
/>
</StatusBoxes>
);
};
ContainerStatBoxes.propTypes = {
shouldRender: PropTypes.bool.isRequired,
container: PropTypes.shape({
vmid: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
name: PropTypes.string,
node: PropTypes.string,
status: PropTypes.string,
type: PropTypes.string,
uptime: PropTypes.number,
cpu_cores: PropTypes.number,
cpu_usage: PropTypes.number,
memory_used: PropTypes.number,
memory_total: PropTypes.number,
memory_usage: PropTypes.number,
swap_used: PropTypes.number,
swap_total: PropTypes.number,
disk_used: PropTypes.number,
disk_total: PropTypes.number,
disk_read: PropTypes.number,
disk_write: PropTypes.number,
network_in: PropTypes.number,
network_out: PropTypes.number,
}),
};
export default ContainerStatBoxes;