ton of improvements to checks

This commit is contained in:
wh1te909
2020-04-05 09:58:04 +00:00
parent 87d4b126e5
commit a7ee28cb8f
5 changed files with 299 additions and 160 deletions

View File

@@ -1,29 +1,35 @@
<template>
<div class="q-pa-sm">
<q-table
dense
class="agents-tbl-sticky"
:data="filter"
:columns="columns"
row-key="id"
binary-state-sort
:pagination.sync="pagination"
<q-table
dense
class="agents-tbl-sticky"
:data="filter"
:columns="columns"
row-key="id"
binary-state-sort
:pagination.sync="pagination"
hide-bottom
>
>
<!-- header slots -->
<template v-slot:header-cell-smsalert="props">
<q-th auto-width :props="props">
<q-icon name="phone_android" size="1.5em"><q-tooltip>SMS Alert</q-tooltip></q-icon>
<q-icon name="phone_android" size="1.5em">
<q-tooltip>SMS Alert</q-tooltip>
</q-icon>
</q-th>
</template>
<template v-slot:header-cell-emailalert="props">
<q-th auto-width :props="props">
<q-icon name="email" size="1.5em"><q-tooltip>Email Alert</q-tooltip></q-icon>
<q-icon name="email" size="1.5em">
<q-tooltip>Email Alert</q-tooltip>
</q-icon>
</q-th>
</template>
<template v-slot:header-cell-patchespending="props">
<q-th auto-width :props="props">
<q-icon name="system_update_alt" size="1.5em" color="warning"><q-tooltip>Patches Pending</q-tooltip></q-icon>
<q-icon name="system_update_alt" size="1.5em" color="warning">
<q-tooltip>Patches Pending</q-tooltip>
</q-icon>
</q-th>
</template>
<!--
@@ -31,10 +37,12 @@
<q-th auto-width :props="props">
<q-icon name="fas fa-shield-alt" size="1.2em" color="primary"><q-tooltip>Anti Virus</q-tooltip></q-icon>
</q-th>
</template> -->
</template>-->
<template v-slot:header-cell-agentstatus="props">
<q-th auto-width :props="props">
<q-icon name="fas fa-signal" size="1.2em" color="accent"><q-tooltip>Agent Status</q-tooltip></q-icon>
<q-icon name="fas fa-signal" size="1.2em" color="accent">
<q-tooltip>Agent Status</q-tooltip>
</q-icon>
</q-th>
</template>
<!-- body slots -->
@@ -50,8 +58,8 @@
<q-menu context-menu>
<q-list dense style="min-width: 200px">
<q-item clickable v-close-popup @click="showEditAgentModal = true">
<q-item-section avatar>
<q-icon name="fas fa-edit" />
<q-item-section side>
<q-icon size="xs" name="fas fa-edit" />
</q-item-section>
<q-item-section>Edit {{ props.row.hostname }}</q-item-section>
</q-item>
@@ -63,8 +71,8 @@
v-close-popup
@click.stop.prevent="takeControl(props.row.id)"
>
<q-item-section avatar>
<q-icon name="fas fa-desktop" />
<q-item-section side>
<q-icon size="xs" name="fas fa-desktop" />
</q-item-section>
<q-item-section>Take Control</q-item-section>
@@ -76,25 +84,25 @@
v-close-popup
@click="toggleSendCommand(props.row.id, props.row.hostname)"
>
<q-item-section avatar>
<q-icon name="fas fa-terminal" />
<q-item-section side>
<q-icon size="xs" name="fas fa-terminal" />
</q-item-section>
<q-item-section>Send Command</q-item-section>
</q-item>
<q-separator />
<q-item clickable v-close-popup @click.stop.prevent="remoteBG(props.row.id)">
<q-item-section avatar>
<q-icon name="fas fa-cogs" />
<q-item-section side>
<q-icon size="xs" name="fas fa-cogs" />
</q-item-section>
<q-item-section>Remote Background</q-item-section>
</q-item>
<!-- patch management -->
<q-separator />
<q-item clickable>
<q-item-section avatar>
<q-icon name="system_update" />
<q-item-section side>
<q-icon size="xs" name="system_update" />
</q-item-section>
<q-item-section>Patch Management</q-item-section>
<q-item-section side>
@@ -113,13 +121,19 @@
</q-item>
</q-list>
</q-menu>
</q-item>
<q-separator />
<q-item clickable v-close-popup @click.stop.prevent="runChecks(props.row.id)">
<q-item-section side>
<q-icon size="xs" name="fas fa-check-double" />
</q-item-section>
<q-item-section>Run Checks</q-item-section>
</q-item>
<q-separator />
<q-item clickable>
<q-item-section avatar>
<q-icon name="power_settings_new" />
<q-item-section side>
<q-icon size="xs" name="power_settings_new" />
</q-item-section>
<q-item-section>Reboot</q-item-section>
<q-item-section side>
@@ -151,14 +165,20 @@
</q-item>
<q-separator />
<q-item clickable v-close-popup @click.stop.prevent="removeAgent(props.row.id, props.row.hostname)">
<q-item-section avatar><q-icon name="delete" /></q-item-section>
<q-item
clickable
v-close-popup
@click.stop.prevent="removeAgent(props.row.id, props.row.hostname)"
>
<q-item-section side>
<q-icon size="xs" name="delete" />
</q-item-section>
<q-item-section>Remove Agent</q-item-section>
</q-item>
<q-separator />
<q-item clickable v-close-popup>
<q-item-section>Quit</q-item-section>
<q-item-section>Close</q-item-section>
</q-item>
</q-list>
</q-menu>
@@ -199,12 +219,20 @@
<q-tooltip>{{ props.row.antivirus }}</q-tooltip>
</q-icon>
<q-icon v-else name="fas fa-times-circle" color="negative" />
</q-td> -->
</q-td>-->
<q-td key="agentstatus">
<q-icon v-if="props.row.status ==='overdue'" name="fas fa-exclamation-triangle" color="negative">
<q-icon
v-if="props.row.status ==='overdue'"
name="fas fa-exclamation-triangle"
color="negative"
>
<q-tooltip>Agent overdue</q-tooltip>
</q-icon>
<q-icon v-else-if="props.row.status ==='offline'" name="fas fa-exclamation-triangle" color="grey-8">
<q-icon
v-else-if="props.row.status ==='offline'"
name="fas fa-exclamation-triangle"
color="grey-8"
>
<q-tooltip>Agent offline</q-tooltip>
</q-icon>
<q-icon v-else name="fas fa-check" color="positive">
@@ -215,7 +243,6 @@
<q-td key="boottime" :props="props">{{ bootTime(props.row.boot_time) }}</q-td>
</q-tr>
</template>
</q-table>
<q-inner-loading :showing="agentTableLoading">
<q-spinner size="40px" color="primary" />
@@ -260,7 +287,7 @@ import EditAgent from "@/components/modals/agents/EditAgent";
export default {
name: "AgentTable",
props: ["frame", "columns", "tab", "filter", "userName"],
components: {EditAgent},
components: { EditAgent },
mixins: [mixins],
data() {
return {
@@ -282,18 +309,18 @@ export default {
this.$store.commit("setActiveRow", pk);
this.$q.loading.show();
// give time for store to change active row
setTimeout(()=>{
setTimeout(() => {
this.$q.loading.hide();
this.showEditAgentModal = true;
}, 500);
},
runPatchStatusScan(pk, hostname) {
axios.get(`/winupdate/${pk}/runupdatescan/`).then(r => {
this.notifySuccess(`Scan will be run shortly on ${hostname}`)
})
axios.get(`/winupdate/${pk}/runupdatescan/`).then(r => {
this.notifySuccess(`Scan will be run shortly on ${hostname}`);
});
},
agentEdited() {
this.$emit("refreshEdit")
this.$emit("refreshEdit");
},
takeControl(pk) {
const url = this.$router.resolve(`/takecontrol/${pk}`).href;
@@ -311,44 +338,55 @@ export default {
"scrollbars=no,location=no,status=no,toolbar=no,menubar=no,width=1280,height=826"
);
},
runChecks(pk) {
axios
.get(`/checks/runchecks/${pk}/`)
.then(r => this.notifySuccess(`Checks will now be re-run on ${r.data}`))
.catch(e => this.notifyError("Something went wrong"));
},
removeAgent(pk, hostname) {
this.$q.dialog({
title: "Are you sure?",
message: `Delete agent ${hostname}`,
cancel: true,
persistent: true
})
.onOk(() => {
this.$q.dialog({
title: `Please type <code style="color:red">${hostname}</code> to confirm`,
prompt: {model: '', type: 'text'},
this.$q
.dialog({
title: "Are you sure?",
message: `Delete agent ${hostname}`,
cancel: true,
persistent: true,
html: true
}).onOk((hostnameConfirm) => {
if (hostnameConfirm !== hostname) {
this.$q.notify({
message: "ERROR: Please type the correct hostname",
color: "red"
})
} else {
const data = {pk: pk};
axios.delete("/agents/uninstallagent/", {data: data}).then(r => {
this.$q.notify({
message: `${hostname} will now be uninstalled!`,
color: "green"
})
})
.catch(e => {
this.$q.notify({
message: e.response.data.error,
color: "info",
timeout: 4000
})
})
}
persistent: true
})
})
.onOk(() => {
this.$q
.dialog({
title: `Please type <code style="color:red">${hostname}</code> to confirm`,
prompt: { model: "", type: "text" },
cancel: true,
persistent: true,
html: true
})
.onOk(hostnameConfirm => {
if (hostnameConfirm !== hostname) {
this.$q.notify({
message: "ERROR: Please type the correct hostname",
color: "red"
});
} else {
const data = { pk: pk };
axios
.delete("/agents/uninstallagent/", { data: data })
.then(r => {
this.$q.notify({
message: `${hostname} will now be uninstalled!`,
color: "green"
});
})
.catch(e => {
this.$q.notify({
message: e.response.data.error,
color: "info",
timeout: 4000
});
});
}
});
});
},
rebootNow(pk, hostname) {
this.$q
@@ -370,7 +408,7 @@ export default {
},
rebootLater() {
// TODO implement this
console.log('reboot later')
console.log("reboot later");
},
toggleSendCommand(pk, hostname) {
this.sendCommandToggle = true;
@@ -436,12 +474,12 @@ export default {
});
},
agentClass(status) {
if (status === 'offline') {
return 'agent-offline'
} else if (status === 'overdue') {
return 'agent-overdue'
if (status === "offline") {
return "agent-offline";
} else if (status === "overdue") {
return "agent-overdue";
} else {
return 'agent-normal'
return "agent-normal";
}
}
},
@@ -477,11 +515,13 @@ export default {
.highlight {
background-color: #c9e6ff;
}
.agent-offline {
background: gray !important
background: gray !important;
}
.agent-overdue {
background: red !important
background: red !important;
}
</style>

View File

@@ -6,21 +6,39 @@
<q-menu>
<q-list dense style="min-width: 200px">
<q-item clickable v-close-popup @click="showAddDiskSpaceCheck = true">
<q-item-section side>
<q-icon size="xs" name="far fa-hdd" />
</q-item-section>
<q-item-section>Disk Space Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddPingCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-network-wired" />
</q-item-section>
<q-item-section>Ping Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddCpuLoadCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-microchip" />
</q-item-section>
<q-item-section>CPU Load Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddMemCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-memory" />
</q-item-section>
<q-item-section>Memory Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddWinSvcCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-cogs" />
</q-item-section>
<q-item-section>Windows Service Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddScriptCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-terminal" />
</q-item-section>
<q-item-section>Script Check</q-item-section>
</q-item>
</q-list>
@@ -91,15 +109,15 @@
<q-td>
<q-checkbox
dense
@input="checkAlertAction(props.row.id, props.row.check_type, 'email', props.row.email_alert)"
v-model="props.row.email_alert"
@input="checkAlertAction(props.row.id, props.row.check_type, 'text', props.row.text_alert)"
v-model="props.row.text_alert"
/>
</q-td>
<q-td>
<q-checkbox
dense
@input="checkAlertAction(props.row.id, props.row.check_type, 'text', props.row.text_alert)"
v-model="props.row.text_alert"
@input="checkAlertAction(props.row.id, props.row.check_type, 'email', props.row.email_alert)"
v-model="props.row.email_alert"
/>
</q-td>
<q-td v-if="props.row.status === 'pending'"></q-td>
@@ -143,7 +161,7 @@
<q-td v-else-if="props.row.check_type === 'script'">
<span
style="cursor:pointer;color:blue;text-decoration:underline"
@click="moreInfo('Script Check', props.row.more_info)"
@click="scriptMoreInfo(props.row)"
>output</span>
</q-td>
<q-td v-else>{{ props.row.more_info }}</q-td>
@@ -217,6 +235,9 @@
:agentpk="checks.pk"
/>
</q-dialog>
<q-dialog v-model="showScriptOutput">
<ScriptOutput @close="showScriptOutput = false; scriptInfo = {}" :scriptInfo="scriptInfo" />
</q-dialog>
</div>
</template>
@@ -236,6 +257,7 @@ import AddWinSvcCheck from "@/components/modals/checks/AddWinSvcCheck";
import EditWinSvcCheck from "@/components/modals/checks/EditWinSvcCheck";
import AddScriptCheck from "@/components/modals/checks/AddScriptCheck";
import EditScriptCheck from "@/components/modals/checks/EditScriptCheck";
import ScriptOutput from "@/components/modals/checks/ScriptOutput";
export default {
name: "ChecksTab",
@@ -251,7 +273,8 @@ export default {
AddWinSvcCheck,
EditWinSvcCheck,
AddScriptCheck,
EditScriptCheck
EditScriptCheck,
ScriptOutput
},
mixins: [mixins],
data() {
@@ -268,7 +291,9 @@ export default {
showEditWinSvcCheck: false,
showAddScriptCheck: false,
showEditScriptCheck: false,
showScriptOutput: false,
editCheckPK: null,
scriptInfo: {},
columns: [
{ name: "smsalert", field: "text_alert", align: "left" },
{ name: "emailalert", field: "email_alert", align: "left" },
@@ -317,12 +342,16 @@ export default {
moreInfo(name, output) {
this.$q.dialog({
title: `${name} output`,
style: "width: 80vw; max-width: 90vw",
style: "width: 35vw; max-width: 50vw",
message: `<pre>${output}</pre>`,
html: true,
dark: true
});
},
scriptMoreInfo(props) {
this.scriptInfo = props;
this.showScriptOutput = true;
},
editCheck(category) {
switch (category) {
case "diskspace":

View File

@@ -1,38 +1,47 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add Disk Space Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add Disk Space Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="addCheck">
<q-card-section>
<q-select outlined v-model="firstdisk" :options="disks" label="Disk" />
</q-card-section>
<q-card-section>
<q-input
outlined
v-model.number="threshold"
label="Threshold (%)"
:rules="[
<q-form @submit.prevent="addCheck">
<q-card-section>
<q-select outlined v-model="firstdisk" :options="disks" label="Disk" />
</q-card-section>
<q-card-section>
<q-input
outlined
v-model.number="threshold"
label="Threshold (%)"
:rules="[
val => !!val || '*Required',
val => val >= 1 || 'Minimum threshold is 1',
val => val < 100 || 'Maximum threshold is 99'
]"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn label="Add" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
</q-card>
/>
</q-card-section>
<q-card-section>
<q-select
outlined
dense
v-model="failure"
:options="failures"
label="Number of consecutive failures before alert"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn label="Add" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
</q-card>
</template>
<script>
import axios from "axios";
import { mapState } from 'vuex';
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "AddDiskSpaceCheck",
@@ -42,22 +51,25 @@ export default {
return {
threshold: 25,
disks: [],
firstdisk: ""
firstdisk: "",
failure: 1,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getDisks() {
axios.get(`/checks/getdisks/${this.agentpk}/`).then(r => {
this.disks = Object.keys(r.data);
this.firstdisk = Object.keys(r.data)[0];
})
axios.get(`/checks/getdisks/${this.agentpk}/`).then(r => {
this.disks = Object.keys(r.data);
this.firstdisk = Object.keys(r.data)[0];
});
},
addCheck() {
const data = {
pk: this.agentpk,
check_type: "diskspace",
disk: this.firstdisk,
threshold: this.threshold
threshold: this.threshold,
failure: this.failure
};
axios
.post("/checks/addstandardcheck/", data)
@@ -70,7 +82,7 @@ export default {
}
},
mounted() {
this.getDisks()
this.getDisks();
}
};
</script>

View File

@@ -1,33 +1,42 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Edit Disk Space Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Edit Disk Space Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="editCheck">
<q-card-section>
<q-select outlined disable v-model="diskToEdit" :options="disks" label="Disk" />
</q-card-section>
<q-card-section>
<q-input
outlined
v-model.number="threshold"
label="Threshold (%)"
:rules="[
<q-form @submit.prevent="editCheck">
<q-card-section>
<q-select outlined disable v-model="diskToEdit" :options="disks" label="Disk" />
</q-card-section>
<q-card-section>
<q-input
outlined
v-model.number="threshold"
label="Threshold (%)"
:rules="[
val => !!val || '*Required',
val => val >= 1 || 'Minimum threshold is 1',
val => val < 100 || 'Maximum threshold is 99'
]"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn label="Edit" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
</q-card>
/>
</q-card-section>
<q-card-section>
<q-select
outlined
dense
v-model="failure"
:options="failures"
label="Number of consecutive failures before alert"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn label="Edit" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
</q-card>
</template>
<script>
@@ -41,34 +50,41 @@ export default {
return {
threshold: null,
disks: [],
diskToEdit: ""
diskToEdit: "",
failure: null,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getCheck() {
axios.get(`/checks/getstandardcheck/diskspace/${this.editCheckPK}/`).then(r => {
axios
.get(`/checks/getstandardcheck/diskspace/${this.editCheckPK}/`)
.then(r => {
this.disks = [r.data.disk];
this.diskToEdit = r.data.disk;
this.threshold = r.data.threshold;
})
this.failure = r.data.failures;
});
},
editCheck() {
const data = {
check_type: "diskspace",
pk: this.editCheckPK,
threshold: this.threshold
}
axios.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
this.$store.dispatch("loadChecks", this.agentpk);
this.notifySuccess("Disk space check was edited!")
})
.catch(e => this.notifyError(e.response.data.error));
threshold: this.threshold,
failures: this.failure
};
axios
.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
this.$store.dispatch("loadChecks", this.agentpk);
this.notifySuccess("Disk space check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));
}
},
mounted() {
this.getCheck()
this.getCheck();
}
};
</script>

View File

@@ -0,0 +1,42 @@
<template>
<q-card style="min-width: 700px" class="q-pa-xs">
<q-card-section>
<div class="row items-center">
<div class="text-h6">{{ scriptInfo.script.name }}</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</div>
<div>
Last Run:
<code>{{ scriptInfo.last_run }}</code>
<br />Run Time:
<code>{{ scriptInfo.execution_time}} seconds</code>
<br />Return Code:
<code>{{ scriptInfo.retcode }}</code>
<br />
</div>
<div v-if="scriptInfo.stdout">
Standard Output:
<q-scroll-area style="height: 200px; max-height: 500px;">
<pre>{{ scriptInfo.stdout }}</pre>
</q-scroll-area>
</div>
<div v-if="scriptInfo.stderr">
Standard Error:
<q-scroll-area style="height: 200px; max-height: 500px;">
<pre>{{ scriptInfo.stderr }}</pre>
</q-scroll-area>
</div>
</q-card-section>
</q-card>
</template>
<script>
export default {
name: "ScriptOutput",
props: ["scriptInfo"],
beforeDestroy() {
this.$emit("close");
}
};
</script>