add total cpu/ram and fix race condition with polling interval for process manager closes amidaware/tacticalrmm#2037
This commit is contained in:
@@ -17,70 +17,85 @@
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
>
|
>
|
||||||
<template v-slot:top>
|
<template v-slot:top>
|
||||||
<q-btn
|
<div class="q-gutter-md flex flex-center items-center">
|
||||||
v-if="isPolling"
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
push
|
|
||||||
@click="stopPoll"
|
|
||||||
icon="stop"
|
|
||||||
label="Stop Live Refresh"
|
|
||||||
/>
|
|
||||||
<q-btn
|
|
||||||
v-else
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
push
|
|
||||||
@click="startPoll"
|
|
||||||
icon="play_arrow"
|
|
||||||
label="Resume Live Refresh"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<q-space />
|
|
||||||
|
|
||||||
<div class="q-pa-md q-gutter-sm">
|
|
||||||
<q-btn
|
<q-btn
|
||||||
:disable="pollInterval === 1"
|
v-if="isPolling"
|
||||||
dense
|
dense
|
||||||
@click="pollIntervalChanged('subtract')"
|
flat
|
||||||
push
|
push
|
||||||
icon="remove"
|
@click="stopPoll"
|
||||||
size="sm"
|
icon="stop"
|
||||||
color="grey"
|
label="Stop Live Refresh"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-else
|
||||||
dense
|
dense
|
||||||
|
flat
|
||||||
push
|
push
|
||||||
icon="add"
|
@click="startPoll"
|
||||||
size="sm"
|
icon="play_arrow"
|
||||||
color="grey"
|
label="Resume Live Refresh"
|
||||||
@click="pollIntervalChanged('add')"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div class="text-overline">
|
|
||||||
<q-badge
|
|
||||||
align="middle"
|
|
||||||
size="sm"
|
|
||||||
class="text-h6"
|
|
||||||
color="blue"
|
|
||||||
:label="pollInterval"
|
|
||||||
/>
|
|
||||||
Refresh interval (seconds)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<q-space />
|
<div class="flex flex-center q-ml-md">
|
||||||
<q-input v-model="filter" outlined label="Search" dense clearable>
|
<q-icon name="fas fa-microchip" class="q-mr-xs" />
|
||||||
<template v-slot:prepend>
|
<div class="text-caption q-mr-sm">
|
||||||
<q-icon name="search" />
|
CPU Usage:
|
||||||
</template>
|
<span class="text-body1 text-weight-medium"
|
||||||
</q-input>
|
>{{ totalCpuUsage }}%</span
|
||||||
<!-- file download doesn't work so disabling -->
|
>
|
||||||
<export-table-btn
|
</div>
|
||||||
v-show="false"
|
|
||||||
class="q-ml-sm"
|
<q-icon name="fas fa-memory" class="q-mr-xs" />
|
||||||
:columns="columns"
|
<div class="text-caption">
|
||||||
:data="processes"
|
RAM Usage:
|
||||||
/>
|
<span class="text-body1 text-weight-medium"
|
||||||
|
>{{ bytes2Human(totalRamUsage) }}/{{ total_ram }} GB</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-space />
|
||||||
|
|
||||||
|
<div class="q-pa-md q-gutter-sm">
|
||||||
|
<q-btn
|
||||||
|
:disable="pollInterval === 1"
|
||||||
|
dense
|
||||||
|
@click="pollIntervalChanged('subtract')"
|
||||||
|
push
|
||||||
|
icon="remove"
|
||||||
|
size="sm"
|
||||||
|
color="grey"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
push
|
||||||
|
icon="add"
|
||||||
|
size="sm"
|
||||||
|
color="grey"
|
||||||
|
@click="pollIntervalChanged('add')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-overline">
|
||||||
|
<q-badge
|
||||||
|
align="middle"
|
||||||
|
size="sm"
|
||||||
|
class="text-h6"
|
||||||
|
color="blue"
|
||||||
|
:label="pollInterval"
|
||||||
|
/>
|
||||||
|
Refresh interval (seconds)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-space />
|
||||||
|
|
||||||
|
<q-input v-model="filter" outlined label="Search" dense clearable>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body="props">
|
<template v-slot:body="props">
|
||||||
<q-tr :props="props" class="cursor-pointer">
|
<q-tr :props="props" class="cursor-pointer">
|
||||||
@@ -121,9 +136,6 @@ import {
|
|||||||
import { bytes2Human } from "@/utils/format";
|
import { bytes2Human } from "@/utils/format";
|
||||||
import { notifySuccess } from "@/utils/notify";
|
import { notifySuccess } from "@/utils/notify";
|
||||||
|
|
||||||
// ui imports
|
|
||||||
import ExportTableBtn from "@/components/ui/ExportTableBtn.vue";
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
name: "name",
|
name: "name",
|
||||||
@@ -164,7 +176,6 @@ const columns = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { ExportTableBtn },
|
|
||||||
name: "ProcessManager",
|
name: "ProcessManager",
|
||||||
props: {
|
props: {
|
||||||
agent_id: !String,
|
agent_id: !String,
|
||||||
@@ -175,52 +186,71 @@ export default {
|
|||||||
const poll = ref(null);
|
const poll = ref(null);
|
||||||
const isPolling = computed(() => !!poll.value);
|
const isPolling = computed(() => !!poll.value);
|
||||||
|
|
||||||
async function startPoll() {
|
function startPoll() {
|
||||||
await getProcesses();
|
stopPoll();
|
||||||
if (processes.value.length > 0) {
|
getProcesses();
|
||||||
refreshProcesses();
|
poll.value = setInterval(() => {
|
||||||
}
|
getProcesses();
|
||||||
|
}, pollInterval.value * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopPoll() {
|
function stopPoll() {
|
||||||
clearInterval(poll.value);
|
if (poll.value) {
|
||||||
poll.value = null;
|
clearInterval(poll.value);
|
||||||
|
poll.value = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function pollIntervalChanged(action) {
|
function pollIntervalChanged(action) {
|
||||||
if (action === "subtract" && pollInterval.value <= 1) {
|
|
||||||
stopPoll();
|
|
||||||
startPoll();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action === "add") {
|
if (action === "add") {
|
||||||
pollInterval.value++;
|
pollInterval.value++;
|
||||||
} else {
|
} else if (action === "subtract" && pollInterval.value > 1) {
|
||||||
pollInterval.value--;
|
pollInterval.value--;
|
||||||
}
|
}
|
||||||
stopPoll();
|
if (isPolling.value) {
|
||||||
startPoll();
|
startPoll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process manager logic
|
// process manager logic
|
||||||
const processes = ref([]);
|
const processes = ref([]);
|
||||||
const filter = ref("");
|
const filter = ref("");
|
||||||
const memory = ref(null);
|
const total_ram = ref(0);
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const totalCpuUsage = computed(() => {
|
||||||
|
if (!Array.isArray(processes.value) || processes.value.length === 0) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = processes.value.reduce((acc, proc) => {
|
||||||
|
const cpuPercent = parseFloat(proc.cpu_percent);
|
||||||
|
|
||||||
|
if (isNaN(cpuPercent)) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc + cpuPercent;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
return total.toFixed(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalRamUsage = computed(() => {
|
||||||
|
return processes.value.reduce((acc, proc) => acc + proc.membytes, 0);
|
||||||
|
});
|
||||||
|
|
||||||
async function getProcesses() {
|
async function getProcesses() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
processes.value = await fetchAgentProcesses(props.agent_id);
|
try {
|
||||||
|
processes.value = await fetchAgentProcesses(props.agent_id);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshProcesses() {
|
|
||||||
poll.value = setInterval(() => {
|
|
||||||
getProcesses(props.agent_id);
|
|
||||||
}, pollInterval.value * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function killProcess(pid) {
|
async function killProcess(pid) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
let result = "";
|
let result = "";
|
||||||
@@ -235,11 +265,8 @@ export default {
|
|||||||
|
|
||||||
// lifecycle hooks
|
// lifecycle hooks
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
memory.value = await fetchAgent(props.agent_id).total_ram;
|
total_ram.value = (await fetchAgent(props.agent_id)).total_ram;
|
||||||
await getProcesses();
|
startPoll();
|
||||||
if (processes.value.length > 0) {
|
|
||||||
refreshProcesses();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => clearInterval(poll.value));
|
onBeforeUnmount(() => clearInterval(poll.value));
|
||||||
@@ -248,10 +275,12 @@ export default {
|
|||||||
// reactive data
|
// reactive data
|
||||||
processes,
|
processes,
|
||||||
filter,
|
filter,
|
||||||
memory,
|
total_ram,
|
||||||
isPolling,
|
isPolling,
|
||||||
pollInterval,
|
pollInterval,
|
||||||
loading,
|
loading,
|
||||||
|
totalCpuUsage,
|
||||||
|
totalRamUsage,
|
||||||
|
|
||||||
// non-reactive data
|
// non-reactive data
|
||||||
columns,
|
columns,
|
||||||
|
Reference in New Issue
Block a user