Merge branch 'refactor-checks' into develop

This commit is contained in:
wh1te909
2020-05-31 01:56:33 +00:00
39 changed files with 2081 additions and 2222 deletions

View File

@@ -81,7 +81,8 @@
<q-td v-if="props.row.last_run">{{ props.row.last_run }}</q-td>
<q-td v-else>Has not run yet</q-td>
<q-td>{{ props.row.schedule }}</q-td>
<q-td>{{ props.row.assigned_check }}</q-td>
<q-td v-if="props.row.assigned_check">{{ props.row.assigned_check.readable_desc }}</q-td>
<q-td v-else></q-td>
</q-tr>
</template>
</q-table>

View File

@@ -1,47 +1,47 @@
<template>
<div v-if="Object.keys(checks).length === 0">No agent selected</div>
<div v-if="checks === null">No agent selected</div>
<div class="row" v-else>
<div class="col-12">
<q-btn size="sm" color="grey-5" icon="fas fa-plus" label="Add Check" text-color="black">
<q-menu>
<q-list dense style="min-width: 200px">
<q-item clickable v-close-popup @click="showAddDiskSpaceCheck = true">
<q-item clickable v-close-popup @click="showCheck('add', 'diskspace')">
<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 clickable v-close-popup @click="showCheck('add', 'ping')">
<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 clickable v-close-popup @click="showCheck('add', 'cpuload')">
<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 clickable v-close-popup @click="showCheck('add', 'memory')">
<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 clickable v-close-popup @click="showCheck('add', 'winsvc')">
<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 clickable v-close-popup @click="showCheck('add', 'script')">
<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-item clickable v-close-popup @click="showAddEventLogCheck = true">
<q-item clickable v-close-popup @click="showCheck('add', 'eventlog')">
<q-item-section side>
<q-icon size="xs" name="fas fa-clipboard-list" />
</q-item-section>
@@ -50,15 +50,15 @@
</q-list>
</q-menu>
</q-btn>
<q-btn dense flat push @click="onRefresh(checks.pk)" icon="refresh" />
<template v-if="allChecks === undefined || allChecks.length === 0">
<q-btn dense flat push @click="onRefresh(selectedAgentPk)" icon="refresh" />
<template v-if="checks === undefined || checks.length === 0">
<p>No Checks</p>
</template>
<template v-else>
<q-table
dense
class="tabs-tbl-sticky"
:data="allChecks"
:data="checks"
:columns="columns"
:row-key="row => row.id + row.check_type"
binary-state-sort
@@ -85,11 +85,11 @@
</template>
<!-- body slots -->
<template slot="body" slot-scope="props" :props="props">
<q-tr @contextmenu="editCheckPK = props.row.id">
<q-tr @contextmenu="checkpk = props.row.id">
<!-- context menu -->
<q-menu context-menu>
<q-list dense style="min-width: 200px">
<q-item clickable v-close-popup @click="editCheck(props.row.check_type)">
<q-item clickable v-close-popup @click="showCheck('edit', props.row.check_type)">
<q-item-section side>
<q-icon name="edit" />
</q-item-section>
@@ -98,7 +98,7 @@
<q-item
clickable
v-close-popup
@click="deleteCheck(props.row.id, props.row.check_type)"
@click="deleteCheck(props.row.id, props.row.readable_desc)"
>
<q-item-section side>
<q-icon name="delete" />
@@ -112,20 +112,23 @@
</q-list>
</q-menu>
<!-- tds -->
<!-- text alert -->
<q-td>
<q-checkbox
dense
@input="checkAlertAction(props.row.id, props.row.check_type, 'text', props.row.text_alert)"
@input="checkAlert(props.row.id, 'Text', props.row.text_alert)"
v-model="props.row.text_alert"
/>
</q-td>
<!-- email alert -->
<q-td>
<q-checkbox
dense
@input="checkAlertAction(props.row.id, props.row.check_type, 'email', props.row.email_alert)"
@input="checkAlert(props.row.id, 'Email', props.row.email_alert)"
v-model="props.row.email_alert"
/>
</q-td>
<!-- status icon -->
<q-td v-if="props.row.status === 'pending'"></q-td>
<q-td v-else-if="props.row.status === 'passing'">
<q-icon style="font-size: 1.3rem;" color="positive" name="check_circle" />
@@ -133,27 +136,9 @@
<q-td v-else-if="props.row.status === 'failing'">
<q-icon style="font-size: 1.3rem;" color="negative" name="error" />
</q-td>
<q-td
v-if="props.row.check_type === 'diskspace'"
>Disk Space Drive {{ props.row.disk }} > {{props.row.threshold }}%</q-td>
<q-td
v-else-if="props.row.check_type === 'cpuload'"
>Avg CPU Load > {{ props.row.cpuload }}%</q-td>
<q-td
v-else-if="props.row.check_type === 'script'"
>Script check: {{ props.row.script.name }}</q-td>
<q-td
v-else-if="props.row.check_type === 'ping'"
>Ping {{ props.row.name }} ({{ props.row.ip }})</q-td>
<q-td
v-else-if="props.row.check_type === 'memory'"
>Avg memory usage > {{ props.row.threshold }}%</q-td>
<q-td
v-else-if="props.row.check_type === 'winsvc'"
>Service Check - {{ props.row.svc_display_name }}</q-td>
<q-td
v-else-if="props.row.check_type === 'eventlog'"
>Event Log Check - {{ props.row.desc }}</q-td>
<!-- check description -->
<q-td>{{ props.row.readable_desc }}</q-td>
<!-- status text -->
<q-td v-if="props.row.status === 'pending'">Awaiting First Synchronization</q-td>
<q-td v-else-if="props.row.status === 'passing'">
<q-badge color="positive">Passing</q-badge>
@@ -161,10 +146,11 @@
<q-td v-else-if="props.row.status === 'failing'">
<q-badge color="negative">Failing</q-badge>
</q-td>
<!-- more info -->
<q-td v-if="props.row.check_type === 'ping'">
<span
style="cursor:pointer;color:blue;text-decoration:underline"
@click="moreInfo('Ping', props.row.more_info)"
@click="pingInfo(props.row.readable_desc, props.row.more_info)"
>output</span>
</q-td>
<q-td v-else-if="props.row.check_type === 'script'">
@@ -179,92 +165,78 @@
@click="eventLogMoreInfo(props.row)"
>output</span>
</q-td>
<q-td
v-else-if="props.row.check_type === 'cpuload' || props.row.check_type === 'memory'"
>{{ props.row.history_info }}</q-td>
<q-td v-else>{{ props.row.more_info }}</q-td>
<q-td>{{ props.row.last_run }}</q-td>
<q-td>{{ props.row.assigned_task }}</q-td>
<q-td v-if="props.row.assigned_task">{{ props.row.assigned_task.name }}</q-td>
<q-td v-else></q-td>
</q-tr>
</template>
</q-table>
</template>
</div>
<!-- modals -->
<q-dialog v-model="showAddDiskSpaceCheck">
<AddDiskSpaceCheck @close="showAddDiskSpaceCheck = false" :agentpk="checks.pk" />
</q-dialog>
<q-dialog v-model="showEditDiskSpaceCheck">
<EditDiskSpaceCheck
@close="showEditDiskSpaceCheck = false"
:editCheckPK="editCheckPK"
:agentpk="checks.pk"
<q-dialog v-model="showDiskSpaceCheck">
<DiskSpaceCheck
@close="showDiskSpaceCheck = false"
:agentpk="selectedAgentPk"
:mode="mode"
:checkpk="checkpk"
/>
</q-dialog>
<q-dialog v-model="showAddPingCheck">
<AddPingCheck @close="showAddPingCheck = false" :agentpk="checks.pk" />
</q-dialog>
<q-dialog v-model="showEditPingCheck">
<EditPingCheck
@close="showEditPingCheck = false"
:editCheckPK="editCheckPK"
:agentpk="checks.pk"
<q-dialog v-model="showMemCheck">
<MemCheck
@close="showMemCheck = false"
:agentpk="selectedAgentPk"
:mode="mode"
:checkpk="checkpk"
/>
</q-dialog>
<q-dialog v-model="showAddCpuLoadCheck">
<AddCpuLoadCheck @close="showAddCpuLoadCheck = false" :agentpk="checks.pk" />
</q-dialog>
<q-dialog v-model="showEditCpuLoadCheck">
<EditCpuLoadCheck
@close="showEditCpuLoadCheck = false"
:editCheckPK="editCheckPK"
:agentpk="checks.pk"
<q-dialog v-model="showCpuLoadCheck">
<CpuLoadCheck
@close="showCpuLoadCheck = false"
:agentpk="selectedAgentPk"
:mode="mode"
:checkpk="checkpk"
/>
</q-dialog>
<q-dialog v-model="showAddMemCheck">
<AddMemCheck @close="showAddMemCheck = false" :agentpk="checks.pk" />
</q-dialog>
<q-dialog v-model="showEditMemCheck">
<EditMemCheck
@close="showEditMemCheck = false"
:editCheckPK="editCheckPK"
:agentpk="checks.pk"
<q-dialog v-model="showPingCheck">
<PingCheck
@close="showPingCheck = false"
:agentpk="selectedAgentPk"
:mode="mode"
:checkpk="checkpk"
/>
</q-dialog>
<q-dialog v-model="showAddWinSvcCheck">
<AddWinSvcCheck @close="showAddWinSvcCheck = false" :agentpk="checks.pk" />
</q-dialog>
<q-dialog v-model="showEditWinSvcCheck">
<EditWinSvcCheck
@close="showEditWinSvcCheck = false"
:editCheckPK="editCheckPK"
:agentpk="checks.pk"
<q-dialog v-model="showWinSvcCheck">
<WinSvcCheck
@close="showWinSvcCheck = false"
:agentpk="selectedAgentPk"
:mode="mode"
:checkpk="checkpk"
/>
</q-dialog>
<!-- script check -->
<q-dialog v-model="showAddScriptCheck">
<AddScriptCheck @close="showAddScriptCheck = false" :agentpk="checks.pk" />
<q-dialog v-model="showEventLogCheck">
<EventLogCheck
@close="showEventLogCheck = false"
:agentpk="selectedAgentPk"
:mode="mode"
:checkpk="checkpk"
/>
</q-dialog>
<q-dialog v-model="showEditScriptCheck">
<EditScriptCheck
@close="showEditScriptCheck = false"
:editCheckPK="editCheckPK"
:agentpk="checks.pk"
<q-dialog v-model="showScriptCheck">
<ScriptCheck
@close="showScriptCheck = false"
:agentpk="selectedAgentPk"
:mode="mode"
:checkpk="checkpk"
/>
</q-dialog>
<q-dialog v-model="showScriptOutput">
<ScriptOutput @close="showScriptOutput = false; scriptInfo = {}" :scriptInfo="scriptInfo" />
</q-dialog>
<!-- event log check -->
<q-dialog v-model="showAddEventLogCheck">
<AddEventLogCheck @close="showAddEventLogCheck = false" :agentpk="checks.pk" />
</q-dialog>
<q-dialog v-model="showEditEventLogCheck">
<EditEventLogCheck
@close="showEditEventLogCheck = false"
:editCheckPK="editCheckPK"
:agentpk="checks.pk"
/>
</q-dialog>
<q-dialog v-model="showEventLogOutput">
<EventLogCheckOutput
@close="showEventLogOutput = false; evtlogdata = {}"
@@ -276,65 +248,45 @@
<script>
import axios from "axios";
import { mapState } from "vuex";
import { mapState, mapGetters } from "vuex";
import mixins from "@/mixins/mixins";
import AddDiskSpaceCheck from "@/components/modals/checks/AddDiskSpaceCheck";
import EditDiskSpaceCheck from "@/components/modals/checks/EditDiskSpaceCheck";
import AddPingCheck from "@/components/modals/checks/AddPingCheck";
import EditPingCheck from "@/components/modals/checks/EditPingCheck";
import AddCpuLoadCheck from "@/components/modals/checks/AddCpuLoadCheck";
import EditCpuLoadCheck from "@/components/modals/checks/EditCpuLoadCheck";
import AddMemCheck from "@/components/modals/checks/AddMemCheck";
import EditMemCheck from "@/components/modals/checks/EditMemCheck";
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 DiskSpaceCheck from "@/components/modals/checks/DiskSpaceCheck";
import MemCheck from "@/components/modals/checks/MemCheck";
import CpuLoadCheck from "@/components/modals/checks/CpuLoadCheck";
import PingCheck from "@/components/modals/checks/PingCheck";
import WinSvcCheck from "@/components/modals/checks/WinSvcCheck";
import EventLogCheck from "@/components/modals/checks/EventLogCheck";
import ScriptCheck from "@/components/modals/checks/ScriptCheck";
import ScriptOutput from "@/components/modals/checks/ScriptOutput";
import AddEventLogCheck from "@/components/modals/checks/AddEventLogCheck";
import EditEventLogCheck from "@/components/modals/checks/EditEventLogCheck";
import EventLogCheckOutput from "@/components/modals/checks/EventLogCheckOutput";
export default {
name: "ChecksTab",
components: {
AddDiskSpaceCheck,
EditDiskSpaceCheck,
AddPingCheck,
EditPingCheck,
AddCpuLoadCheck,
EditCpuLoadCheck,
AddMemCheck,
EditMemCheck,
AddWinSvcCheck,
EditWinSvcCheck,
AddScriptCheck,
EditScriptCheck,
DiskSpaceCheck,
MemCheck,
CpuLoadCheck,
PingCheck,
WinSvcCheck,
EventLogCheck,
ScriptCheck,
ScriptOutput,
AddEventLogCheck,
EditEventLogCheck,
EventLogCheckOutput
},
mixins: [mixins],
data() {
return {
showAddDiskSpaceCheck: false,
showEditDiskSpaceCheck: false,
showAddPingCheck: false,
showEditPingCheck: false,
showAddCpuLoadCheck: false,
showEditCpuLoadCheck: false,
showAddMemCheck: false,
showEditMemCheck: false,
showAddWinSvcCheck: false,
showEditWinSvcCheck: false,
showAddScriptCheck: false,
showEditScriptCheck: false,
mode: "add",
checkpk: null,
showDiskSpaceCheck: false,
showMemCheck: false,
showCpuLoadCheck: false,
showPingCheck: false,
showWinSvcCheck: false,
showEventLogCheck: false,
showScriptCheck: false,
showScriptOutput: false,
showAddEventLogCheck: false,
showEditEventLogCheck: false,
showEventLogOutput: false,
editCheckPK: null,
scriptInfo: {},
evtlogdata: {},
columns: [
@@ -363,20 +315,55 @@ export default {
};
},
methods: {
checkAlertAction(pk, category, alert_type, alert_action) {
const action = alert_action ? "enabled" : "disabled";
const data = {
alertType: alert_type,
checkid: pk,
category: category,
action: action
};
const alertColor = alert_action ? "positive" : "warning";
axios.patch("/checks/checkalert/", data).then(r => {
showCheck(mode, type) {
switch (mode) {
case "add":
this.mode = "add";
break;
case "edit":
this.mode = "edit";
break;
}
switch (type) {
case "diskspace":
this.showDiskSpaceCheck = true;
break;
case "memory":
this.showMemCheck = true;
break;
case "cpuload":
this.showCpuLoadCheck = true;
break;
case "ping":
this.showPingCheck = true;
break;
case "winsvc":
this.showWinSvcCheck = true;
break;
case "eventlog":
this.showEventLogCheck = true;
break;
case "script":
this.showScriptCheck = true;
break;
}
},
checkAlert(id, alert_type, action) {
const data = {};
if (alert_type === "Email") {
data.email_alert = action;
} else {
data.text_alert = action;
}
const act = action ? "enabled" : "disabled";
const color = action ? "positive" : "warning";
axios.patch(`/checks/${id}/check/`, data).then(r => {
this.$q.notify({
color: alertColor,
color: color,
icon: "fas fa-check-circle",
message: `${alert_type} alerts ${action}`
message: `${alert_type} alerts ${act}`
});
});
},
@@ -384,13 +371,12 @@ export default {
this.$store.dispatch("loadChecks", id);
this.$store.dispatch("loadAutomatedTasks", id);
},
moreInfo(name, output) {
pingInfo(desc, output) {
this.$q.dialog({
title: `${name} output`,
style: "width: 35vw; max-width: 50vw",
title: desc,
style: "width: 50vw; max-width: 60vw",
message: `<pre>${output}</pre>`,
html: true,
dark: true
html: true
});
},
scriptMoreInfo(props) {
@@ -401,69 +387,29 @@ export default {
this.evtlogdata = props;
this.showEventLogOutput = true;
},
editCheck(category) {
switch (category) {
case "diskspace":
this.showEditDiskSpaceCheck = true;
break;
case "ping":
this.showEditPingCheck = true;
break;
case "cpuload":
this.showEditCpuLoadCheck = true;
break;
case "memory":
this.showEditMemCheck = true;
break;
case "winsvc":
this.showEditWinSvcCheck = true;
break;
case "script":
this.showEditScriptCheck = true;
break;
case "eventlog":
this.showEditEventLogCheck = true;
break;
default:
return false;
}
},
deleteCheck(pk, check_type) {
deleteCheck(pk, desc) {
this.$q
.dialog({
title: "Are you sure?",
message: `Delete ${check_type} check`,
message: `Delete ${desc}`,
cancel: true,
ok: { label: "Delete", color: "negative" },
persistent: true
})
.onOk(() => {
const data = { pk: pk, checktype: check_type };
axios
.delete("checks/deletestandardcheck/", { data: data })
.delete(`/checks/${pk}/check/`)
.then(r => {
this.$store.dispatch("loadChecks", this.checks.pk);
this.$store.dispatch("loadAutomatedTasks", this.checks.pk);
this.notifySuccess("Check was deleted!");
this.$store.dispatch("loadChecks", this.selectedAgentPk);
this.$store.dispatch("loadAutomatedTasks", this.selectedAgentPk);
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.error));
.catch(e => this.notifyError(e.response.data));
});
}
},
computed: {
...mapState({
checks: state => state.agentChecks
}),
allChecks() {
return [
...this.checks.diskchecks,
...this.checks.cpuloadchecks,
...this.checks.memchecks,
...this.checks.scriptchecks,
...this.checks.winservicechecks,
...this.checks.pingchecks,
...this.checks.eventlogchecks
];
}
...mapGetters(["selectedAgentPk", "checks"])
}
};
</script>

View File

@@ -19,22 +19,22 @@
unelevated
no-caps
icon="add"
@click="showUploadScriptModal = true; clearRow"
@click="showScript('add'); clearRow()"
/>
<q-btn
label="Edit"
:disable="selectedRow === null"
:disable="scriptpk === null"
dense
flat
push
unelevated
no-caps
icon="edit"
@click="showEditScriptModal = true"
@click="showScript('edit')"
/>
<q-btn
label="Delete"
:disable="selectedRow === null"
:disable="scriptpk === null"
dense
flat
push
@@ -45,7 +45,7 @@
/>
<q-btn
label="View Code"
:disable="selectedRow === null"
:disable="scriptpk === null"
dense
flat
push
@@ -56,7 +56,7 @@
/>
<q-btn
label="Download Script"
:disable="selectedRow === null"
:disable="scriptpk === null"
dense
flat
push
@@ -82,8 +82,8 @@
>
<template slot="body" slot-scope="props" :props="props">
<q-tr
:class="{highlight: selectedRow === props.row.id}"
@click="scriptRowSelected(props.row.id, props.row.filename)"
:class="{highlight: scriptpk === props.row.id}"
@click="scriptpk = props.row.id; filename = props.row.filename; code = props.row.code;"
>
<q-td>{{ props.row.name }}</q-td>
<q-td>{{ props.row.description }}</q-td>
@@ -98,11 +98,13 @@
<q-card-section></q-card-section>
</q-card>
</q-dialog>
<q-dialog v-model="showUploadScriptModal">
<UploadScript @close="showUploadScriptModal = false" @uploaded="getScripts" />
</q-dialog>
<q-dialog v-model="showEditScriptModal">
<EditScript :pk="selectedRow" @close="showEditScriptModal = false" @edited="getScripts" />
<q-dialog v-model="showScriptModal">
<ScriptModal
:mode="mode"
:scriptpk="scriptpk"
@close="showScriptModal = false"
@uploaded="getScripts"
/>
</q-dialog>
</div>
</template>
@@ -111,18 +113,18 @@
import axios from "axios";
import mixins from "@/mixins/mixins";
import { mapState } from "vuex";
import UploadScript from "@/components/modals/scripts/UploadScript";
import EditScript from "@/components/modals/scripts/EditScript";
import ScriptModal from "@/components/modals/scripts/ScriptModal";
export default {
name: "ScriptManager",
components: { UploadScript, EditScript },
components: { ScriptModal },
mixins: [mixins],
data() {
return {
selectedRow: null,
showUploadScriptModal: false,
showEditScriptModal: false,
mode: "add",
scriptpk: null,
showScriptModal: false,
filename: null,
code: null,
pagination: {
rowsPerPage: 0,
sortBy: "id",
@@ -170,26 +172,17 @@ export default {
hideScriptManager() {
this.$store.commit("TOGGLE_SCRIPT_MANAGER", false);
},
scriptRowSelected(pk, filename) {
this.selectedRow = pk;
this.filename = filename;
},
clearRow() {
this.selectedRow = null;
this.scriptpk = null;
this.filename = null;
},
viewCode() {
axios
.get(`/checks/viewscriptcode/${this.selectedRow}/`)
.then(r => {
this.$q.dialog({
title: r.data.name,
message: `<pre>${r.data.text}</pre>`,
html: true,
fullWidth: true
});
})
.catch(() => this.notifyError("Something went wrong"));
this.$q.dialog({
title: this.filename,
message: `<pre>${this.code}</pre>`,
html: true,
style: "width: 70vw; max-width: 80vw;"
});
},
deleteScript() {
this.$q
@@ -199,16 +192,18 @@ export default {
ok: { label: "Delete", color: "negative" }
})
.onOk(() => {
const data = { pk: this.selectedRow };
axios.delete("/checks/deletescript/", { data: data }).then(r => {
this.getScripts();
this.notifySuccess(`Script ${r.data} was deleted!`);
});
axios
.delete(`/scripts/${this.scriptpk}/script/`)
.then(r => {
this.getScripts();
this.notifySuccess(r.data);
})
.catch(() => this.notifySuccess("Something went wrong"));
});
},
downloadScript() {
axios
.get(`/checks/downloadscript/${this.selectedRow}/`, { responseType: "blob" })
.get(`/scripts/${this.scriptpk}/download/`, { responseType: "blob" })
.then(({ data }) => {
const blob = new Blob([data], { type: "text/plain" });
let link = document.createElement("a");
@@ -216,7 +211,18 @@ export default {
link.download = this.filename;
link.click();
})
.catch(error => console.error(error));
.catch(() => this.notifyError("Something went wrong"));
},
showScript(mode) {
switch (mode) {
case "add":
this.mode = "add";
break;
case "edit":
this.mode = "edit";
break;
}
this.showScriptModal = true;
}
},
computed: {

View File

@@ -247,7 +247,7 @@ export default {
},
clearRow() {
this.$store.commit("automation/setSelectedPolicy", null);
this.$store.commit("automation/setPolicyChecks", {});
this.$store.commit("automation/setPolicyChecks", []);
this.$store.commit("automation/setPolicyAutomatedTasks", {});
},
refresh() {

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="Object.keys(checks).length === 0">No Policy Selected</div>
<div v-if="selectedPolicy === null">No Policy Selected</div>
<div class="row" v-else>
<div class="col-12">
<q-btn
@@ -8,46 +8,47 @@
icon="fas fa-plus"
label="Add Check"
text-color="black"
ref="add"
>
<q-menu>
<q-list dense style="min-width: 200px">
<q-item clickable v-close-popup @click="showAddDialog('AddDiskSpaceCheck')">
<q-item clickable v-close-popup @click="showAddDialog('DiskSpaceCheck')">
<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="showAddDialog('AddPingCheck')">
<q-item clickable v-close-popup @click="showAddDialog('PingCheck')">
<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="showAddDialog('AddCpuLoadCheck')">
<q-item clickable v-close-popup @click="showAddDialog('CpuLoadCheck')">
<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="showAddDialog('AddMemCheck')">
<q-item clickable v-close-popup @click="showAddDialog('MemCheck')">
<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="showAddDialog('AddWinSvcCheck')">
<q-item clickable v-close-popup @click="showAddDialog('WinSvcCheck')">
<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="showAddDialog('AddScriptCheck')">
<q-item clickable v-close-popup @click="showAddDialog('ScriptCheck')">
<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-item clickable v-close-popup @click="showAddDialog('AddEventLogCheck')">
<q-item clickable v-close-popup @click="showAddDialog('EventLogCheck')">
<q-item-section side>
<q-icon size="xs" name="fas fa-clipboard-list" />
</q-item-section>
@@ -60,17 +61,18 @@
dense
flat
push
@click="onRefresh(checks.id)"
@click="onRefresh(selectedPolicy)"
icon="refresh"
ref="refresh"
/>
<template v-if="allChecks === undefined || allChecks.length === 0">
<template v-if="checks.length === 0">
<p>No Checks</p>
</template>
<template v-else>
<q-table
dense
class="tabs-tbl-sticky"
:data="allChecks"
:data="checks"
:columns="columns"
:row-key="row => row.id + row.check_type"
binary-state-sort
@@ -97,14 +99,15 @@
</template>
<!-- body slots -->
<template v-slot:body="props">
<q-tr @contextmenu="editCheckPK = props.row.id" :props="props">
<q-tr :props="props">
<!-- context menu -->
<q-menu context-menu>
<q-list dense style="min-width: 200px">
<q-item
clickable
v-close-popup
@click="showEditDialog(props.row.check_type)"
@click="showEditDialog(props.row)"
id="context-edit"
>
<q-item-section side>
<q-icon name="edit" />
@@ -114,7 +117,8 @@
<q-item
clickable
v-close-popup
@click="deleteCheck(props.row.id, props.row.check_type)"
@click="deleteCheck(props.row)"
id="context-delete"
>
<q-item-section side>
<q-icon name="delete" />
@@ -124,7 +128,12 @@
<q-separator></q-separator>
<q-item clickable v-close-popup @click="showPolicyCheckStatusModal(props.row)">
<q-item
clickable
v-close-popup
@click="showPolicyCheckStatusModal(props.row)"
id="context-status"
>
<q-item-section side>
<q-icon name="sync" />
</q-item-section>
@@ -142,14 +151,14 @@
<q-td>
<q-checkbox
dense
@input="checkAlertAction(props.row.id, props.row.check_type, 'text', props.row.text_alert)"
@input="checkAlert(props.row.id, '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, 'email', props.row.email_alert)"
@input="checkAlert(props.row.id, 'Email', props.row.email_alert)"
v-model="props.row.email_alert"
/>
</q-td>
@@ -158,6 +167,7 @@
<span
style="cursor:pointer;color:blue;text-decoration:underline"
@click="showPolicyCheckStatusModal(props.row)"
class="status-cell"
>
See Status
</span>
@@ -178,12 +188,16 @@
</q-dialog>
<!-- add/edit modals -->
<q-dialog v-model="showDialog">
<q-dialog
v-model="showDialog"
@hide="hideDialog">
<component
v-if="dialogComponent !== null"
:is="dialogComponent"
@close="hideDialog"
:policypk="checks.id"
:editCheckPK="editCheckPK"
:policypk="selectedPolicy"
:checkpk="editCheckPK"
:mode="!!editCheckPK ? 'edit' : 'add'"
/>
</q-dialog>
</div>
@@ -193,11 +207,25 @@
import { mapState, mapGetters } from "vuex";
import mixins, { notifySuccessConfig, notifyErrorConfig } from "@/mixins/mixins";
import PolicyStatus from "@/components/automation/modals/PolicyStatus";
import DiskSpaceCheck from "@/components/modals/checks/DiskSpaceCheck";
import PingCheck from "@/components/modals/checks/PingCheck";
import CpuLoadCheck from "@/components/modals/checks/CpuLoadCheck";
import MemCheck from "@/components/modals/checks/MemCheck";
import WinSvcCheck from "@/components/modals/checks/WinSvcCheck";
import ScriptCheck from "@/components/modals/checks/ScriptCheck";
import EventLogCheck from "@/components/modals/checks/EventLogCheck";
export default {
name: "PolicyChecksTab",
components: {
PolicyStatus
PolicyStatus,
DiskSpaceCheck,
PingCheck,
CpuLoadCheck,
MemCheck,
WinSvcCheck,
ScriptCheck,
EventLogCheck,
},
mixins: [mixins],
data() {
@@ -219,22 +247,23 @@ export default {
};
},
methods: {
checkAlertAction(pk, category, alert_type, alert_action) {
const action = alert_action ? "enabled" : "disabled";
const data = {
alertType: alert_type,
checkid: pk,
category: category,
action: action
};
const alertColor = alert_action ? "positive" : "warning";
checkAlert(id, alert_type, action) {
const data = {};
if (alert_type === "Email") {
data.email_alert = action;
} else {
data.text_alert = action;
}
const act = action ? "enabled" : "disabled";
const color = action ? "positive" : "warning";
this.$store
.dispatch("editCheckAlertAction", data)
.dispatch("editCheckAlert", id, data)
.then(r => {
this.$q.notify({
color: alertColor,
color: color,
icon: "fas fa-check-circle",
message: `${alert_type} alerts ${action}`
message: `${alert_type} alerts ${act}`
});
});
},
@@ -242,62 +271,58 @@ export default {
this.$store.dispatch("automation/loadPolicyChecks", id);
},
showAddDialog(component) {
this.dialogComponent = () => import(`@/components/modals/checks/${component}`);
this.dialogComponent = component;
this.showDialog = true;
},
showEditDialog(category) {
let component = null;
switch (category) {
showEditDialog(check) {
switch (check.check_type) {
case "diskspace":
component = "EditDiskSpaceCheck";
this.dialogComponent = "DiskSpaceCheck";
break;
case "ping":
component = "EditPingCheck";
this.dialogComponent = "PingCheck";
break;
case "cpuload":
tcomponent = "EditCpuLoadCheck";
this.dialogComponent = "CpuLoadCheck";
break;
case "memory":
component = "EditMemCheck";
this.dialogComponent = "MemCheck";
break;
case "winsvc":
component = "EditWinSvcCheck";
this.dialogComponent = "WinSvcCheck";
break;
case "script":
component = "EditScriptCheck";
this.dialogComponent = "ScriptCheck";
break;
case "eventlog":
component = "EditEventLogCheck";
this.dialogComponent = "EventLogCheck";
break;
default:
return null;
}
this.dialogComponent = () => import(`@/components/modals/checks/${component}`);
this.editCheckPK = check.id
this.showDialog = true;
},
hideDialog(component) {
this.showDialog = false;
this.dialogComponent = null;
},
deleteCheck(pk, check_type) {
deleteCheck(check) {
this.$q
.dialog({
title: "Are you sure?",
message: `Delete ${check_type} check`,
title: `Delete ${check.check_type} check?`,
ok: { label: "Delete", color: "negative" },
cancel: true,
persistent: true
})
.onOk(() => {
const data = { pk: pk, checktype: check_type };
this.$store
.dispatch("deleteCheck", data)
.dispatch("deleteCheck", check.id)
.then(r => {
this.$store.dispatch("automation/loadPolicyChecks", this.checks.id);
this.$q.notify(notifySuccessConfig);
this.$store.dispatch("automation/loadPolicyChecks", check.id);
this.$q.notify(notifySuccessConfig("Check Deleted!"));
})
.catch(e => this.$q.notify(notifyErrorConfig));
.catch(e => this.$q.notify(notifyErrorConfig("An Error Occurred while deleting")));
});
},
showPolicyCheckStatusModal(check) {
@@ -326,12 +351,10 @@ export default {
}
},
computed: {
...mapState({
checks: state => state.automation.checks
}),
...mapGetters({
allChecks: "automation/allChecks"
})
checks: "automation/checks",
selectedPolicy: "automation/selectedPolicyPk"
})
}
};
</script>

View File

@@ -1,81 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add CPU Load 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-input
outlined
v-model.number="threshold"
label="Alert if average utilization > (%)"
:rules="[
val => !!val || '*Required',
val => val >= 1 || 'Minimum threshold is 1',
val => val < 100 || 'Maximum threshold is 99'
]"
/>
</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 mixins from "@/mixins/mixins";
export default {
name: "AddCpuLoadCheck",
props: ["agentpk", "policypk"],
mixins: [mixins],
data() {
return {
threshold: 85,
failure: 5,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check_type: "cpuload",
threshold: this.threshold,
failure: this.failure
};
axios
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("CPU load check was added!");
})
.catch(e => this.notifyError(e.response.data.error));
}
}
};
</script>

View File

@@ -1,102 +0,0 @@
<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-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-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 mixins from "@/mixins/mixins";
export default {
name: "AddDiskSpaceCheck",
props: ["agentpk", "policypk"],
mixins: [mixins],
data() {
return {
threshold: 25,
disks: [],
firstdisk: "",
failure: 2,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getDisks() {
if (this.policypk) {
axios.get("/checks/getalldisks/").then(r => {
this.disks = r.data;
this.firstdisk = "C:";
});
} else {
axios.get(`/checks/getdisks/${this.agentpk}/`).then(r => {
this.disks = Object.keys(r.data);
this.firstdisk = Object.keys(r.data)[0];
});
}
},
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check_type: "diskspace",
disk: this.firstdisk,
threshold: this.threshold,
failure: this.failure
};
axios
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess(`Disk check for drive ${data.disk} was added!`);
})
.catch(e => this.notifyError(e.response.data.error));
}
},
mounted() {
this.getDisks();
}
};
</script>

View File

@@ -1,149 +0,0 @@
<template>
<q-card style="min-width: 40vw">
<q-card-section class="row items-center">
<div class="text-h6">Add Event Log 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-input
dense
outlined
v-model="desc"
label="Descriptive Name"
:rules="[ val => !!val || '*Required' ]"
/>
</q-card-section>
<q-card-section>
<q-select
dense
outlined
v-model="logname"
:options="logNameOptions"
label="Event log to query"
/>
</q-card-section>
<q-card-section>
<q-select
dense
outlined
v-model="failWhen"
:options="failWhenOptions"
label="Fail When"
emit-value
map-options
/>
</q-card-section>
<q-card-section>
<q-input
dense
outlined
v-model.number="eventID"
label="Event ID"
:rules="[
val => !!val.toString() || '*Required',
val => val >= 0 || 'Min 0',
val => val <= 999999 || 'Max 999999'
]"
/>
</q-card-section>
<q-card-section>
<q-input
dense
outlined
v-model.number="searchLastDays"
label="How many previous days to search (Enter 0 for the entire log)"
:rules="[
val => !!val.toString() || '*Required',
val => val >= 0 || 'Min 0',
val => val <= 9999 || 'Max 9999'
]"
/>
</q-card-section>
<q-card-section>
<span>Event Type:</span>
<div class="q-gutter-sm">
<q-radio dense v-model="eventType" val="INFO" label="Information" />
<q-radio dense v-model="eventType" val="WARNING" label="Warning" />
<q-radio dense v-model="eventType" val="ERROR" label="Error" />
<q-radio dense v-model="eventType" val="AUDIT_SUCCESS" label="Success Audit" />
<q-radio dense v-model="eventType" val="AUDIT_FAILURE" label="Failure Audit" />
</div>
</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 mixins from "@/mixins/mixins";
export default {
name: "AddEventLogCheck",
props: ["agentpk", "policypk"],
mixins: [mixins],
data() {
return {
desc: null,
eventID: 0,
eventType: "INFO",
logname: "Application",
logNameOptions: ["Application", "System", "Security"],
failWhen: "contains",
searchLastDays: 1,
failWhenOptions: [
{ label: "Log contains", value: "contains" },
{ label: "Log does not contain", value: "not_contains" }
],
failure: 1,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check_type: "eventlog",
desc: this.desc,
log_name: this.logname,
event_id: this.eventID,
event_type: this.eventType,
fail_when: this.failWhen,
search_last_days: this.searchLastDays,
failure: this.failure
};
axios
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Event log check was added!");
})
.catch(e => this.notifyError(e.response.data.desc));
}
}
};
</script>

View File

@@ -1,81 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add Memory 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-input
outlined
v-model.number="threshold"
label="Alert if average memory usage > (%)"
:rules="[
val => !!val || '*Required',
val => val >= 1 || 'Minimum threshold is 1',
val => val < 100 || 'Maximum threshold is 99'
]"
/>
</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 mixins from "@/mixins/mixins";
export default {
name: "AddMemCheck",
props: ["agentpk", "policypk"],
mixins: [mixins],
data() {
return {
threshold: 85,
failure: 5,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check_type: "mem",
threshold: this.threshold,
failure: this.failure
};
axios
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Memory check was added!");
})
.catch(e => this.notifyError(e.response.data.error));
}
}
};
</script>

View File

@@ -1,89 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add Ping 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-input
outlined
v-model="pingname"
label="Descriptive Name"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section>
<q-input
outlined
v-model="pingip"
label="Hostname or IP"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section>
<q-select
outlined
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 mixins from "@/mixins/mixins";
export default {
name: "AddPingCheck",
props: ["agentpk", "policypk"],
mixins: [mixins],
data() {
return {
failure: 5,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
pingname: "",
pingip: ""
};
},
methods: {
addCheck() {
let pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check_type: "ping",
failures: this.failure,
name: this.pingname,
ip: this.pingip
};
axios
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Ping check was added!");
})
.catch(e => {
this.notifyError(e.response.data);
});
}
}
};
</script>

View File

@@ -1,182 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add Windows Service 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-radio
v-if="policypk"
v-model="serviceType"
val="svcdefault"
label="Choose from defaults"
@input="manualServiceName = null; manualSvcDisplayName = null; displayName = null"
/>
<q-radio
v-if="policypk"
v-model="serviceType"
val="svcmanual"
label="Enter manually"
@input="manualServiceName = null; manualSvcDisplayName = null; displayName = null"
/>
<q-select
v-if="policypk && serviceType === 'svcdefault'"
dense
outlined
v-model="displayName"
:options="svcDisplayNames"
label="Service"
@input="getRawName"
/>
<q-input
v-if="policypk && serviceType === 'svcmanual'"
outlined
dense
v-model="manualServiceName"
label="Service Name"
/>
<q-input
v-if="policypk && serviceType === 'svcmanual'"
outlined
dense
v-model="manualSvcDisplayName"
label="Display Name"
/>
<q-select
v-if="agentpk"
:rules="[val => !!val || '*Required']"
dense
outlined
v-model="displayName"
:options="svcDisplayNames"
label="Service"
@input="getRawName"
/>
</q-card-section>
<q-card-section>
<q-checkbox
v-model="passIfStartPending"
label="PASS if service is in 'Start Pending' mode"
/>
<q-checkbox v-model="restartIfStopped" label="RESTART service if it's stopped" />
</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 mixins from "@/mixins/mixins";
export default {
name: "AddWinSvcCheck",
props: ["agentpk", "policypk"],
mixins: [mixins],
data() {
return {
serviceType: "svcdefault",
manualServiceName: "",
manualSvcDisplayName: "",
servicesData: [],
displayName: "",
rawName: [],
passIfStartPending: false,
restartIfStopped: false,
failure: 2,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
computed: {
svcDisplayNames() {
return this.servicesData.map(k => k.display_name).sort();
}
},
methods: {
getServices() {
if (this.policypk) {
axios.get("/services/getdefaultservices/").then(r => {
this.servicesData = Object.freeze(r.data);
});
} else {
axios.get(`/services/${this.agentpk}/services/`).then(r => {
this.servicesData = Object.freeze([r.data][0].services);
});
}
},
getRawName() {
let svc = this.servicesData.find(k => k.display_name === this.displayName);
this.rawName = [svc].map(j => j.name);
},
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
let rawname, displayname;
if (this.policypk) {
// policy
if (this.serviceType === "svcdefault") {
rawname = { rawname: this.rawName[0] };
displayname = { displayname: this.displayName };
if (this.rawName.length === 0) {
this.notifyError("Please select a service");
return;
}
} else if (this.serviceType === "svcmanual") {
rawname = { rawname: this.manualServiceName };
displayname = { displayname: this.manualSvcDisplayName };
if (!this.manualServiceName || !this.manualSvcDisplayName) {
this.notifyError("All fields required");
return;
}
}
} else {
// agent
rawname = { rawname: this.rawName[0] };
displayname = { displayname: this.displayName };
}
const data = {
...pk,
check_type: "winsvc",
...rawname,
...displayname,
passifstartpending: this.passIfStartPending,
restartifstopped: this.restartIfStopped,
failures: this.failure
};
axios
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess(`${data.displayname} service check added!`);
})
.catch(e => this.notifyError(e.response.data.error));
}
},
mounted() {
this.getServices();
}
};
</script>

View File

@@ -0,0 +1,106 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div v-if="mode === 'add'" class="text-h6">Add CPU Load Check</div>
<div v-else-if="mode === 'edit'" class="text-h6">Edit CPU Load Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="mode === 'add' ? addCheck() : editCheck()">
<q-card-section>
<q-input
outlined
v-model.number="cpuloadcheck.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-section>
<q-select
outlined
dense
v-model="cpuloadcheck.fails_b4_alert"
:options="failOptions"
label="Number of consecutive failures before alert"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn v-if="mode === 'add'" label="Add" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" label="Edit" 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 mixins from "@/mixins/mixins";
export default {
name: "CpuLoadCheck",
props: {
agentpk: Number,
policypk: Number,
mode: String,
checkpk: Number
},
mixins: [mixins],
data() {
return {
cpuloadcheck: {
check_type: "cpuload",
threshold: 85,
fails_b4_alert: 1
},
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getCheck() {
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.cpuloadcheck = r.data));
},
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check: this.cpuloadcheck
};
axios
.post("/checks/checks/", data)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
editCheck() {
axios
.patch(`/checks/${this.checkpk}/check/`, this.cpuloadcheck)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
reloadChecks() {
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
}
},
created() {
if (this.mode === "edit") {
this.getCheck();
}
}
};
</script>

View File

@@ -0,0 +1,134 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div v-if="mode === 'add'" class="text-h6">Add Disk Space Check</div>
<div v-else-if="mode === 'edit'" 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="mode === 'add' ? addCheck() : editCheck()">
<q-card-section>
<q-select
:disable="this.mode === 'edit'"
outlined
v-model="diskcheck.disk"
:options="diskOptions"
label="Disk"
/>
</q-card-section>
<q-card-section>
<q-input
outlined
v-model.number="diskcheck.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-section>
<q-select
outlined
dense
v-model="diskcheck.fails_b4_alert"
:options="failOptions"
label="Number of consecutive failures before alert"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn v-if="mode === 'add'" label="Add" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" label="Edit" 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, mapGetters } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "DiskSpaceCheck",
props: {
agentpk: Number,
policypk: Number,
mode: String,
checkpk: Number
},
mixins: [mixins],
data() {
return {
diskcheck: {
disk: null,
check_type: "diskspace",
threshold: 25,
fails_b4_alert: 1
},
diskOptions: [],
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
setDiskOptions() {
if (this.policypk) {
axios.get("/checks/getalldisks/").then(r => {
this.diskOptions = r.data;
this.diskcheck.disk = "C:";
});
} else {
this.diskOptions = Object.keys(this.agentDisks);
this.diskcheck.disk = this.diskOptions[0];
}
},
getCheck() {
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.diskcheck = r.data));
},
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check: this.diskcheck
};
axios
.post("/checks/checks/", data)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
editCheck() {
axios
.patch(`/checks/${this.checkpk}/check/`, this.diskcheck)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
reloadChecks() {
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
}
},
computed: {
...mapGetters(["agentDisks"])
},
created() {
if (this.mode === "add") {
this.setDiskOptions();
} else if (this.mode === "edit") {
this.getCheck();
}
}
};
</script>

View File

@@ -1,88 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Edit CPU Load 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-input
outlined
v-model.number="threshold"
label="Alert if average utilization > (%)"
:rules="[
val => !!val || '*Required',
val => val >= 1 || 'Minimum threshold is 1',
val => val < 100 || 'Maximum threshold is 99'
]"
/>
</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>
import axios from "axios";
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "EditCpuLoadCheck",
props: ["agentpk", "policypk", "editCheckPK"],
mixins: [mixins],
data() {
return {
threshold: null,
failure: null,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getCheck() {
axios.get(`/checks/getstandardcheck/cpuload/${this.editCheckPK}/`).then(r => {
this.threshold = r.data.cpuload;
this.failure = r.data.failures;
});
},
editCheck() {
const data = {
pk: this.editCheckPK,
check_type: "cpuload",
threshold: this.threshold,
failure: this.failure
};
axios
.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("CPU load check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));
}
},
mounted() {
this.getCheck();
}
};
</script>

View File

@@ -1,94 +0,0 @@
<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-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-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>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "EditDiskSpaceCheck",
props: ["editCheckPK", "agentpk", "policypk"],
mixins: [mixins],
data() {
return {
threshold: null,
disks: [],
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 => {
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,
failures: this.failure
};
axios
.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Disk space check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));
}
},
mounted() {
this.getCheck();
}
};
</script>

View File

@@ -1,161 +0,0 @@
<template>
<q-card style="min-width: 40vw">
<q-card-section class="row items-center">
<div class="text-h6">Edit Event Log 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-input
dense
outlined
v-model="desc"
label="Descriptive Name"
:rules="[ val => !!val || '*Required' ]"
/>
</q-card-section>
<q-card-section>
<q-select
dense
outlined
v-model="logname"
:options="logNameOptions"
label="Event log to query"
/>
</q-card-section>
<q-card-section>
<q-select
dense
outlined
v-model="failWhen"
:options="failWhenOptions"
label="Fail When"
emit-value
map-options
/>
</q-card-section>
<q-card-section>
<q-input
dense
outlined
v-model.number="eventID"
label="Event ID"
:rules="[
val => !!val.toString() || '*Required',
val => val >= 0 || 'Min 0',
val => val <= 999999 || 'Max 999999'
]"
/>
</q-card-section>
<q-card-section>
<q-input
dense
outlined
v-model.number="searchLastDays"
label="How many previous days to search (Enter 0 for the entire log)"
:rules="[
val => !!val.toString() || '*Required',
val => val >= 0 || 'Min 0',
val => val <= 9999 || 'Max 9999'
]"
/>
</q-card-section>
<q-card-section>
<span>Event Type:</span>
<div class="q-gutter-sm">
<q-radio dense v-model="eventType" val="INFO" label="Information" />
<q-radio dense v-model="eventType" val="WARNING" label="Warning" />
<q-radio dense v-model="eventType" val="ERROR" label="Error" />
<q-radio dense v-model="eventType" val="AUDIT_SUCCESS" label="Success Audit" />
<q-radio dense v-model="eventType" val="AUDIT_FAILURE" label="Failure Audit" />
</div>
</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>
import axios from "axios";
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "EditEventLogCheck",
props: ["agentpk", "policypk", "editCheckPK"],
mixins: [mixins],
data() {
return {
desc: null,
eventID: null,
eventType: null,
logname: null,
logNameOptions: ["Application", "System", "Security"],
failWhen: null,
searchLastDays: null,
failWhenOptions: [
{ label: "Log contains", value: "contains" },
{ label: "Log does not contain", value: "not_contains" }
],
failure: null,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getCheck() {
axios.get(`/checks/getstandardcheck/eventlog/${this.editCheckPK}/`).then(r => {
this.desc = r.data.desc;
this.eventID = r.data.event_id;
this.eventType = r.data.event_type;
this.logname = r.data.log_name;
this.failWhen = r.data.fail_when;
this.searchLastDays = r.data.search_last_days;
this.failure = r.data.failures;
});
},
editCheck() {
const data = {
pk: this.editCheckPK,
check_type: "eventlog",
desc: this.desc,
log_name: this.logname,
event_id: this.eventID,
event_type: this.eventType,
fail_when: this.failWhen,
search_last_days: this.searchLastDays,
failures: this.failure
};
axios
.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Event log check was edited!");
})
.catch(e => this.notifyError(e.response.data.desc));
}
},
created() {
this.getCheck();
}
};
</script>

View File

@@ -1,88 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Edit Memory 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-input
outlined
v-model.number="threshold"
label="Alert if average memory usage > (%)"
:rules="[
val => !!val || '*Required',
val => val >= 1 || 'Minimum threshold is 1',
val => val < 100 || 'Maximum threshold is 99'
]"
/>
</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>
import axios from "axios";
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "EditMemCheck",
props: ["agentpk", "policypk", "editCheckPK"],
mixins: [mixins],
data() {
return {
threshold: null,
failure: null,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getCheck() {
axios.get(`/checks/getstandardcheck/mem/${this.editCheckPK}/`).then(r => {
this.threshold = r.data.threshold;
this.failure = r.data.failures;
});
},
editCheck() {
const data = {
pk: this.editCheckPK,
check_type: "mem",
threshold: this.threshold,
failure: this.failure
};
axios
.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Memory check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));
}
},
mounted() {
this.getCheck();
}
};
</script>

View File

@@ -1,94 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Edit Ping 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-input
outlined
v-model="pingname"
label="Descriptive Name"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section>
<q-input
outlined
v-model="pingip"
label="Hostname or IP"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section>
<q-select
outlined
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>
import axios from "axios";
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "EditPingCheck",
props: ["agentpk", "policypk", "editCheckPK"],
mixins: [mixins],
data() {
return {
failure: null,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
pingname: "",
pingip: ""
};
},
methods: {
getCheck() {
axios.get(`/checks/getstandardcheck/ping/${this.editCheckPK}/`).then(r => {
this.failure = r.data.failures;
this.pingname = r.data.name;
this.pingip = r.data.ip;
});
},
editCheck() {
const data = {
pk: this.editCheckPK,
check_type: "ping",
failures: this.failure,
name: this.pingname,
ip: this.pingip
};
axios
.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Ping check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));
}
},
mounted() {
this.getCheck();
}
};
</script>

View File

@@ -1,93 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Edit Script Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="editScriptCheck">
<q-card-section>
<q-select dense outlined v-model="scriptName" disable label="Select script" />
</q-card-section>
<q-card-section>
<q-input
outlined
dense
v-model.number="timeout"
label="Timeout (seconds)"
:rules="[
val => !!val || '*Required',
val => val >= 10 || 'Minimum is 10 seconds',
val => val <= 86400 || 'Maximum is 86400 seconds'
]"
/>
</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>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "EditScriptCheck",
props: ["agentpk", "policypk", "editCheckPK"],
mixins: [mixins],
data() {
return {
scriptName: null,
failure: null,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
timeout: null
};
},
methods: {
getScriptCheck() {
axios.get(`/checks/getstandardcheck/script/${this.editCheckPK}/`).then(r => {
this.failure = r.data.failures;
this.timeout = r.data.timeout;
this.scriptName = r.data.script.name;
});
},
editScriptCheck() {
const data = {
pk: this.editCheckPK,
check_type: "script",
failures: this.failure,
timeout: this.timeout
};
axios
.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.error));
}
},
created() {
this.getScriptCheck();
}
};
</script>

View File

@@ -1,103 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Edit Windows Service 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
disable
dense
outlined
v-model="displayName"
:options="svcDisplayNames"
label="Service"
/>
</q-card-section>
<q-card-section>
<q-checkbox
v-model="passIfStartPending"
label="PASS if service is in 'Start Pending' mode"
/>
<q-checkbox v-model="restartIfStopped" label="RESTART service if it's stopped" />
</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>
import axios from "axios";
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "EditWinSvcCheck",
props: ["agentpk", "editCheckPK", "policypk"],
mixins: [mixins],
data() {
return {
displayName: "",
svcDisplayNames: [],
passIfStartPending: null,
restartIfStopped: null,
failure: null,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
async getService() {
try {
let r = await axios.get(`/checks/getstandardcheck/winsvc/${this.editCheckPK}/`);
this.svcDisplayNames = [r.data.svc_display_name];
this.displayName = r.data.svc_display_name;
this.passIfStartPending = r.data.pass_if_start_pending;
this.restartIfStopped = r.data.restart_if_stopped;
this.failure = r.data.failures;
} catch (e) {
console.log(`ERROR!: ${e}`);
}
},
editCheck() {
const data = {
pk: this.editCheckPK,
check_type: "winsvc",
failures: this.failure,
passifstartpending: this.passIfStartPending,
restartifstopped: this.restartIfStopped
};
axios
.patch("/checks/editstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Windows service check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));
}
},
mounted() {
this.getService();
}
};
</script>

View File

@@ -0,0 +1,178 @@
<template>
<q-card style="min-width: 40vw">
<q-card-section class="row items-center">
<div v-if="mode === 'add'" class="text-h6">Add Event Log Check</div>
<div v-else-if="mode === 'edit'" class="text-h6">Edit Event Log Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="mode === 'add' ? addCheck() : editCheck()">
<q-card-section>
<q-input
dense
outlined
v-model="eventlogcheck.name"
label="Descriptive Name"
:rules="[ val => !!val || '*Required' ]"
/>
</q-card-section>
<q-card-section>
<q-select
dense
outlined
v-model="eventlogcheck.log_name"
:options="logNameOptions"
label="Event log to query"
/>
</q-card-section>
<q-card-section>
<q-select
dense
outlined
v-model="eventlogcheck.fail_when"
:options="failWhenOptions"
label="Fail When"
emit-value
map-options
/>
</q-card-section>
<q-card-section>
<q-input
dense
outlined
v-model.number="eventlogcheck.event_id"
label="Event ID"
:rules="[
val => !!val.toString() || '*Required',
val => val >= 0 || 'Min 0',
val => val <= 999999 || 'Max 999999'
]"
/>
</q-card-section>
<q-card-section>
<q-input
dense
outlined
v-model.number="eventlogcheck.search_last_days"
label="How many previous days to search (Enter 0 for the entire log)"
:rules="[
val => !!val.toString() || '*Required',
val => val >= 0 || 'Min 0',
val => val <= 9999 || 'Max 9999'
]"
/>
</q-card-section>
<q-card-section>
<span>Event Type:</span>
<div class="q-gutter-sm">
<q-radio dense v-model="eventlogcheck.event_type" val="INFO" label="Information" />
<q-radio dense v-model="eventlogcheck.event_type" val="WARNING" label="Warning" />
<q-radio dense v-model="eventlogcheck.event_type" val="ERROR" label="Error" />
<q-radio
dense
v-model="eventlogcheck.event_type"
val="AUDIT_SUCCESS"
label="Success Audit"
/>
<q-radio
dense
v-model="eventlogcheck.event_type"
val="AUDIT_FAILURE"
label="Failure Audit"
/>
</div>
</q-card-section>
<q-card-section>
<q-select
outlined
dense
v-model="eventlogcheck.fails_b4_alert"
:options="failOptions"
label="Number of consecutive failures before alert"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn v-if="mode === 'add'" label="Add" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" label="Edit" 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 mixins from "@/mixins/mixins";
export default {
name: "EventLogCheck",
props: {
agentpk: Number,
policypk: Number,
mode: String,
checkpk: Number
},
mixins: [mixins],
data() {
return {
eventlogcheck: {
check_type: "eventlog",
log_name: "Application",
event_id: null,
event_type: "INFO",
fail_when: "contains",
search_last_days: 1,
fails_b4_alert: 1
},
logNameOptions: ["Application", "System", "Security"],
failWhenOptions: [
{ label: "Log contains", value: "contains" },
{ label: "Log does not contain", value: "not_contains" }
],
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getCheck() {
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.eventlogcheck = r.data));
},
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check: this.eventlogcheck
};
axios
.post("/checks/checks/", data)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
editCheck() {
axios
.patch(`/checks/${this.checkpk}/check/`, this.eventlogcheck)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
reloadChecks() {
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
}
},
mounted() {
if (this.mode === "edit") {
this.getCheck();
}
}
};
</script>

View File

@@ -6,11 +6,11 @@
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</div>
<div v-if="evtlogdata.more_info !== null">
<div v-if="evtlogdata.extra_details !== null">
<q-table
dense
class="remote-bg-tbl-sticky"
:data="evtlogdata.more_info.log"
:data="evtlogdata.extra_details.log"
:columns="columns"
:pagination.sync="pagination"
row-key="uid"

View File

@@ -0,0 +1,106 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div v-if="mode === 'add'" class="text-h6">Add Memory Check</div>
<div v-else-if="mode === 'edit'" class="text-h6">Edit Memory Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="mode === 'add' ? addCheck() : editCheck()">
<q-card-section>
<q-input
outlined
v-model.number="memcheck.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-section>
<q-select
outlined
dense
v-model="memcheck.fails_b4_alert"
:options="failOptions"
label="Number of consecutive failures before alert"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn v-if="mode === 'add'" label="Add" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" label="Edit" 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 mixins from "@/mixins/mixins";
export default {
name: "MemCheck",
props: {
agentpk: Number,
policypk: Number,
mode: String,
checkpk: Number
},
mixins: [mixins],
data() {
return {
memcheck: {
check_type: "memory",
threshold: 85,
fails_b4_alert: 1
},
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getCheck() {
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.memcheck = r.data));
},
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check: this.memcheck
};
axios
.post("/checks/checks/", data)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
editCheck() {
axios
.patch(`/checks/${this.checkpk}/check/`, this.memcheck)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
reloadChecks() {
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
}
},
created() {
if (this.mode === "edit") {
this.getCheck();
}
}
};
</script>

View File

@@ -0,0 +1,111 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row items-center">
<div v-if="mode === 'add'" class="text-h6">Add Ping Check</div>
<div v-else-if="mode === 'edit'" class="text-h6">Edit Ping Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="mode === 'add' ? addCheck() : editCheck()">
<q-card-section>
<q-input
outlined
v-model="pingcheck.name"
label="Descriptive Name"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section>
<q-input
outlined
v-model="pingcheck.ip"
label="Hostname or IP"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section>
<q-select
outlined
dense
v-model="pingcheck.fails_b4_alert"
:options="failOptions"
label="Number of consecutive failures before alert"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn v-if="mode === 'add'" label="Add" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" label="Edit" 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 mixins from "@/mixins/mixins";
export default {
name: "PingCheck",
props: {
agentpk: Number,
policypk: Number,
mode: String,
checkpk: Number
},
mixins: [mixins],
data() {
return {
pingcheck: {
check_type: "ping",
name: null,
ip: null,
fails_b4_alert: 1
},
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
methods: {
getCheck() {
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.pingcheck = r.data));
},
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check: this.pingcheck
};
axios
.post("/checks/checks/", data)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
editCheck() {
axios
.patch(`/checks/${this.checkpk}/check/`, this.pingcheck)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
reloadChecks() {
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
}
},
created() {
if (this.mode === "edit") {
this.getCheck();
}
}
};
</script>

View File

@@ -12,27 +12,31 @@
</q-card>
<q-card v-else style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add Script Check</div>
<div v-if="mode === 'add'" class="text-h6">Add Script Check</div>
<div v-else-if="mode === 'edit'" class="text-h6">Edit Script Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="addScriptCheck">
<q-form @submit.prevent="mode === 'add' ? addCheck() : editCheck()">
<q-card-section>
<q-select
:rules="[val => !!val || '*Required']"
dense
outlined
v-model="scriptName"
v-model="scriptcheck.script"
:options="scriptOptions"
label="Select script"
map-options
emit-value
:disable="this.mode === 'edit'"
/>
</q-card-section>
<q-card-section>
<q-input
outlined
dense
v-model.number="timeout"
v-model.number="scriptcheck.timeout"
label="Timeout (seconds)"
:rules="[
val => !!val || '*Required',
@@ -45,13 +49,14 @@
<q-select
outlined
dense
v-model="failure"
:options="failures"
v-model="scriptcheck.fails_b4_alert"
:options="failOptions"
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 v-if="mode === 'add'" label="Add" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" label="Edit" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
@@ -60,62 +65,82 @@
<script>
import axios from "axios";
import { mapState } from "vuex";
import { mapGetters } from "vuex";
import mixins from "@/mixins/mixins";
import { mapGetters, mapState } from "vuex";
export default {
name: "AddScriptCheck",
props: ["agentpk", "policypk"],
name: "ScriptCheck",
props: {
agentpk: Number,
policypk: Number,
mode: String,
checkpk: Number
},
mixins: [mixins],
data() {
return {
scriptName: null,
failure: 1,
failures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
timeout: 120
};
},
methods: {
getScripts() {
this.$store.dispatch("getScripts");
},
addScriptCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
scriptcheck: {
check_type: "script",
scriptPk: this.scriptPk,
timeout: this.timeout,
failures: this.failure
};
axios
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data));
}
script: null,
timeout: 120,
fails_b4_alert: 1
},
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
computed: {
...mapGetters(["scripts"]),
scriptOptions() {
return this.scripts.map(k => k.name).sort();
const ret = [];
this.scripts.forEach(i => {
ret.push({ label: i.name, value: i.id });
});
return ret;
}
},
methods: {
getCheck() {
axios.get(`/checks/${this.checkpk}/check/`).then(r => {
this.scriptcheck = r.data;
this.scriptcheck.script = r.data.script.id;
});
},
scriptPk(name) {
return this.scripts.filter(k => k.name === this.scriptName)[0].id;
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check: this.scriptcheck
};
axios
.post("/checks/checks/", data)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
editCheck() {
axios
.patch(`/checks/${this.checkpk}/check/`, this.scriptcheck)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
reloadChecks() {
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
}
},
created() {
this.getScripts();
if (this.mode === "edit") {
this.getCheck();
}
}
};
</script>

View File

@@ -1,8 +1,8 @@
<template>
<q-card style="min-width: 700px" class="q-pa-xs">
<q-card style="min-width: 70vw" class="q-pa-xs">
<q-card-section>
<div class="row items-center">
<div class="text-h6">{{ scriptInfo.script.name }}</div>
<div class="text-h6">{{ scriptInfo.readable_desc }}</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</div>
@@ -15,15 +15,17 @@
<code>{{ scriptInfo.retcode }}</code>
<br />
</div>
<br />
<div v-if="scriptInfo.stdout">
Standard Output:
<q-scroll-area style="height: 200px; max-height: 500px;">
Standard Output
<q-separator />
<q-scroll-area style="height: 50vh; max-height: 70vh;">
<pre>{{ scriptInfo.stdout }}</pre>
</q-scroll-area>
</div>
<div v-if="scriptInfo.stderr">
Standard Error:
<q-scroll-area style="height: 200px; max-height: 500px;">
<q-scroll-area style="height: 50vh; max-height: 70vh;">
<pre>{{ scriptInfo.stderr }}</pre>
</q-scroll-area>
</div>

View File

@@ -0,0 +1,215 @@
<template>
<q-card style="min-width: 40vw">
<q-card-section class="row items-center">
<div v-if="mode === 'add'" class="text-h6">Add Service Check</div>
<div v-else-if="mode === 'edit'" class="text-h6">Edit Service Check</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="mode === 'add' ? addCheck() : editCheck()">
<q-card-section>
<!-- policy check, either choose from a list of default services or enter manually -->
<q-radio
v-if="policypk && this.mode !== 'edit'"
v-model="winsvccheck.svc_policy_mode"
val="default"
label="Choose from defaults"
@input="clearServiceOptions"
/>
<q-radio
v-if="policypk && this.mode !== 'edit'"
v-model="winsvccheck.svc_policy_mode"
val="manual"
label="Enter manually"
@input="clearServiceOptions"
/>
<q-select
v-if="policypk && winsvccheck.svc_policy_mode === 'default' && this.mode !== 'edit'"
:rules="[val => !!val || '*Required']"
dense
outlined
v-model="winsvccheck.svc_name"
:options="serviceOptions"
label="Service"
map-options
emit-value
@input="getDisplayName"
/>
<!-- disable selection if editing -->
<q-select
v-if="policypk && winsvccheck.svc_policy_mode === 'default' && this.mode === 'edit'"
disable
dense
outlined
v-model="winsvccheck.svc_name"
:options="serviceOptions"
label="Service"
map-options
emit-value
/>
<q-input
v-if="policypk && winsvccheck.svc_policy_mode === 'manual'"
:rules="[val => !!val || '*Required']"
outlined
dense
v-model="winsvccheck.svc_name"
label="Service Name"
/>
<q-input
v-if="policypk && winsvccheck.svc_policy_mode === 'manual'"
:rules="[val => !!val || '*Required']"
outlined
dense
v-model="winsvccheck.svc_display_name"
label="Display Name"
/>
<!-- agent check -->
<!-- disable selection if editing -->
<q-select
v-if="agentpk"
:rules="[val => !!val || '*Required']"
dense
outlined
v-model="winsvccheck.svc_name"
:options="serviceOptions"
label="Service"
map-options
emit-value
@input="getDisplayName"
:disable="this.mode === 'edit'"
/>
</q-card-section>
<q-card-section>
<q-checkbox
v-model="winsvccheck.pass_if_start_pending"
label="PASS if service is in 'Start Pending' mode"
/>
<br />
<q-checkbox
v-model="winsvccheck.restart_if_stopped"
label="Restart service if it's stopped"
/>
</q-card-section>
<q-card-section>
<q-select
outlined
dense
v-model="winsvccheck.fails_b4_alert"
:options="failOptions"
label="Number of consecutive failures before alert"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn v-if="mode === 'add'" label="Add" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" label="Edit" 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 mixins from "@/mixins/mixins";
import { mapGetters } from "vuex";
export default {
name: "WinSvcCheck",
props: {
agentpk: Number,
policypk: Number,
mode: String,
checkpk: Number
},
mixins: [mixins],
data() {
return {
winsvccheck: {
check_type: "winsvc",
svc_name: null,
svc_display_name: null,
svc_policy_mode: null,
pass_if_start_pending: false,
restart_if_stopped: false,
fails_b4_alert: 1
},
svcData: [],
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
},
computed: {
...mapGetters(["agentServices"]),
serviceOptions() {
const ret = [];
this.svcData.forEach(i => {
ret.push({ label: i.display_name, value: i.name });
});
// sort alphabetically by display name
return ret.sort((a, b) => (a.label > b.label ? 1 : -1));
}
},
methods: {
clearServiceOptions() {
this.winsvccheck.svc_name = null;
this.winsvccheck.svc_display_name = null;
},
setServices() {
if (this.policypk) {
axios.get("/services/defaultservices/").then(r => {
this.svcData = Object.freeze(r.data);
this.winsvccheck.svc_policy_mode = "default";
});
} else {
this.svcData = Object.freeze(this.agentServices);
}
},
getDisplayName() {
this.winsvccheck.svc_display_name = this.serviceOptions.find(i => i.value === this.winsvccheck.svc_name).label;
},
getCheck() {
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.winsvccheck = r.data));
},
addCheck() {
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check: this.winsvccheck
};
axios
.post("/checks/checks/", data)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
editCheck() {
axios
.patch(`/checks/${this.checkpk}/check/`, this.winsvccheck)
.then(r => {
this.$emit("close");
this.reloadChecks();
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
reloadChecks() {
if (this.policypk) {
this.$store.dispatch("automation/loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
}
},
created() {
this.setServices();
},
mounted() {
if (this.mode === "edit") {
this.getCheck();
}
}
};
</script>

View File

@@ -1,118 +0,0 @@
<template>
<q-card style="width: 40vw">
<q-form @submit.prevent="editScript">
<q-card-section class="row items-center">
<div class="text-h6">Edit Script</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card-section class="row">
<div class="col-2">Name:</div>
<div class="col-10">
<q-input outlined dense v-model="name" :rules="[ val => !!val || '*Required']" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Description:</div>
<div class="col-10">
<q-input outlined dense v-model="desc" type="textarea" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">File Upload:</div>
<div class="col-10">
<q-file
v-model="script"
label="Upload new script version"
filled
counter
accept=".ps1, .bat, .py"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Type:</div>
<q-select
dense
class="col-10"
outlined
v-model="shell"
:options="shellOptions"
emit-value
map-options
:rules="[ val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section class="row items-center">
<q-btn label="Edit" color="primary" type="submit" />
</q-card-section>
</q-form>
</q-card>
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "EditScript",
mixins: [mixins],
props: ["pk"],
data() {
return {
name: null,
desc: null,
shell: null,
script: null,
shellOptions: [
{ label: "Powershell", value: "powershell" },
{ label: "Batch (CMD)", value: "cmd" },
{ label: "Python", value: "python" }
]
};
},
methods: {
getScript() {
axios.get(`/checks/getscript/${this.pk}/`).then(r => {
this.name = r.data.name;
this.desc = r.data.description;
this.shell = r.data.shell;
});
},
editScript() {
if (!this.name || !this.shell) {
this.notifyError("Name and Type are required!");
return false;
}
this.$q.loading.show();
let formData = new FormData();
if (this.script) {
formData.append("script", this.script);
}
formData.append("pk", this.pk);
formData.append("name", this.name);
formData.append("shell", this.shell);
formData.append("desc", this.desc);
axios
.put(`/checks/editscript/`, formData)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
this.$emit("edited");
this.notifySuccess("Script edited!");
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
}
},
created() {
this.getScript();
}
};
</script>

View File

@@ -0,0 +1,157 @@
<template>
<q-card style="width: 40vw">
<q-form @submit.prevent="handleScript">
<q-card-section class="row items-center">
<div v-if="mode === 'add'" class="text-h6">Add Script</div>
<div v-else-if="mode === 'edit'" class="text-h6">Edit Script</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card-section class="row">
<div class="col-2">Name:</div>
<div class="col-10">
<q-input outlined dense v-model="script.name" :rules="[ val => !!val || '*Required']" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Description:</div>
<div class="col-10">
<q-input outlined dense v-model="script.description" type="textarea" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">File Upload:</div>
<div v-if="mode === 'add'" class="col-10">
<q-file
v-model="script.filename"
label="Supported file types: .ps1, .bat, .py"
stack-label
filled
counter
accept=".ps1, .bat, .py"
:rules="[ val => !!val || '*Required']"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
</div>
<!-- don't enforce rules if edit mode -->
<div v-if="mode === 'edit'" class="col-10">
<q-file
v-model="script.filename"
label="Upload new script version"
stack-label
filled
counter
accept=".ps1, .bat, .py"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Type:</div>
<q-select
dense
class="col-10"
outlined
v-model="script.shell"
:options="shellOptions"
emit-value
map-options
:rules="[ val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section class="row items-center">
<q-btn v-if="mode === 'add'" label="Upload" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" label="Edit" color="primary" type="submit" />
</q-card-section>
</q-form>
</q-card>
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "ScriptModal",
mixins: [mixins],
props: {
scriptpk: Number,
mode: String
},
data() {
return {
script: {},
originalFile: null,
shellOptions: [
{ label: "Powershell", value: "powershell" },
{ label: "Batch (CMD)", value: "cmd" },
{ label: "Python", value: "python" }
]
};
},
methods: {
getScript() {
axios.get(`/scripts/${this.scriptpk}/script/`).then(r => {
this.originalFile = r.data.filename;
delete r.data.filename;
this.script = r.data;
});
},
handleScript() {
let formData = new FormData();
if (this.mode === "add") {
formData.append("filename", this.script.filename);
}
// only append file if uploading a new file
else if (this.mode === "edit" && this.script.filename) {
formData.append("filename", this.script.filename);
// filename needs to be the same if editing so we don't have a ghost file on server
if (this.script.filename.name !== this.originalFile) {
this.notifyError("Script filename must be the same if editing.", 4000);
return;
}
}
let url;
switch (this.mode) {
case "add":
url = "/scripts/scripts/";
break;
case "edit":
url = `/scripts/${this.scriptpk}/script/`;
break;
}
formData.append("name", this.script.name);
formData.append("shell", this.script.shell);
formData.append("description", this.script.description);
this.$q.loading.show();
axios
.put(url, formData)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
this.$emit("uploaded");
this.notifySuccess(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data.non_field_errors, 4000);
});
}
},
created() {
if (this.mode === "edit") {
this.getScript();
}
}
};
</script>

View File

@@ -1,106 +0,0 @@
<template>
<q-card style="width: 40vw">
<q-form @submit.prevent="uploadScript">
<q-card-section class="row items-center">
<div class="text-h6">Upload Script</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card-section class="row">
<div class="col-2">Name:</div>
<div class="col-10">
<q-input outlined dense v-model="name" :rules="[ val => !!val || '*Required']" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Description:</div>
<div class="col-10">
<q-input outlined dense v-model="desc" type="textarea" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">File Upload:</div>
<div class="col-10">
<q-file
v-model="script"
label="Supported file types: .ps1, .bat, .py"
stack-label
filled
counter
accept=".ps1, .bat, .py"
:rules="[ val => !!val || '*Required']"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Type:</div>
<q-select
dense
class="col-10"
outlined
v-model="shell"
:options="shellOptions"
emit-value
map-options
:rules="[ val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section class="row items-center">
<q-btn label="Upload" color="primary" type="submit" />
</q-card-section>
</q-form>
</q-card>
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "UploadScript",
mixins: [mixins],
data() {
return {
name: null,
desc: null,
shell: null,
script: null,
shellOptions: [
{ label: "Powershell", value: "powershell" },
{ label: "Batch (CMD)", value: "cmd" },
{ label: "Python", value: "python" }
]
};
},
methods: {
uploadScript() {
if (!this.name || !this.shell || !this.script) {
this.notifyError("Name, Script and Type are required!");
return false;
}
this.$q.loading.show();
let formData = new FormData();
formData.append("script", this.script);
formData.append("name", this.name);
formData.append("shell", this.shell);
formData.append("desc", this.desc);
axios
.put("/checks/uploadscript/", formData)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
this.$emit("uploaded");
this.notifySuccess("Script uploaded!");
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
}
}
};
</script>

View File

@@ -6,7 +6,7 @@
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card-section>
<p>You need to upload a script/task first</p>
<p>You need to upload a script first</p>
<p>Settings -> Script Manager</p>
</q-card-section>
</q-card>
@@ -23,7 +23,7 @@
:rules="[val => !!val || '*Required']"
dense
outlined
v-model="scriptPk"
v-model="autotask.script"
:options="scriptOptions"
label="Select task"
map-options
@@ -35,7 +35,7 @@
:rules="[val => !!val || '*Required']"
outlined
dense
v-model="taskName"
v-model="autotask.name"
label="Descriptive name of task"
/>
</q-card-section>
@@ -44,7 +44,7 @@
:rules="[val => !!val || '*Required']"
outlined
dense
v-model.number="timeout"
v-model.number="autotask.timeout"
type="number"
label="Maximum permitted execution time (seconds)"
/>
@@ -52,28 +52,38 @@
</q-step>
<q-step :name="2" title="Choose Schedule" :done="step2Done" :error="!step2Done">
<q-radio v-model="trigger" val="daily" label="Scheduled" />
<q-radio v-model="trigger" val="checkfailure" label="On check failure" />
<q-radio v-model="trigger" val="manual" label="Manual" />
<div v-if="trigger === 'daily'" class="row q-pa-lg">
<q-radio v-model="autotask.task_type" val="scheduled" label="Scheduled" @input="clear" />
<q-radio
v-model="autotask.task_type"
val="checkfailure"
label="On check failure"
@input="clear"
/>
<q-radio v-model="autotask.task_type" val="manual" label="Manual" @input="clear" />
<div v-if="autotask.task_type === 'scheduled'" class="row q-pa-lg">
<div class="col-3">
Run on Days:
<q-option-group :options="dayOptions" label="Days" type="checkbox" v-model="days" />
<q-option-group
:options="dayOptions"
label="Days"
type="checkbox"
v-model="autotask.run_time_days"
/>
</div>
<div class="col-2"></div>
<div class="col-6">
At time:
<q-time v-model="time" />
<q-time v-model="autotask.run_time_minute" />
</div>
<div class="col-1"></div>
</div>
<div v-else-if="trigger === 'checkfailure'" class="q-pa-lg">
<div v-else-if="autotask.task_type === 'checkfailure'" class="q-pa-lg">
When Check Fails:
<q-select
:rules="[val => !!val || '*Required']"
dense
outlined
v-model="assignedCheck"
v-model="autotask.assigned_check"
:options="checksOptions"
label="Select Check"
map-options
@@ -120,13 +130,15 @@ export default {
data() {
return {
step: 1,
trigger: "daily",
time: null,
taskName: null,
scriptPk: null,
assignedCheck: null,
timeout: 120,
days: [],
autotask: {
script: null,
assigned_check: null,
name: null,
run_time_days: [],
run_time_minute: null,
task_type: "scheduled",
timeout: 120
},
dayOptions: [
{ label: "Monday", value: 0 },
{ label: "Tuesday", value: 1 },
@@ -139,6 +151,11 @@ export default {
};
},
methods: {
clear() {
this.autotask.assigned_check = null;
this.autotask.run_time_days = [];
this.autotask.run_time_minute = null;
},
addTask() {
if (!this.step1Done || !this.step2Done) {
this.notifyError("Some steps incomplete");
@@ -147,16 +164,9 @@ export default {
const data = {
...pk,
name: this.taskName,
script: this.scriptPk,
trigger: this.trigger,
check: this.assignedCheck,
time: this.time,
days: this.days,
timeout: this.timeout
autotask: this.autotask
};
console.log(data);
axios
.post("tasks/automatedtasks/", data)
.then(r => {
@@ -180,48 +190,34 @@ export default {
},
computed: {
...mapGetters(["selectedAgentPk", "scripts"]),
/* ...mapState({
checks: state => (this.policypk ? state.automation.checks : state.agentChecks)
}), */
// I have no idea why this works and the above doesn't
checks() {
return this.policypk ? this.$store.state.automation.checks : this.$store.state.agentChecks;
},
allChecks() {
return [
...this.checks.diskchecks,
...this.checks.cpuloadchecks,
...this.checks.memchecks,
...this.checks.scriptchecks,
...this.checks.winservicechecks,
...this.checks.pingchecks,
...this.checks.eventlogchecks
];
},
checksOptions() {
const r = [];
this.allChecks.forEach(k => {
// some checks may have the same primary key so add the check type to make them unique
r.push({ label: k.readable_desc, value: `${k.id}|${k.check_type}` });
this.checks.forEach(i => {
r.push({ label: i.readable_desc, value: i.id });
});
return r;
},
scriptOptions() {
const r = [];
this.scripts.forEach(k => {
r.push({ label: k.name, value: k.id });
this.scripts.forEach(i => {
r.push({ label: i.name, value: i.id });
});
return r;
},
step1Done() {
return this.step > 1 && this.scriptPk !== null && this.taskName !== null ? true : false;
return this.step > 1 && this.autotask.script !== null && this.autotask.name && this.autotask.timeout
? true
: false;
},
step2Done() {
if (this.trigger === "daily") {
return this.days !== null && this.days.length !== 0 && this.time !== null ? true : false;
} else if (this.trigger === "checkfailure") {
return this.assignedCheck !== null && this.assignedCheck.length !== 0 ? true : false;
} else if (this.trigger === "manual") {
if (this.autotask.task_type === "scheduled") {
return this.autotask.run_time_days.length !== 0 && this.autotask.run_time_minute !== null ? true : false;
} else if (this.autotask.task_type === "checkfailure") {
return this.autotask.assigned_check !== null ? true : false;
} else if (this.autotask.task_type === "manual") {
return true;
} else {
return false;

View File

@@ -4,22 +4,14 @@ export default {
namespaced: true,
state: {
selectedPolicy: null,
checks: {},
checks: [],
automatedTasks: {},
policies: [],
},
getters: {
allChecks(state) {
return [
...state.checks.diskchecks,
...state.checks.cpuloadchecks,
...state.checks.memchecks,
...state.checks.scriptchecks,
...state.checks.winservicechecks,
...state.checks.pingchecks,
...state.checks.eventlogchecks
];
checks(state) {
return state.checks;
},
selectedPolicyPk(state) {
return state.selectedPolicy;
@@ -56,7 +48,7 @@ export default {
});
},
loadPolicyChecks(context, pk) {
axios.get(`/checks/${pk}/loadpolicychecks/`).then(r => {
axios.get(`/automation/${pk}/policychecks/`).then(r => {
context.commit("setPolicyChecks", r.data);
});
},

View File

@@ -24,7 +24,7 @@ export const store = new Vuex.Store({
selectedRow: null,
agentSummary: {},
winUpdates: {},
agentChecks: {},
agentChecks: null,
automatedTasks: {},
agentTableLoading: false,
treeLoading: false,
@@ -39,6 +39,15 @@ export const store = new Vuex.Store({
selectedAgentPk(state) {
return state.agentSummary.id;
},
agentDisks(state) {
return state.agentSummary.disks;
},
agentServices(state) {
return state.agentSummary.services;
},
checks(state) {
return state.agentChecks;
},
managedByWsus(state) {
return state.agentSummary.managed_by_wsus;
},
@@ -104,7 +113,7 @@ export const store = new Vuex.Store({
},
destroySubTable(state) {
(state.agentSummary = {}),
(state.agentChecks = {}),
(state.agentChecks = null),
(state.winUpdates = {});
(state.installedSoftware = []);
state.selectedRow = "";
@@ -120,7 +129,7 @@ export const store = new Vuex.Store({
})
},
getScripts(context) {
axios.get("/checks/getscripts/").then(r => {
axios.get("/scripts/scripts/").then(r => {
context.commit("SET_SCRIPTS", r.data);
});
},
@@ -144,11 +153,17 @@ export const store = new Vuex.Store({
context.commit("setChecks", r.data);
});
},
editCheckAlertAction(context, data) {
return axios.patch("/checks/checkalert/", data);
loadDefaultServices(context) {
return axios.get("/services/getdefaultservices/");
},
deleteCheck(context, data) {
return axios.delete("checks/deletestandardcheck/", { data: data });
loadAgentServices(context, agentpk) {
return axios.get(`/services/${agentpk}/services/`);
},
editCheckAlert(context, pk, data) {
return axios.patch(`/checks/${pk}/check/`, data);
},
deleteCheck(context, pk) {
return axios.delete(`/checks/${pk}/check/`);
},
editAutoTask(context, data) {
return axios.patch(`/tasks/${data.id}/automatedtasks/`, data);
@@ -187,7 +202,7 @@ export const store = new Vuex.Store({
child_single.push({
label: sites_arr[i].split("|")[0],
id: sites_arr[i].split("|")[1],
raw: sites_arr[i],
raw: `Site|${sites_arr[i]}`,
header: "generic",
icon: "apartment",
iconColor: sites_arr[i].split("|")[2]
@@ -196,7 +211,7 @@ export const store = new Vuex.Store({
output.push({
label: prop.split("|")[0],
id: prop.split("|")[1],
raw: prop,
raw: `Client|${prop}`,
header: "root",
icon: "business",
iconColor: prop.split("|")[2],

View File

@@ -202,12 +202,12 @@ export default {
let client, site, url;
try {
client = this.$refs.tree.meta[activenode].parent.key.split("|")[0];
site = activenode.split("|")[0];
client = this.$refs.tree.meta[activenode].parent.key.split("|")[1];
site = activenode.split("|")[1];
url = `/agents/bysite/${client}/${site}/`;
} catch (e) {
try {
client = activenode.split("|")[0];
client = activenode.split("|")[1];
} catch (e) {
return false;
}

View File

@@ -6,8 +6,18 @@ import "@/quasar.js"
const localVue = createLocalVue();
localVue.use(Vuex);
describe("AutomationManager.vue", () => {
const bodyWrapper = createWrapper(document.body);
// This is needed to remove q-dialogs since body doesn't rerender
afterEach(() => {
const dialogs = document.querySelectorAll(".q-dialog");
const menus = document.querySelectorAll(".q-menu");
dialogs.forEach(x => x.remove());
menus.forEach(x => x.remove());
});
describe("AutomationManager.vue", () => {
const policiesData = [
{
id: 1,
@@ -29,7 +39,6 @@ describe("AutomationManager.vue", () => {
}
];
const bodyWrapper = createWrapper(document.body);
let wrapper;
let state, mutations, actions, store;
@@ -83,23 +92,12 @@ describe("AutomationManager.vue", () => {
});
// Runs after every test
// This is needed to remove q-dialogs since body doesn't rerender
afterEach(() => {
const dialogs = document.querySelectorAll(".q-dialog");
const menus = document.querySelectorAll(".q-menu");
dialogs.forEach(x => x.remove());
menus.forEach(x => x.remove());
});
// The Tests
it("calls vuex loadPolicies action on mount", () => {
expect(actions.loadPolicies).toHaveBeenCalled();
expect(mutations.setSelectedPolicy).toHaveBeenCalledWith(expect.anything(), null);
expect(mutations.setPolicyChecks).toHaveBeenCalledWith(expect.anything(), {});
expect(mutations.setPolicyChecks).toHaveBeenCalledWith(expect.anything(), []);
expect(mutations.setPolicyAutomatedTasks).toHaveBeenCalledWith(expect.anything(), {});
});
@@ -208,7 +206,7 @@ describe("AutomationManager.vue", () => {
expect(bodyWrapper.find(".q-dialog").exists()).toBe(true);
expect(mutations.setSelectedPolicy).toHaveBeenCalledWith(expect.anything(), null);
expect(mutations.setPolicyChecks).toHaveBeenCalledWith(expect.anything(), {});
expect(mutations.setPolicyChecks).toHaveBeenCalledWith(expect.anything(), []);
expect(mutations.setPolicyAutomatedTasks).toHaveBeenCalledWith(expect.anything(), {});
});
@@ -220,7 +218,7 @@ describe("AutomationManager.vue", () => {
button.trigger("click");
expect(actions.loadPolicies).toHaveBeenCalled();
expect(mutations.setSelectedPolicy).toHaveBeenCalledWith(expect.anything(), null);
expect(mutations.setPolicyChecks).toHaveBeenCalledWith(expect.anything(), {});
expect(mutations.setPolicyChecks).toHaveBeenCalledWith(expect.anything(), []);
expect(mutations.setPolicyAutomatedTasks).toHaveBeenCalledWith(expect.anything(), {});
});

View File

@@ -0,0 +1,102 @@
const common = {
email_alert: false,
failure_count: 0,
failures: 5,
history: [],
last_run: null,
more_info: null,
status: "pending",
task_on_failure: null,
text_alert: false,
agent: null,
policy: 1
};
const diskcheck = {
id: 1,
check_type: "diskspace",
disk: "C:",
threshold: 25,
readable_desc: "Disk space check: Drive C",
...common
};
const cpuloadcheck = {
id: 2,
check_type: "cpuload",
cpuload: 85,
readable_desc: "CPU Load check: > 85%",
...common
};
const memcheck = {
id: 3,
check_type: "memory",
threshold: 75,
readable_desc: "Memory checks: > 85%",
...common
};
const scriptcheck = {
id: 4,
check_type: "script",
execution_time: "0.0000",
retcode: 0,
script: {
description: "Test",
filename: "local_admin_group.bat",
filepath: "salt://scripts//userdefined//local_admin_group.bat",
id: 1,
name: "Test Script",
shell: "cmd"
},
stderr: null,
stdout: null,
timeout: 120,
readable_desc: "Script check: Test Script",
...common
};
const winservicecheck = {
id: 5,
check_type: "winsvc",
pass_if_start_pending: false,
restart_if_stopped: false,
svc_display_name: "Agent Activation Runtime_1232as",
svc_name: "AarSvc_1232as",
readable_desc: "Service check: Agent Activation Runtime_1232as",
...common
};
const pingcheck = {
id: 6,
name: "fghfgh",
check_type: "ping",
ip: "10.10.10.10",
readable_desc: "Ping Check: Test Ping Check",
...common
};
const eventlogcheck = {
id: 7,
desc: "asasasa",
check_type: "eventlog",
log_name: "Application",
event_id: 1456,
event_type: "ERROR",
fail_when: "contains",
search_last_days: 1,
readable_desc: "Event log check: asdsasa",
...common,
};
export {
diskcheck,
cpuloadcheck,
memcheck,
scriptcheck,
winservicecheck,
pingcheck,
eventlogcheck
}

View File

@@ -7,80 +7,126 @@ import "@/quasar.js";
const localVue = createLocalVue();
localVue.use(Vuex);
describe("PolicyForm.vue", () => {
/*** TEST DATA ***/
const clients = [
{
id: 1,
client: "Test Client"
},
{
id: 2,
client: "Test Client2"
},
{
id: 3,
client: "Test Client3"
}
];
const sites = [
{
id: 1,
site: "Site Name",
client_name: "Test Client"
},
{
id: 2,
site: "Site Name2",
client_name: "Test Client2"
}
];
const clients = [
{
id: 1,
client: "Test Client"
},
{
id: 2,
client: "Test Client2"
},
{
id: 3,
client: "Test Client3"
}
];
const sites = [
{
id: 1,
site: "Site Name",
client_name: "Test Client"
},
{
id: 2,
site: "Site Name2",
client_name: "Test Client2"
}
];
const policy = {
id: 1,
name: "Test Policy",
desc: "Test Desc",
active: true,
clients: [],
sites: []
};
const policy = {
id: 1,
name: "Test Policy",
desc: "Test Desc",
active: true,
clients: [],
sites: []
let actions, rootActions, store;
beforeEach(() => {
rootActions = {
loadClients: jest.fn(() => new Promise(res => res({ data: clients }))),
loadSites: jest.fn(() => new Promise(res => res({ data: sites }))),
};
let actions, rootActions, store;
actions = {
loadPolicy: jest.fn(() => new Promise(res => res({ data: policy }))),
addPolicy: jest.fn(() => new Promise(res => res())),
editPolicy: jest.fn(() => new Promise(res => res())),
};
// Runs before every test
store = new Vuex.Store({
actions: rootActions,
modules: {
automation: {
namespaced: true,
actions,
}
}
});
})
/*** TEST SUITES ***/
describe("PolicyForm.vue when editting", () => {
let wrapper;
beforeEach(() => {
rootActions = {
loadClients: jest.fn(() => new Promise(res => res({ data: clients }))),
loadSites: jest.fn(() => new Promise(res => res({ data: sites }))),
};
actions = {
loadPolicy: jest.fn(() => new Promise(res => res({ data: policy }))),
addPolicy: jest.fn(() => new Promise(res => res())),
editPolicy: jest.fn(() => new Promise(res => res())),
};
store = new Vuex.Store({
actions: rootActions,
modules: {
automation: {
namespaced: true,
actions,
}
wrapper = mount(PolicyForm, {
localVue,
store,
propsData: {
pk: 1
}
});
});
// The Tests
it("calls vuex actions on mount", () => {
/*** TESTS ***/
it("calls vuex actions on mount with pk prop set", () => {
const wrapper = mount(PolicyForm, {
expect(rootActions.loadClients).toHaveBeenCalled();
expect(rootActions.loadSites).toHaveBeenCalled();
expect(actions.loadPolicy).toHaveBeenCalledWith(expect.anything(), 1);
});
it("sends the correct edit action on submit", async () => {
await flushPromises();
const form = wrapper.findComponent({ ref: "form" });
form.vm.$emit("submit");
await wrapper.vm.$nextTick();
expect(actions.addPolicy).not.toHaveBeenCalled();
expect(actions.editPolicy).toHaveBeenCalledWith(expect.anything(), policy);
});
it("Renders correct title on edit", () => {
expect(wrapper.vm.title).toBe("Edit Policy");
});
});
describe("PolicyForm.vue when adding", () => {
let wrapper;
beforeEach(() => {
wrapper = mount(PolicyForm, {
localVue,
store
});
});
/*** TESTS ***/
it("calls vuex actions on mount", () => {
expect(rootActions.loadClients).toHaveBeenCalled();
expect(rootActions.loadSites).toHaveBeenCalled();
@@ -89,29 +135,8 @@ describe("PolicyForm.vue", () => {
});
it("calls vuex actions on mount with pk prop set", () => {
mount(PolicyForm, {
localVue,
store,
propsData: {
pk: 1
}
});
expect(rootActions.loadClients).toHaveBeenCalled();
expect(rootActions.loadSites).toHaveBeenCalled();
expect(actions.loadPolicy).toHaveBeenCalledWith(expect.anything(), 1);
});
it("Sets client and site options correctly", async () => {
const wrapper = mount(PolicyForm, {
localVue,
store
});
// Make sure the promises are resolved
await flushPromises();
@@ -119,13 +144,8 @@ describe("PolicyForm.vue", () => {
expect(wrapper.vm.siteOptions).toHaveLength(2);
});
it("sends the correct add action on submit", async () => {
const wrapper = mount(PolicyForm, {
localVue,
store
});
it("sends the correct add action on submit", async () => {
wrapper.setData({name: "Test Policy"});
const form = wrapper.findComponent({ ref: "form" });
@@ -137,33 +157,8 @@ describe("PolicyForm.vue", () => {
});
it("sends the correct edit action on submit", async () => {
const wrapper = mount(PolicyForm, {
localVue,
store,
propsData: {
pk: 1
}
});
await flushPromises();
const form = wrapper.findComponent({ ref: "form" });
form.vm.$emit("submit");
await wrapper.vm.$nextTick();
expect(actions.addPolicy).not.toHaveBeenCalled();
expect(actions.editPolicy).toHaveBeenCalledWith(expect.anything(), policy);
});
it("sends error when name isn't set on submit", async () => {
const wrapper = mount(PolicyForm, {
localVue,
store
});
const form = wrapper.findComponent({ ref: "form" });
form.vm.$emit("submit");
await wrapper.vm.$nextTick();
@@ -172,28 +167,9 @@ describe("PolicyForm.vue", () => {
expect(actions.editPolicy).not.toHaveBeenCalled();
});
it("Renders correct title on edit", () => {
const wrapper = mount(PolicyForm, {
localVue,
store,
propsData: {
pk: 1
}
});
expect(wrapper.vm.title).toBe("Edit Policy");
});
it("Renders correct title on add", () => {
const wrapper = mount(PolicyForm, {
localVue,
store,
});
expect(wrapper.vm.title).toBe("Add Policy");
});
});
});

View File

@@ -0,0 +1,391 @@
import { mount, shallowMount, createLocalVue, createWrapper } from "@vue/test-utils";
import PolicyChecksTab from "@/components/automation/PolicyChecksTab";
import Vuex from "vuex";
import "@/quasar.js";
// Import Test Data
import {
diskcheck,
cpuloadcheck,
memcheck,
scriptcheck,
winservicecheck,
pingcheck,
eventlogcheck
} from "./checksData.js";
const localVue = createLocalVue();
localVue.use(Vuex);
const bodyWrapper = createWrapper(document.body);
// This is needed to remove q-dialogs since body doesn't rerender
afterEach(() => {
const dialogs = document.querySelectorAll(".q-dialog");
const menus = document.querySelectorAll(".q-menu");
dialogs.forEach(x => x.remove());
menus.forEach(x => x.remove());
});
/*** TEST SUITES ***/
describe("PolicyChecksTab.vue with no policy selected", () => {
let wrapper, state, getters, store;
// Runs before every test
beforeEach(() => {
// Create the Test store
// Create the Test store
state = {
checks: [],
selectedPolicy: null
};
getters = {
checks(state) {
return state.checks
},
selectedPolicyPk(state) {
return state.selectedPolicy
}
};
store = new Vuex.Store({
modules: {
automation: {
namespaced: true,
state,
getters
}
}
});
wrapper = shallowMount(PolicyChecksTab, {
store,
localVue
});
});
/*** TESTS ***/
it("renders text when policy is selected with no checks", () => {
expect(wrapper.html()).toContain("No Policy Selected");
});
});
describe("PolicyChecksTab.vue with policy selected and no checks", () => {
// Used for the add check test loop
const addChecksMenu = [
{ name: "DiskSpaceCheck", index: 0 },
{ name: "PingCheck", index: 1},
{ name: "CpuLoadCheck", index: 2},
{ name: "MemCheck", index: 3},
{ name: "WinSvcCheck", index: 4},
{ name: "ScriptCheck", index: 5},
{ name: "EventLogCheck", index: 6}
];
let wrapper, store, state, actions, getters;
// Runs before every test
beforeEach(() => {
// Create the Test store
state = {
checks: [],
selectedPolicy: 1
};
getters = {
checks(state) {
return state.checks
},
selectedPolicyPk(state) {
return state.selectedPolicy
}
};
actions = {
loadPolicyChecks: jest.fn()
};
store = new Vuex.Store({
modules: {
automation: {
namespaced: true,
state,
getters,
actions
}
}
});
// Mount all sub components except the ones specified
wrapper = mount(PolicyChecksTab, {
store,
localVue,
stubs: [
"DiskSpaceCheck",
"PingCheck",
"CpuLoadCheck",
"MemCheck",
"WinSvcCheck",
"ScriptCheck",
"EventLogCheck"
]
});
});
it("renders text when policy is selected with no checks", () => {
expect(wrapper.html()).toContain("No Checks");
});
it("sends vuex actions on refresh button click", () => {
wrapper.findComponent({ ref: "refresh" }).trigger("click");
expect(actions.loadPolicyChecks).toHaveBeenCalledWith(expect.anything(), 1);
});
// Create a test for each Add modal
addChecksMenu.forEach(item => {
it(`opens ${item.name} Dialog`, async () => {
const addButton = wrapper.findComponent({ ref: "add" });
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
expect(bodyWrapper.find(".q-menu").exists()).toBe(false);
await addButton.trigger("click");
expect(bodyWrapper.find(".q-menu").exists()).toBe(true);
// Selects correct menu item
await bodyWrapper.findAll(".q-item").wrappers[item.index].trigger("click");
expect(bodyWrapper.find(".q-dialog").exists()).toBe(true);
expect(wrapper.vm.showDialog).toBe(true);
expect(wrapper.vm.dialogComponent).toBe(item.name);
});
});
});
describe("PolicyChecksTab.vue with policy selected and checks", () => {
// Used for the edit check test loop
const editChecksModals = [
{name: "DiskSpaceCheck", index: 0, id: 1},
{name: "CpuLoadCheck", index: 1, id: 2},
{name: "MemCheck", index: 2, id: 3},
{name: "ScriptCheck", index: 3, id: 4},
{name: "WinSvcCheck", index: 4, id: 5},
{name: "PingCheck", index: 5, id: 6},
{name: "EventLogCheck", index: 6, id: 7}
];
let state, rootActions, actions, getters, store, wrapper;
// Runs before every test
beforeEach(() => {
// Create the Test store
// Create the Test store
state = {
checks: [
diskcheck,
cpuloadcheck,
memcheck,
scriptcheck,
winservicecheck,
pingcheck,
eventlogcheck
],
selectedPolicy: 1
};
getters = {
checks(state) {
return state.checks
},
selectedPolicyPk(state) {
return state.selectedPolicy
}
};
actions = {
loadPolicyChecks: jest.fn()
};
rootActions = {
editCheckAlertAction: jest.fn(),
deleteCheck: jest.fn()
};
store = new Vuex.Store({
actions: rootActions,
modules: {
automation: {
namespaced: true,
state,
getters,
actions
}
}
});
// Mount all sub components except the ones specified
wrapper = mount(PolicyChecksTab, {
store,
localVue,
stubs: [
"DiskSpaceCheck",
"PingCheck",
"CpuLoadCheck",
"MemCheck",
"WinSvcCheck",
"ScriptCheck",
"EventLogCheck",
"PolicyStatus"
]
});
});
/*** TESTS ***/
it("renders the correct number of rows based on checks", () => {
const rows = wrapper.findAll(".q-table > tbody > .q-tr").wrappers;
expect(rows).toHaveLength(7);
});
// Create a test for each Edit modal
editChecksModals.forEach(item => {
it(`show ${item.name} Dialog`, async () => {
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
expect(bodyWrapper.find(".q-menu").exists()).toBe(false);
const row = wrapper.findAll(".q-table > tbody > .q-tr").wrappers[item.index];
await row.trigger("contextmenu");
expect(bodyWrapper.find(".q-menu").exists()).toBe(true);
await bodyWrapper.find("#context-edit").trigger("click");
expect(bodyWrapper.find(".q-dialog").exists()).toBe(true);
expect(wrapper.vm.showDialog).toBe(true);
expect(wrapper.vm.dialogComponent).toBe(item.name);
expect(wrapper.vm.editCheckPK).toBe(item.id);
});
});
it("shows policy status modal on cell click", async () => {
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
const row = wrapper.findAll(".status-cell").wrappers[0];
await row.trigger("click");
expect(bodyWrapper.find(".q-dialog").exists()).toBe(true);
expect(wrapper.vm.statusCheck).toEqual(diskcheck);
});
it("shows policy status modal on context menu item click", async () => {
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
expect(bodyWrapper.find(".q-menu").exists()).toBe(false);
const row = wrapper.findAll(".q-table > tbody > .q-tr").wrappers[0];
await row.trigger("contextmenu");
expect(bodyWrapper.find(".q-menu").exists()).toBe(true);
await bodyWrapper.find("#context-status").trigger("click");
expect(bodyWrapper.find(".q-dialog").exists()).toBe(true);
expect(wrapper.vm.statusCheck).toEqual(diskcheck);
});
it("renders correct description for checks", () => {
expect(wrapper.find(".q-table").html()).toContain("Disk Space Drive C: &gt; 25%");
expect(wrapper.find(".q-table").html()).toContain("Avg CPU Load &gt; 85%");
expect(wrapper.find(".q-table").html()).toContain("Avg memory usage &gt; 75%");
expect(wrapper.find(".q-table").html()).toContain("Script check: Test Script");
expect(wrapper.find(".q-table").html()).toContain("Service Check - Agent Activation Runtime_1232as");
expect(wrapper.find(".q-table").html()).toContain("Ping fghfgh (10.10.10.10)");
expect(wrapper.find(".q-table").html()).toContain("Event Log Check - asasasa");
});
it("deletes check", async () => {
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
expect(bodyWrapper.find(".q-menu").exists()).toBe(false);
const row = wrapper.findAll(".q-table > tbody > .q-tr").wrappers[0];
await row.trigger("contextmenu");
expect(bodyWrapper.find(".q-menu").exists()).toBe(true);
await bodyWrapper.find("#context-delete").trigger("click");
expect(bodyWrapper.find(".q-dialog").exists()).toBe(true);
//Get OK button on confirmation dialog and click it
await bodyWrapper.findAll(".q-btn").wrappers[1].trigger("click");
expect(rootActions.deleteCheck).toHaveBeenCalledWith(expect.anything(), {pk: 1, checktype:"diskspace"});
expect(actions.loadPolicyChecks).toHaveBeenCalled();
});
it("enables and disables text alerts for check", async () => {
//Get first checkbox in first row
const row = wrapper.findAll(".q-checkbox").wrappers[0];
//Enable Text Alert
await row.trigger("click");
expect(rootActions.editCheckAlertAction).toHaveBeenCalledWith(expect.anything(), {
alertType: "text",
checkid: 1,
category: "diskspace",
action: "enabled"
});
//Disable Text Alert
await row.trigger("click");
expect(rootActions.editCheckAlertAction).toHaveBeenCalledWith(expect.anything(), {
alertType: "text",
checkid: 1,
category: "diskspace",
action: "disabled"
});
});
it("enables and disables email alerts for check", async () => {
//Get second checkbox in first row
const row = wrapper.findAll(".q-checkbox").wrappers[1];
//Enable Text Alert
await row.trigger("click");
expect(rootActions.editCheckAlertAction).toHaveBeenCalledWith(expect.anything(), {
alertType: "email",
checkid: 1,
category: "diskspace",
action: "enabled"
});
//Disable Text Alert
await row.trigger("click");
expect(rootActions.editCheckAlertAction).toHaveBeenCalledWith(expect.anything(), {
alertType: "email",
checkid: 1,
category: "diskspace",
action: "disabled"
});
});
/* TODO: test @close and @hide events */
});

View File

@@ -0,0 +1,8 @@
import { mount, shallowMount, createLocalVue, createWrapper } from "@vue/test-utils";
import PolicyAutomatedTasksTab from "@/components/automation/PolicyAutomatedTasksTab";
import Vuex from "vuex";
import "@/quasar.js";
describe.skip("PolicyAutomatedTasks.vue", () => {
// TODO after checks rework
});