This commit is contained in:
henrygd
2026-03-05 16:10:19 -05:00
parent 1243a7bd8d
commit d9e3c4678a
7 changed files with 316 additions and 180 deletions

View File

@@ -123,6 +123,9 @@ func (pm *pveManager) getPVEStats() ([]*container.PveNodeStats, error) {
resourceStats.MaxCPU = resource.MaxCPU resourceStats.MaxCPU = resource.MaxCPU
resourceStats.MaxMem = resource.MaxMem resourceStats.MaxMem = resource.MaxMem
resourceStats.Uptime = resource.Uptime resourceStats.Uptime = resource.Uptime
resourceStats.DiskRead = resource.DiskRead
resourceStats.DiskWrite = resource.DiskWrite
resourceStats.Disk = resource.MaxDisk
// prevent first run from sending all prev sent/recv bytes // prevent first run from sending all prev sent/recv bytes
total_sent := resource.NetOut total_sent := resource.NetOut
@@ -143,6 +146,8 @@ func (pm *pveManager) getPVEStats() ([]*container.PveNodeStats, error) {
resourceStats.Cpu = twoDecimals(100.0 * resource.CPU * float64(resource.MaxCPU) / float64(pm.cpuCount)) resourceStats.Cpu = twoDecimals(100.0 * resource.CPU * float64(resource.MaxCPU) / float64(pm.cpuCount))
resourceStats.Mem = bytesToMegabytes(float64(resource.Mem)) resourceStats.Mem = bytesToMegabytes(float64(resource.Mem))
resourceStats.Bandwidth = [2]uint64{uint64(sent_delta), uint64(recv_delta)} resourceStats.Bandwidth = [2]uint64{uint64(sent_delta), uint64(recv_delta)}
resourceStats.NetOut = total_sent
resourceStats.NetIn = total_recv
stats = append(stats, resourceStats) stats = append(stats, resourceStats)
} }

View File

@@ -157,8 +157,13 @@ type PveNodeStats struct {
// fields used for pve_vms table // fields used for pve_vms table
MaxCPU uint64 `json:"-" cbor:"10,keyasint,omitzero"` // PVE: max vCPU count MaxCPU uint64 `json:"-" cbor:"10,keyasint,omitzero"` // PVE: max vCPU count
MaxMem uint64 `json:"-" cbor:"11,keyasint,omitzero"` // PVE: max memory bytes MaxMem uint64 `json:"-" cbor:"11,keyasint,omitzero"` // PVE: max memory bytes
Uptime uint64 `json:"-" cbor:"12,keyasint,omitzero"` // PVE: uptime in seconds Uptime uint64 `json:"-" cbor:"12,keyasint,omitzero"` // PVE: uptime in seconds
Type string `json:"-" cbor:"13,keyasint,omitzero"` // PVE: resource type (e.g. "qemu" or "lxc") Type string `json:"-" cbor:"13,keyasint,omitzero"` // PVE: resource type (e.g. "qemu" or "lxc")
DiskRead uint64 `json:"-" cbor:"14,keyasint,omitzero"` // PVE: cumulative disk read bytes
DiskWrite uint64 `json:"-" cbor:"15,keyasint,omitzero"` // PVE: cumulative disk write bytes
Disk uint64 `json:"-" cbor:"16,keyasint,omitzero"` // PVE: allocated disk size in bytes
NetOut uint64 `json:"-" cbor:"17,keyasint,omitzero"` // PVE: cumulative bytes sent by VM
NetIn uint64 `json:"-" cbor:"18,keyasint,omitzero"` // PVE: cumulative bytes received by VM
} }

View File

@@ -367,7 +367,7 @@ func createPVEVMRecords(app core.App, data []*container.PveNodeStats, systemId s
valueStrings := make([]string, 0, len(data)) valueStrings := make([]string, 0, len(data))
for i, vm := range data { for i, vm := range data {
suffix := fmt.Sprintf("%d", i) suffix := fmt.Sprintf("%d", i)
valueStrings = append(valueStrings, fmt.Sprintf("({:id%[1]s}, {:system}, {:name%[1]s}, {:type%[1]s}, {:cpu%[1]s}, {:mem%[1]s}, {:net%[1]s}, {:maxcpu%[1]s}, {:maxmem%[1]s}, {:uptime%[1]s}, {:updated})", suffix)) valueStrings = append(valueStrings, fmt.Sprintf("({:id%[1]s}, {:system}, {:name%[1]s}, {:type%[1]s}, {:cpu%[1]s}, {:mem%[1]s}, {:netout%[1]s}, {:netin%[1]s}, {:maxcpu%[1]s}, {:maxmem%[1]s}, {:uptime%[1]s}, {:diskread%[1]s}, {:diskwrite%[1]s}, {:disk%[1]s}, {:updated})", suffix))
params["id"+suffix] = makeStableHashId(systemId, vm.Id) params["id"+suffix] = makeStableHashId(systemId, vm.Id)
params["name"+suffix] = vm.Name params["name"+suffix] = vm.Name
params["type"+suffix] = vm.Type // "qemu" or "lxc" params["type"+suffix] = vm.Type // "qemu" or "lxc"
@@ -376,11 +376,14 @@ func createPVEVMRecords(app core.App, data []*container.PveNodeStats, systemId s
params["maxcpu"+suffix] = vm.MaxCPU params["maxcpu"+suffix] = vm.MaxCPU
params["maxmem"+suffix] = vm.MaxMem params["maxmem"+suffix] = vm.MaxMem
params["uptime"+suffix] = vm.Uptime params["uptime"+suffix] = vm.Uptime
netBytes := vm.Bandwidth[0] + vm.Bandwidth[1] params["diskread"+suffix] = vm.DiskRead
params["net"+suffix] = netBytes params["diskwrite"+suffix] = vm.DiskWrite
params["disk"+suffix] = vm.Disk
params["netout"+suffix] = vm.NetOut // cumulative bytes sent by VM
params["netin"+suffix] = vm.NetIn // cumulative bytes received by VM
} }
queryString := fmt.Sprintf( queryString := fmt.Sprintf(
"INSERT INTO pve_vms (id, system, name, type, cpu, mem, net, maxcpu, maxmem, uptime, updated) VALUES %s ON CONFLICT(id) DO UPDATE SET system=excluded.system, name=excluded.name, type=excluded.type, cpu=excluded.cpu, mem=excluded.mem, net=excluded.net, maxcpu=excluded.maxcpu, maxmem=excluded.maxmem, uptime=excluded.uptime, updated=excluded.updated", "INSERT INTO pve_vms (id, system, name, type, cpu, mem, netout, netin, maxcpu, maxmem, uptime, diskread, diskwrite, disk, updated) VALUES %s ON CONFLICT(id) DO UPDATE SET system=excluded.system, name=excluded.name, type=excluded.type, cpu=excluded.cpu, mem=excluded.mem, netout=excluded.netout, netin=excluded.netin, maxcpu=excluded.maxcpu, maxmem=excluded.maxmem, uptime=excluded.uptime, diskread=excluded.diskread, diskwrite=excluded.diskwrite, disk=excluded.disk, updated=excluded.updated",
strings.Join(valueStrings, ","), strings.Join(valueStrings, ","),
) )
_, err := app.DB().NewQuery(queryString).Bind(params).Execute() _, err := app.DB().NewQuery(queryString).Bind(params).Execute()

View File

@@ -1847,30 +1847,6 @@ func init() {
"system": false, "system": false,
"type": "number" "type": "number"
}, },
{
"hidden": false,
"id": "pve_vms_mem001",
"max": null,
"min": 0,
"name": "mem",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "pve_vms_net001",
"max": null,
"min": null,
"name": "net",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{ {
"hidden": false, "hidden": false,
"id": "number1253106325", "id": "number1253106325",
@@ -1883,6 +1859,18 @@ func init() {
"system": false, "system": false,
"type": "number" "type": "number"
}, },
{
"hidden": false,
"id": "pve_vms_mem001",
"max": null,
"min": 0,
"name": "mem",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{ {
"hidden": false, "hidden": false,
"id": "number1693954525", "id": "number1693954525",
@@ -1895,6 +1883,66 @@ func init() {
"system": false, "system": false,
"type": "number" "type": "number"
}, },
{
"hidden": false,
"id": "number208985346",
"max": null,
"min": null,
"name": "disk",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "number4125810518",
"max": null,
"min": null,
"name": "diskread",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "number752404475",
"max": null,
"min": null,
"name": "diskwrite",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "number1880667380",
"max": null,
"min": null,
"name": "netout",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "number2702533949",
"max": null,
"min": null,
"name": "netin",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{ {
"hidden": false, "hidden": false,
"id": "number1563400775", "id": "number1563400775",
@@ -1932,7 +1980,6 @@ func init() {
"updateRule": null, "updateRule": null,
"viewRule": null "viewRule": null
} }
]` ]`
err := app.ImportCollectionsByMarshaledJSON([]byte(jsonData), false) err := app.ImportCollectionsByMarshaledJSON([]byte(jsonData), false)

View File

@@ -3,9 +3,9 @@ import { Button } from "@/components/ui/button"
import { cn, decimalString, formatBytes, hourWithSeconds, toFixedFloat } from "@/lib/utils" import { cn, decimalString, formatBytes, hourWithSeconds, toFixedFloat } from "@/lib/utils"
import type { PveVmRecord } from "@/types" import type { PveVmRecord } from "@/types"
import { import {
ArrowUpDownIcon,
ClockIcon, ClockIcon,
CpuIcon, CpuIcon,
HardDriveIcon,
MemoryStickIcon, MemoryStickIcon,
MonitorIcon, MonitorIcon,
ServerIcon, ServerIcon,
@@ -42,7 +42,7 @@ export const pveVmCols: ColumnDef<PveVmRecord>[] = [
accessorFn: (record) => record.name, accessorFn: (record) => record.name,
header: ({ column }) => <HeaderButton column={column} name={t`Name`} Icon={MonitorIcon} />, header: ({ column }) => <HeaderButton column={column} name={t`Name`} Icon={MonitorIcon} />,
cell: ({ getValue }) => { cell: ({ getValue }) => {
return <span className="ms-1.5 xl:w-48 block truncate">{getValue() as string}</span> return <span className="ms-1 max-w-48 block truncate">{getValue() as string}</span>
}, },
}, },
{ {
@@ -57,7 +57,7 @@ export const pveVmCols: ColumnDef<PveVmRecord>[] = [
header: ({ column }) => <HeaderButton column={column} name={t`System`} Icon={ServerIcon} />, header: ({ column }) => <HeaderButton column={column} name={t`System`} Icon={ServerIcon} />,
cell: ({ getValue }) => { cell: ({ getValue }) => {
const allSystems = useStore($allSystemsById) const allSystems = useStore($allSystemsById)
return <span className="ms-1.5 xl:w-34 block truncate">{allSystems[getValue() as string]?.name ?? ""}</span> return <span className="ms-1 max-w-34 block truncate">{allSystems[getValue() as string]?.name ?? ""}</span>
}, },
}, },
{ {
@@ -68,7 +68,7 @@ export const pveVmCols: ColumnDef<PveVmRecord>[] = [
cell: ({ getValue }) => { cell: ({ getValue }) => {
const type = getValue() as string const type = getValue() as string
return ( return (
<Badge variant="outline" className="dark:border-white/12 ms-1.5"> <Badge variant="outline" className="dark:border-white/12 ms-1">
{type} {type}
</Badge> </Badge>
) )
@@ -81,7 +81,7 @@ export const pveVmCols: ColumnDef<PveVmRecord>[] = [
header: ({ column }) => <HeaderButton column={column} name={t`CPU`} Icon={CpuIcon} />, header: ({ column }) => <HeaderButton column={column} name={t`CPU`} Icon={CpuIcon} />,
cell: ({ getValue }) => { cell: ({ getValue }) => {
const val = getValue() as number const val = getValue() as number
return <span className="ms-1.5 tabular-nums">{`${decimalString(val, val >= 10 ? 1 : 2)}%`}</span> return <span className="ms-1 tabular-nums">{`${decimalString(val, val >= 10 ? 1 : 2)}%`}</span>
}, },
}, },
{ {
@@ -93,41 +93,86 @@ export const pveVmCols: ColumnDef<PveVmRecord>[] = [
const val = getValue() as number const val = getValue() as number
const formatted = formatBytes(val, false, undefined, true) const formatted = formatBytes(val, false, undefined, true)
return ( return (
<span className="ms-1.5 tabular-nums">{`${decimalString(formatted.value, formatted.value >= 10 ? 1 : 2)} ${formatted.unit}`}</span> <span className="ms-1 tabular-nums">{`${decimalString(formatted.value, formatted.value >= 10 ? 1 : 2)} ${formatted.unit}`}</span>
) )
}, },
}, },
{ {
id: "net", id: "maxmem",
accessorFn: (record) => record.net, accessorFn: (record) => record.maxmem,
header: ({ column }) => <HeaderButton column={column} name={t`Max`} Icon={MemoryStickIcon} />,
invertSorting: true, invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Net`} Icon={EthernetIcon} />, cell: ({ getValue }) => {
// maxmem is stored in bytes; convert to MB for formatBytes
const formatted = formatBytes(getValue() as number, false, undefined, false)
return <span className="ms-1 tabular-nums">{`${toFixedFloat(formatted.value, 2)} ${formatted.unit}`}</span>
},
},
{
id: "disk",
accessorFn: (record) => record.disk,
invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Disk`} Icon={HardDriveIcon} />,
cell: ({ getValue }) => {
const formatted = formatBytes(getValue() as number, false, undefined, false)
return <span className="ms-1 tabular-nums">{`${toFixedFloat(formatted.value, 2)} ${formatted.unit}`}</span>
},
},
{
id: "diskread",
accessorFn: (record) => record.diskread,
invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Read`} Icon={HardDriveIcon} />,
cell: ({ getValue }) => { cell: ({ getValue }) => {
const val = getValue() as number const val = getValue() as number
const formatted = formatBytes(val, true, undefined, false) const formatted = formatBytes(val, false, undefined, false)
return <span className="ms-1 tabular-nums">{`${toFixedFloat(formatted.value, 2)} ${formatted.unit}`}</span>
},
},
{
id: "diskwrite",
accessorFn: (record) => record.diskwrite,
invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Write`} Icon={HardDriveIcon} />,
cell: ({ getValue }) => {
const val = getValue() as number
const formatted = formatBytes(val, false, undefined, false)
return <span className="ms-1 tabular-nums">{`${toFixedFloat(formatted.value, 2)} ${formatted.unit}`}</span>
},
},
{
id: "netin",
accessorFn: (record) => record.netin,
invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Download`} Icon={EthernetIcon} />,
cell: ({ getValue }) => {
const val = getValue() as number
const formatted = formatBytes(val, false, undefined, false)
return ( return (
<span className="ms-1.5 tabular-nums">{`${decimalString(formatted.value, formatted.value >= 10 ? 1 : 2)} ${formatted.unit}`}</span> <span className="ms-1 tabular-nums">{`${decimalString(formatted.value, formatted.value >= 10 ? 1 : 2)} ${formatted.unit}`}</span>
)
},
},
{
id: "netout",
accessorFn: (record) => record.netout,
invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Upload`} Icon={EthernetIcon} />,
cell: ({ getValue }) => {
const val = getValue() as number
const formatted = formatBytes(val, false, undefined, false)
return (
<span className="ms-1 tabular-nums">{`${decimalString(formatted.value, formatted.value >= 10 ? 1 : 2)} ${formatted.unit}`}</span>
) )
}, },
}, },
{ {
id: "maxcpu", id: "maxcpu",
accessorFn: (record) => record.maxcpu, accessorFn: (record) => record.maxcpu,
header: ({ column }) => <HeaderButton column={column} name={t`vCPUs`} Icon={CpuIcon} />, header: ({ column }) => <HeaderButton column={column} name="vCPUs" Icon={CpuIcon} />,
invertSorting: true, invertSorting: true,
cell: ({ getValue }) => { cell: ({ getValue }) => {
return <span className="ms-1.5 tabular-nums">{getValue() as number}</span> return <span className="ms-1 tabular-nums">{getValue() as number}</span>
},
},
{
id: "maxmem",
accessorFn: (record) => record.maxmem,
header: ({ column }) => <HeaderButton column={column} name={t`Max Mem`} Icon={MemoryStickIcon} />,
invertSorting: true,
cell: ({ getValue }) => {
// maxmem is stored in bytes; convert to MB for formatBytes
const formatted = formatBytes(getValue() as number, false, undefined, false)
return <span className="ms-1.5 tabular-nums">{`${toFixedFloat(formatted.value, 2)} ${formatted.unit}`}</span>
}, },
}, },
{ {
@@ -136,7 +181,7 @@ export const pveVmCols: ColumnDef<PveVmRecord>[] = [
invertSorting: true, invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Uptime`} Icon={TimerIcon} />, header: ({ column }) => <HeaderButton column={column} name={t`Uptime`} Icon={TimerIcon} />,
cell: ({ getValue }) => { cell: ({ getValue }) => {
return <span className="ms-1.5 w-25 block truncate">{formatUptime(getValue() as number)}</span> return <span className="ms-1">{formatUptime(getValue() as number)}</span>
}, },
}, },
{ {
@@ -146,7 +191,7 @@ export const pveVmCols: ColumnDef<PveVmRecord>[] = [
header: ({ column }) => <HeaderButton column={column} name={t`Updated`} Icon={ClockIcon} />, header: ({ column }) => <HeaderButton column={column} name={t`Updated`} Icon={ClockIcon} />,
cell: ({ getValue }) => { cell: ({ getValue }) => {
const timestamp = getValue() as number const timestamp = getValue() as number
return <span className="ms-1.5 tabular-nums">{hourWithSeconds(new Date(timestamp).toISOString())}</span> return <span className="ms-1 tabular-nums">{hourWithSeconds(new Date(timestamp).toISOString())}</span>
}, },
}, },
] ]
@@ -164,7 +209,7 @@ function HeaderButton({ column, name, Icon }: { column: Column<PveVmRecord>; nam
> >
{Icon && <Icon className="size-4" />} {Icon && <Icon className="size-4" />}
{name} {name}
<ArrowUpDownIcon className="size-4" /> {/* <ArrowUpDownIcon className="size-4" /> */}
</Button> </Button>
) )
} }

View File

@@ -46,7 +46,6 @@ export default function PveTable({ systemId }: { systemId?: string }) {
function fetchData(systemId?: string) { function fetchData(systemId?: string) {
pb.collection<PveVmRecord>("pve_vms") pb.collection<PveVmRecord>("pve_vms")
.getList(0, 2000, { .getList(0, 2000, {
fields: "id,name,type,cpu,mem,net,maxcpu,maxmem,uptime,system,updated",
filter: systemId ? pb.filter("system={:system}", { system: systemId }) : undefined, filter: systemId ? pb.filter("system={:system}", { system: systemId }) : undefined,
}) })
.then(({ items }) => { .then(({ items }) => {
@@ -145,7 +144,7 @@ export default function PveTable({ systemId }: { systemId?: string }) {
<div className="grid md:flex gap-5 w-full items-end"> <div className="grid md:flex gap-5 w-full items-end">
<div className="px-2 sm:px-1"> <div className="px-2 sm:px-1">
<CardTitle className="mb-2"> <CardTitle className="mb-2">
<Trans>All Proxmox VMs</Trans> <Trans>Proxmox Resources</Trans>
</CardTitle> </CardTitle>
<CardDescription className="flex"> <CardDescription className="flex">
<Trans>CPU is percent of overall host CPU usage.</Trans> <Trans>CPU is percent of overall host CPU usage.</Trans>
@@ -259,7 +258,11 @@ function PveVmSheet({
const memFormatted = formatBytes(vm.mem, false, undefined, true) const memFormatted = formatBytes(vm.mem, false, undefined, true)
const maxMemFormatted = formatBytes(vm.maxmem, false, undefined, false) const maxMemFormatted = formatBytes(vm.maxmem, false, undefined, false)
const netFormatted = formatBytes(vm.net, true, undefined, false) const netoutFormatted = formatBytes(vm.netout, false, undefined, false)
const netinFormatted = formatBytes(vm.netin, false, undefined, false)
const diskReadFormatted = formatBytes(vm.diskread, false, undefined, false)
const diskWriteFormatted = formatBytes(vm.diskwrite, false, undefined, false)
const diskFormatted = formatBytes(vm.disk, false, undefined, false)
return ( return (
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}> <Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
@@ -294,9 +297,14 @@ function PveVmSheet({
<dd className="tabular-nums">{`${decimalString(memFormatted.value, memFormatted.value >= 10 ? 1 : 2)} ${memFormatted.unit}`}</dd> <dd className="tabular-nums">{`${decimalString(memFormatted.value, memFormatted.value >= 10 ? 1 : 2)} ${memFormatted.unit}`}</dd>
<dt className="text-muted-foreground"> <dt className="text-muted-foreground">
<Trans>Network</Trans> <Trans>Upload</Trans>
</dt> </dt>
<dd className="tabular-nums">{`${decimalString(netFormatted.value, netFormatted.value >= 10 ? 1 : 2)} ${netFormatted.unit}`}</dd> <dd className="tabular-nums">{`${decimalString(netoutFormatted.value, netoutFormatted.value >= 10 ? 1 : 2)} ${netoutFormatted.unit}`}</dd>
<dt className="text-muted-foreground">
<Trans>Download</Trans>
</dt>
<dd className="tabular-nums">{`${decimalString(netinFormatted.value, netinFormatted.value >= 10 ? 1 : 2)} ${netinFormatted.unit}`}</dd>
<dt className="text-muted-foreground"> <dt className="text-muted-foreground">
<Trans>vCPUs</Trans> <Trans>vCPUs</Trans>
@@ -308,6 +316,21 @@ function PveVmSheet({
</dt> </dt>
<dd className="tabular-nums">{`${decimalString(maxMemFormatted.value, maxMemFormatted.value >= 10 ? 1 : 2)} ${maxMemFormatted.unit}`}</dd> <dd className="tabular-nums">{`${decimalString(maxMemFormatted.value, maxMemFormatted.value >= 10 ? 1 : 2)} ${maxMemFormatted.unit}`}</dd>
<dt className="text-muted-foreground">
<Trans>Disk Read</Trans>
</dt>
<dd className="tabular-nums">{`${decimalString(diskReadFormatted.value, diskReadFormatted.value >= 10 ? 1 : 2)} ${diskReadFormatted.unit}`}</dd>
<dt className="text-muted-foreground">
<Trans>Disk Write</Trans>
</dt>
<dd className="tabular-nums">{`${decimalString(diskWriteFormatted.value, diskWriteFormatted.value >= 10 ? 1 : 2)} ${diskWriteFormatted.unit}`}</dd>
<dt className="text-muted-foreground">
<Trans>Disk Size</Trans>
</dt>
<dd className="tabular-nums">{`${decimalString(diskFormatted.value, diskFormatted.value >= 10 ? 1 : 2)} ${diskFormatted.unit}`}</dd>
<dt className="text-muted-foreground"> <dt className="text-muted-foreground">
<Trans>Uptime</Trans> <Trans>Uptime</Trans>
</dt> </dt>

View File

@@ -285,14 +285,22 @@ export interface PveVmRecord extends RecordModel {
cpu: number cpu: number
/** Memory used (MB) */ /** Memory used (MB) */
mem: number mem: number
/** Network bandwidth (bytes/s, combined send+recv) */ /** Total upload (bytes, sent by VM) */
net: number netout: number
/** Total download (bytes, received by VM) */
netin: number
/** Max vCPU count */ /** Max vCPU count */
maxcpu: number maxcpu: number
/** Max memory (bytes) */ /** Max memory (bytes) */
maxmem: number maxmem: number
/** Uptime (seconds) */ /** Uptime (seconds) */
uptime: number uptime: number
/** Cumulative disk read (bytes) */
diskread: number
/** Cumulative disk write (bytes) */
diskwrite: number
/** Allocated disk size (bytes) */
disk: number
/** Unix timestamp (ms) */ /** Unix timestamp (ms) */
updated: number updated: number
} }
@@ -447,116 +455,116 @@ export interface SystemdRecord extends RecordModel {
} }
export interface SystemdServiceDetails { export interface SystemdServiceDetails {
AccessSELinuxContext: string; AccessSELinuxContext: string
ActivationDetails: any[]; ActivationDetails: any[]
ActiveEnterTimestamp: number; ActiveEnterTimestamp: number
ActiveEnterTimestampMonotonic: number; ActiveEnterTimestampMonotonic: number
ActiveExitTimestamp: number; ActiveExitTimestamp: number
ActiveExitTimestampMonotonic: number; ActiveExitTimestampMonotonic: number
ActiveState: string; ActiveState: string
After: string[]; After: string[]
AllowIsolate: boolean; AllowIsolate: boolean
AssertResult: boolean; AssertResult: boolean
AssertTimestamp: number; AssertTimestamp: number
AssertTimestampMonotonic: number; AssertTimestampMonotonic: number
Asserts: any[]; Asserts: any[]
Before: string[]; Before: string[]
BindsTo: any[]; BindsTo: any[]
BoundBy: any[]; BoundBy: any[]
CPUUsageNSec: number; CPUUsageNSec: number
CanClean: any[]; CanClean: any[]
CanFreeze: boolean; CanFreeze: boolean
CanIsolate: boolean; CanIsolate: boolean
CanLiveMount: boolean; CanLiveMount: boolean
CanReload: boolean; CanReload: boolean
CanStart: boolean; CanStart: boolean
CanStop: boolean; CanStop: boolean
CollectMode: string; CollectMode: string
ConditionResult: boolean; ConditionResult: boolean
ConditionTimestamp: number; ConditionTimestamp: number
ConditionTimestampMonotonic: number; ConditionTimestampMonotonic: number
Conditions: any[]; Conditions: any[]
ConflictedBy: any[]; ConflictedBy: any[]
Conflicts: string[]; Conflicts: string[]
ConsistsOf: any[]; ConsistsOf: any[]
DebugInvocation: boolean; DebugInvocation: boolean
DefaultDependencies: boolean; DefaultDependencies: boolean
Description: string; Description: string
Documentation: string[]; Documentation: string[]
DropInPaths: any[]; DropInPaths: any[]
ExecMainPID: number; ExecMainPID: number
FailureAction: string; FailureAction: string
FailureActionExitStatus: number; FailureActionExitStatus: number
Following: string; Following: string
FragmentPath: string; FragmentPath: string
FreezerState: string; FreezerState: string
Id: string; Id: string
IgnoreOnIsolate: boolean; IgnoreOnIsolate: boolean
InactiveEnterTimestamp: number; InactiveEnterTimestamp: number
InactiveEnterTimestampMonotonic: number; InactiveEnterTimestampMonotonic: number
InactiveExitTimestamp: number; InactiveExitTimestamp: number
InactiveExitTimestampMonotonic: number; InactiveExitTimestampMonotonic: number
InvocationID: string; InvocationID: string
Job: Array<number | string>; Job: Array<number | string>
JobRunningTimeoutUSec: number; JobRunningTimeoutUSec: number
JobTimeoutAction: string; JobTimeoutAction: string
JobTimeoutRebootArgument: string; JobTimeoutRebootArgument: string
JobTimeoutUSec: number; JobTimeoutUSec: number
JoinsNamespaceOf: any[]; JoinsNamespaceOf: any[]
LoadError: string[]; LoadError: string[]
LoadState: string; LoadState: string
MainPID: number; MainPID: number
Markers: any[]; Markers: any[]
MemoryCurrent: number; MemoryCurrent: number
MemoryLimit: number; MemoryLimit: number
MemoryPeak: number; MemoryPeak: number
NRestarts: number; NRestarts: number
Names: string[]; Names: string[]
NeedDaemonReload: boolean; NeedDaemonReload: boolean
OnFailure: any[]; OnFailure: any[]
OnFailureJobMode: string; OnFailureJobMode: string
OnFailureOf: any[]; OnFailureOf: any[]
OnSuccess: any[]; OnSuccess: any[]
OnSuccessJobMode: string; OnSuccessJobMode: string
OnSuccessOf: any[]; OnSuccessOf: any[]
PartOf: any[]; PartOf: any[]
Perpetual: boolean; Perpetual: boolean
PropagatesReloadTo: any[]; PropagatesReloadTo: any[]
PropagatesStopTo: any[]; PropagatesStopTo: any[]
RebootArgument: string; RebootArgument: string
Refs: any[]; Refs: any[]
RefuseManualStart: boolean; RefuseManualStart: boolean
RefuseManualStop: boolean; RefuseManualStop: boolean
ReloadPropagatedFrom: any[]; ReloadPropagatedFrom: any[]
RequiredBy: any[]; RequiredBy: any[]
Requires: string[]; Requires: string[]
RequiresMountsFor: any[]; RequiresMountsFor: any[]
Requisite: any[]; Requisite: any[]
RequisiteOf: any[]; RequisiteOf: any[]
Result: string; Result: string
SliceOf: any[]; SliceOf: any[]
SourcePath: string; SourcePath: string
StartLimitAction: string; StartLimitAction: string
StartLimitBurst: number; StartLimitBurst: number
StartLimitIntervalUSec: number; StartLimitIntervalUSec: number
StateChangeTimestamp: number; StateChangeTimestamp: number
StateChangeTimestampMonotonic: number; StateChangeTimestampMonotonic: number
StopPropagatedFrom: any[]; StopPropagatedFrom: any[]
StopWhenUnneeded: boolean; StopWhenUnneeded: boolean
SubState: string; SubState: string
SuccessAction: string; SuccessAction: string
SuccessActionExitStatus: number; SuccessActionExitStatus: number
SurviveFinalKillSignal: boolean; SurviveFinalKillSignal: boolean
TasksCurrent: number; TasksCurrent: number
TasksMax: number; TasksMax: number
Transient: boolean; Transient: boolean
TriggeredBy: string[]; TriggeredBy: string[]
Triggers: any[]; Triggers: any[]
UnitFilePreset: string; UnitFilePreset: string
UnitFileState: string; UnitFileState: string
UpheldBy: any[]; UpheldBy: any[]
Upholds: any[]; Upholds: any[]
WantedBy: any[]; WantedBy: any[]
Wants: string[]; Wants: string[]
WantsMountsFor: any[]; WantsMountsFor: any[]
} }