fix check threshold modals and add client/serverside validation. Allow viewing alert script results in alerts overview. Fix diskspace check history computation. other fixes and improvements
This commit is contained in:
@@ -534,14 +534,22 @@ class Agent(BaseAuditModel):
|
||||
):
|
||||
templates.append(core.workstation_policy.alert_template)
|
||||
|
||||
# check if client, site, or agent has been excluded from templates in order and return if not
|
||||
# go through the templates and return the first one that isn't excluded
|
||||
for template in templates:
|
||||
# check if client, site, or agent has been excluded from template
|
||||
if (
|
||||
client.pk in template.excluded_clients.all()
|
||||
or site.pk in template.excluded_sites.all()
|
||||
or self.pk in template.excluded_agents.all()
|
||||
):
|
||||
continue
|
||||
|
||||
# see if template is excluding desktops
|
||||
if (
|
||||
self.monitoring_type == "workstation"
|
||||
and not template.agent_include_desktops
|
||||
):
|
||||
continue
|
||||
else:
|
||||
return template
|
||||
|
||||
@@ -751,7 +759,7 @@ class Agent(BaseAuditModel):
|
||||
alert.resolved_action_execution_time = "{:.4f}".format(
|
||||
r["execution_time"]
|
||||
)
|
||||
alert.resolved_action_run = True
|
||||
alert.resolved_action_run = djangotime.now()
|
||||
alert.save()
|
||||
else:
|
||||
logger.error(
|
||||
@@ -825,7 +833,7 @@ class Agent(BaseAuditModel):
|
||||
alert.action_stdout = r["stdout"]
|
||||
alert.action_stderr = r["stderr"]
|
||||
alert.action_execution_time = "{:.4f}".format(r["execution_time"])
|
||||
alert.action_run = True
|
||||
alert.action_run = djangotime.now()
|
||||
alert.save()
|
||||
else:
|
||||
logger.error(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 3.1.4 on 2021-02-07 14:26
|
||||
# Generated by Django 3.1.4 on 2021-02-12 14:08
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
@@ -8,14 +8,44 @@ import django.db.models.deletion
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scripts', '0006_auto_20201210_2145'),
|
||||
('autotasks', '0016_automatedtask_status'),
|
||||
('agents', '0028_auto_20210206_1534'),
|
||||
('agents', '0029_delete_agentoutage'),
|
||||
('clients', '0008_auto_20201103_1430'),
|
||||
('autotasks', '0017_auto_20210210_1512'),
|
||||
('scripts', '0005_auto_20201207_1606'),
|
||||
('alerts', '0003_auto_20201021_1815'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_execution_time',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_retcode',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_run',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_stderr',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_stdout',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_timeout',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='alert_type',
|
||||
@@ -26,11 +56,66 @@ class Migration(migrations.Migration):
|
||||
name='assigned_task',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='alert', to='autotasks.automatedtask'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='email_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='hidden',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_execution_time',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_retcode',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_run',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_stderr',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_stdout',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_timeout',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_email_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_on',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_sms_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='sms_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='snoozed',
|
||||
@@ -47,6 +132,8 @@ class Migration(migrations.Migration):
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('action_args', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255, null=True), blank=True, default=list, null=True, size=None)),
|
||||
('resolved_action_args', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255, null=True), blank=True, default=list, null=True, size=None)),
|
||||
('email_recipients', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=100), blank=True, default=list, null=True, size=None)),
|
||||
('text_recipients', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=100), blank=True, default=list, null=True, size=None)),
|
||||
('email_from', models.EmailField(blank=True, max_length=254, null=True)),
|
||||
@@ -75,10 +162,11 @@ class Migration(migrations.Migration):
|
||||
('task_always_text', models.BooleanField(blank=True, default=False, null=True)),
|
||||
('task_always_alert', models.BooleanField(blank=True, default=False, null=True)),
|
||||
('task_periodic_alert_days', models.PositiveIntegerField(blank=True, default=0, null=True)),
|
||||
('actions', models.ManyToManyField(blank=True, related_name='alert_templates', to='scripts.Script')),
|
||||
('action', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='alert_template', to='scripts.script')),
|
||||
('excluded_agents', models.ManyToManyField(blank=True, related_name='alert_exclusions', to='agents.Agent')),
|
||||
('excluded_clients', models.ManyToManyField(blank=True, related_name='alert_exclusions', to='clients.Client')),
|
||||
('excluded_sites', models.ManyToManyField(blank=True, related_name='alert_exclusions', to='clients.Site')),
|
||||
('resolved_action', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='resolved_alert_template', to='scripts.script')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 3.1.4 on 2021-02-07 18:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scripts', '0006_auto_20201210_2145'),
|
||||
('alerts', '0004_auto_20210207_1426'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='alerttemplate',
|
||||
name='resolved_actions',
|
||||
field=models.ManyToManyField(blank=True, related_name='alert_templates_resolved', to='scripts.Script'),
|
||||
),
|
||||
]
|
||||
@@ -1,129 +0,0 @@
|
||||
# Generated by Django 3.1.4 on 2021-02-10 15:12
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scripts', '0006_auto_20201210_2145'),
|
||||
('alerts', '0005_alerttemplate_resolved_actions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='alerttemplate',
|
||||
name='actions',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='alerttemplate',
|
||||
name='resolved_actions',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_execution_time',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_retcode',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_run',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_stderr',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_stdout',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='action_timeout',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='email_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='hidden',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_execution_time',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_retcode',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_run',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_stderr',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_stdout',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_action_timeout',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_email_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='resolved_sms_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alert',
|
||||
name='sms_sent',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alerttemplate',
|
||||
name='action',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='alert_template', to='scripts.script'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alerttemplate',
|
||||
name='action_args',
|
||||
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255, null=True), blank=True, default=list, null=True, size=None),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alerttemplate',
|
||||
name='resolved_action',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='resolved_alert_template', to='scripts.script'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alerttemplate',
|
||||
name='resolved_action_args',
|
||||
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255, null=True), blank=True, default=list, null=True, size=None),
|
||||
),
|
||||
]
|
||||
@@ -3,8 +3,6 @@ from django.contrib.postgres.fields import ArrayField
|
||||
from django.db.models.fields import BooleanField, PositiveIntegerField
|
||||
from django.utils import timezone as djangotime
|
||||
|
||||
from typing import Union, Type
|
||||
|
||||
SEVERITY_CHOICES = [
|
||||
("info", "Informational"),
|
||||
("warning", "Warning"),
|
||||
@@ -56,13 +54,13 @@ class Alert(models.Model):
|
||||
sms_sent = models.DateTimeField(null=True, blank=True)
|
||||
resolved_sms_sent = models.DateTimeField(null=True, blank=True)
|
||||
hidden = models.BooleanField(default=False)
|
||||
action_run = models.BooleanField(default=False)
|
||||
action_run = models.DateTimeField(null=True, blank=True)
|
||||
action_timeout = models.PositiveIntegerField(null=True, blank=True)
|
||||
action_stdout = models.TextField(null=True, blank=True)
|
||||
action_stderr = models.TextField(null=True, blank=True)
|
||||
action_retcode = models.IntegerField(null=True, blank=True)
|
||||
action_execution_time = models.CharField(max_length=100, null=True, blank=True)
|
||||
resolved_action_run = models.BooleanField(default=False)
|
||||
resolved_action_run = models.DateTimeField(null=True, blank=True)
|
||||
resolved_action_timeout = models.PositiveIntegerField(null=True, blank=True)
|
||||
resolved_action_stdout = models.TextField(null=True, blank=True)
|
||||
resolved_action_stderr = models.TextField(null=True, blank=True)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 3.1.4 on 2021-02-07 14:26
|
||||
# Generated by Django 3.1.4 on 2021-02-12 14:08
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
@@ -7,7 +7,7 @@ import django.db.models.deletion
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('alerts', '0004_auto_20210207_1426'),
|
||||
('alerts', '0004_auto_20210212_1408'),
|
||||
('automation', '0006_delete_policyexclusions'),
|
||||
]
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class Policy(BaseAuditModel):
|
||||
def delete(self, *args, **kwargs):
|
||||
from automation.tasks import generate_agent_checks_task
|
||||
|
||||
agents = list(self.related_agents().values_list("pk", flat=True))
|
||||
agents = list(self.related_agents().only("pk").values_list("pk", flat=True))
|
||||
super(BaseAuditModel, self).delete(*args, **kwargs)
|
||||
|
||||
generate_agent_checks_task.delay(agents, create_tasks=True)
|
||||
|
||||
@@ -115,7 +115,7 @@ def generate_agent_tasks_from_policies_task(policypk):
|
||||
"pk", "monitoring_type"
|
||||
)
|
||||
else:
|
||||
agents = policy.related_agents()
|
||||
agents = policy.related_agents().only("pk")
|
||||
|
||||
for agent in agents:
|
||||
agent.generate_tasks_from_policies()
|
||||
|
||||
@@ -3,6 +3,7 @@ import random
|
||||
import string
|
||||
import datetime as dt
|
||||
|
||||
from django.utils import timezone as djangotime
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
@@ -289,7 +290,7 @@ class AutomatedTask(BaseAuditModel):
|
||||
alert.resolved_action_execution_time = "{:.4f}".format(
|
||||
r["execution_time"]
|
||||
)
|
||||
alert.resolved_action_run = True
|
||||
alert.resolved_action_run = djangotime.now()
|
||||
alert.save()
|
||||
else:
|
||||
logger.error(
|
||||
@@ -303,6 +304,11 @@ class AutomatedTask(BaseAuditModel):
|
||||
else:
|
||||
alert = Alert.objects.get(assigned_task=self, resolved=False)
|
||||
|
||||
# check if alert severity changed on task and update the alert
|
||||
if self.alert_severity != alert.severity:
|
||||
alert.severity = self.alert_severity
|
||||
alert.save(update_fields=["severity"])
|
||||
|
||||
# create alert in dashboard if enabled
|
||||
if (
|
||||
self.dashboard_alert
|
||||
@@ -359,7 +365,7 @@ class AutomatedTask(BaseAuditModel):
|
||||
alert.action_stdout = r["stdout"]
|
||||
alert.action_stderr = r["stderr"]
|
||||
alert.action_execution_time = "{:.4f}".format(r["execution_time"])
|
||||
alert.action_run = True
|
||||
alert.action_run = djangotime.now()
|
||||
alert.save()
|
||||
else:
|
||||
logger.error(
|
||||
|
||||
24
api/tacticalrmm/checks/migrations/0021_auto_20210212_1429.py
Normal file
24
api/tacticalrmm/checks/migrations/0021_auto_20210212_1429.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 3.1.4 on 2021-02-12 14:29
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('checks', '0020_auto_20210210_1512'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='check',
|
||||
name='error_threshold',
|
||||
field=models.PositiveIntegerField(blank=True, default=0, null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(99)]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='check',
|
||||
name='warning_threshold',
|
||||
field=models.PositiveIntegerField(blank=True, default=0, null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(99)]),
|
||||
),
|
||||
]
|
||||
@@ -5,8 +5,10 @@ import json
|
||||
import pytz
|
||||
from statistics import mean
|
||||
|
||||
from django.utils import timezone as djangotime
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from rest_framework.fields import JSONField
|
||||
from typing import List, Any
|
||||
@@ -113,10 +115,17 @@ class Check(BaseAuditModel):
|
||||
|
||||
# threshold percent for diskspace, cpuload or memory check
|
||||
error_threshold = models.PositiveIntegerField(
|
||||
validators=[MinValueValidator(0), MaxValueValidator(99)],
|
||||
null=True,
|
||||
blank=True,
|
||||
default=0,
|
||||
)
|
||||
warning_threshold = models.PositiveIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
validators=[MinValueValidator(0), MaxValueValidator(99)],
|
||||
default=0,
|
||||
)
|
||||
warning_threshold = models.PositiveIntegerField(null=True, blank=True, default=0)
|
||||
# diskcheck i.e C:, D: etc
|
||||
disk = models.CharField(max_length=2, null=True, blank=True)
|
||||
# ping checks
|
||||
@@ -314,7 +323,7 @@ class Check(BaseAuditModel):
|
||||
alert.resolved_action_execution_time = "{:.4f}".format(
|
||||
r["execution_time"]
|
||||
)
|
||||
alert.resolved_action_run = True
|
||||
alert.resolved_action_run = djangotime.now()
|
||||
alert.save()
|
||||
else:
|
||||
logger.error(
|
||||
@@ -327,6 +336,11 @@ class Check(BaseAuditModel):
|
||||
else:
|
||||
alert = Alert.objects.get(assigned_check=self, resolved=False)
|
||||
|
||||
# check if alert severity changed on check and update the alert
|
||||
if self.alert_severity != alert.severity:
|
||||
alert.severity = self.alert_severity
|
||||
alert.save(update_fields=["severity"])
|
||||
|
||||
# create alert in dashboard if enabled
|
||||
if (
|
||||
self.dashboard_alert
|
||||
@@ -384,7 +398,7 @@ class Check(BaseAuditModel):
|
||||
alert.action_stdout = r["stdout"]
|
||||
alert.action_stderr = r["stderr"]
|
||||
alert.action_execution_time = "{:.4f}".format(r["execution_time"])
|
||||
alert.action_run = True
|
||||
alert.action_run = djangotime.now()
|
||||
alert.save()
|
||||
else:
|
||||
logger.error(
|
||||
@@ -408,15 +422,12 @@ class Check(BaseAuditModel):
|
||||
|
||||
avg = int(mean(self.history))
|
||||
|
||||
if self.warning_threshold and avg > self.warning_threshold:
|
||||
self.status = "failing"
|
||||
self.alert_severity = "warning"
|
||||
else:
|
||||
self.status = "passing"
|
||||
|
||||
if self.error_threshold and avg > self.error_threshold:
|
||||
self.status = "failing"
|
||||
self.alert_severity = "error"
|
||||
elif self.warning_threshold and avg > self.warning_threshold:
|
||||
self.status = "failing"
|
||||
self.alert_severity = "warning"
|
||||
else:
|
||||
self.status = "passing"
|
||||
|
||||
@@ -430,25 +441,23 @@ class Check(BaseAuditModel):
|
||||
total = bytes2human(data["total"])
|
||||
free = bytes2human(data["free"])
|
||||
|
||||
if (
|
||||
if self.error_threshold and (100 - percent_used) < self.error_threshold:
|
||||
self.status = "failing"
|
||||
self.alert_severity = "error"
|
||||
elif (
|
||||
self.warning_threshold
|
||||
and (100 - percent_used) < self.warning_threshold
|
||||
):
|
||||
self.status = "failing"
|
||||
self.alert_severity = "warning"
|
||||
else:
|
||||
self.status = "passing"
|
||||
|
||||
if self.error_threshold and (100 - percent_used) < self.error_threshold:
|
||||
self.status = "failing"
|
||||
self.alert_severity = "error"
|
||||
else:
|
||||
self.status = "passing"
|
||||
|
||||
self.more_info = f"Total: {total}B, Free: {free}B"
|
||||
|
||||
# add check history
|
||||
self.add_check_history(percent_used)
|
||||
self.add_check_history(100 - percent_used)
|
||||
else:
|
||||
self.status = "failing"
|
||||
self.alert_severity = "error"
|
||||
@@ -630,15 +639,11 @@ class Check(BaseAuditModel):
|
||||
# handle status
|
||||
if self.status == "failing":
|
||||
self.fail_count += 1
|
||||
self.save(update_fields=["status", "fail_count"])
|
||||
self.save(update_fields=["status", "fail_count", "alert_severity"])
|
||||
|
||||
elif self.status == "passing":
|
||||
|
||||
if self.fail_count != 0:
|
||||
self.fail_count = 0
|
||||
self.save(update_fields=["status", "fail_count"])
|
||||
else:
|
||||
self.save(update_fields=["status"])
|
||||
self.fail_count = 0
|
||||
self.save(update_fields=["status", "fail_count", "alert_severity"])
|
||||
|
||||
self.handle_alert()
|
||||
|
||||
|
||||
@@ -40,19 +40,30 @@ class CheckSerializer(serializers.ModelSerializer):
|
||||
check_type = val["check_type"]
|
||||
except KeyError:
|
||||
return val
|
||||
|
||||
# disk checks
|
||||
# make sure no duplicate diskchecks exist for an agent/policy
|
||||
if check_type == "diskspace" and not self.instance: # only on create
|
||||
checks = (
|
||||
Check.objects.filter(**self.context)
|
||||
.filter(check_type="diskspace")
|
||||
.exclude(managed_by_policy=True)
|
||||
)
|
||||
for check in checks:
|
||||
if val["disk"] in check.disk:
|
||||
raise serializers.ValidationError(
|
||||
f"A disk check for Drive {val['disk']} already exists!"
|
||||
)
|
||||
if check_type == "diskspace":
|
||||
if not self.instance: # only on create
|
||||
checks = (
|
||||
Check.objects.filter(**self.context)
|
||||
.filter(check_type="diskspace")
|
||||
.exclude(managed_by_policy=True)
|
||||
)
|
||||
for check in checks:
|
||||
if val["disk"] in check.disk:
|
||||
raise serializers.ValidationError(
|
||||
f"A disk check for Drive {val['disk']} already exists!"
|
||||
)
|
||||
|
||||
if (
|
||||
val["warning_threshold"] < val["error_threshold"]
|
||||
and val["warning_threshold"] > 0
|
||||
and val["error_threshold"] > 0
|
||||
):
|
||||
raise serializers.ValidationError(
|
||||
f"Warning threshold must be greater than Error Threshold"
|
||||
)
|
||||
|
||||
# ping checks
|
||||
if check_type == "ping":
|
||||
@@ -74,6 +85,14 @@ class CheckSerializer(serializers.ModelSerializer):
|
||||
raise serializers.ValidationError(
|
||||
"A cpuload check for this agent already exists"
|
||||
)
|
||||
if (
|
||||
val["warning_threshold"] > val["error_threshold"]
|
||||
and val["warning_threshold"] > 0
|
||||
and val["error_threshold"] > 0
|
||||
):
|
||||
raise serializers.ValidationError(
|
||||
f"Warning threshold must be less than Error Threshold"
|
||||
)
|
||||
|
||||
if check_type == "memory" and not self.instance:
|
||||
if (
|
||||
@@ -85,6 +104,15 @@ class CheckSerializer(serializers.ModelSerializer):
|
||||
"A memory check for this agent already exists"
|
||||
)
|
||||
|
||||
if (
|
||||
val["warning_threshold"] > val["error_threshold"]
|
||||
and val["warning_threshold"] > 0
|
||||
and val["error_threshold"] > 0
|
||||
):
|
||||
raise serializers.ValidationError(
|
||||
f"Warning threshold must be less than Error Threshold"
|
||||
)
|
||||
|
||||
return val
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 3.1.4 on 2021-02-07 14:26
|
||||
# Generated by Django 3.1.4 on 2021-02-12 14:08
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
@@ -7,7 +7,7 @@ import django.db.models.deletion
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('alerts', '0004_auto_20210207_1426'),
|
||||
('alerts', '0004_auto_20210212_1408'),
|
||||
('clients', '0008_auto_20201103_1430'),
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 3.1.4 on 2021-02-07 14:50
|
||||
# Generated by Django 3.1.4 on 2021-02-12 14:08
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
@@ -7,7 +7,7 @@ import django.db.models.deletion
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('alerts', '0004_auto_20210207_1426'),
|
||||
('alerts', '0004_auto_20210212_1408'),
|
||||
('core', '0012_coresettings_check_history_prune_days'),
|
||||
]
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# Generated by Django 3.1.4 on 2020-12-10 21:45
|
||||
|
||||
from django.db import migrations
|
||||
from django.conf import settings
|
||||
import os
|
||||
import base64
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def move_scripts_to_db(apps, schema_editor):
|
||||
print("")
|
||||
Script = apps.get_model("scripts", "Script")
|
||||
for script in Script.objects.all():
|
||||
if not script.script_type == "builtin":
|
||||
|
||||
if script.filename:
|
||||
filepath = f"{settings.SCRIPTS_DIR}/userdefined/{script.filename}"
|
||||
else:
|
||||
print(f"No filename on script found. Skipping")
|
||||
continue
|
||||
|
||||
# test if file exists
|
||||
if os.path.exists(filepath):
|
||||
print(f"Found script {script.name}. Importing code.")
|
||||
|
||||
with open(filepath, "rb") as f:
|
||||
script_bytes = f.read().decode("utf-8").encode("ascii", "ignore")
|
||||
script.code_base64 = base64.b64encode(script_bytes).decode("ascii")
|
||||
script.save(update_fields=["code_base64"])
|
||||
else:
|
||||
print(
|
||||
f"Script file {script.name} was not found on the disk. You will need to edit the script in the UI"
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("scripts", "0005_auto_20201207_1606"),
|
||||
]
|
||||
|
||||
operations = [migrations.RunPython(move_scripts_to_db, migrations.RunPython.noop)]
|
||||
@@ -172,7 +172,7 @@
|
||||
<span
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
@click="scriptMoreInfo(props.row)"
|
||||
@click="showScriptOutput(props.row)"
|
||||
>output</span
|
||||
>
|
||||
</q-td>
|
||||
@@ -191,16 +191,6 @@
|
||||
<q-dialog v-model="showAddAutomatedTask" position="top">
|
||||
<AddAutomatedTask @close="showAddAutomatedTask = false" />
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog v-model="showScriptOutput">
|
||||
<ScriptOutput
|
||||
@close="
|
||||
showScriptOutput = false;
|
||||
scriptInfo = {};
|
||||
"
|
||||
:scriptInfo="scriptInfo"
|
||||
/>
|
||||
</q-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -214,15 +204,13 @@ import ScriptOutput from "@/components/modals/checks/ScriptOutput";
|
||||
|
||||
export default {
|
||||
name: "AutomatedTasksTab",
|
||||
components: { AddAutomatedTask, ScriptOutput },
|
||||
components: { AddAutomatedTask },
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
showAddAutomatedTask: false,
|
||||
showEditAutomatedTask: false,
|
||||
showScriptOutput: false,
|
||||
editTaskPk: null,
|
||||
showScriptOutput: false,
|
||||
scriptInfo: {},
|
||||
columns: [
|
||||
{ name: "enabled", align: "left", field: "enabled" },
|
||||
@@ -310,9 +298,12 @@ export default {
|
||||
refreshTasks(id) {
|
||||
this.$store.dispatch("loadAutomatedTasks", id);
|
||||
},
|
||||
scriptMoreInfo(props) {
|
||||
this.scriptInfo = props;
|
||||
this.showScriptOutput = true;
|
||||
showScriptOutput(script) {
|
||||
this.$q.dialog({
|
||||
component: ScriptOutput,
|
||||
parent: this,
|
||||
scriptInfo: script,
|
||||
});
|
||||
},
|
||||
showEditTask(task) {
|
||||
this.$q
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
v-else-if="props.row.check_type === 'script'"
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
@click="scriptMoreInfo(props.row)"
|
||||
@click="showScriptOutput(props.row)"
|
||||
>Last Output</span
|
||||
>
|
||||
<span
|
||||
@@ -225,7 +225,7 @@
|
||||
>Last Output</span
|
||||
>
|
||||
</q-td>
|
||||
<q-td>{{ props.row.last_run }}</q-td>
|
||||
<q-td>{{ props.row.last_run || "Never" }}</q-td>
|
||||
<q-td v-if="props.row.assigned_task !== null && props.row.assigned_task.length > 1"
|
||||
>{{ props.row.assigned_task.length }} Tasks</q-td
|
||||
>
|
||||
@@ -258,15 +258,6 @@
|
||||
<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>
|
||||
<q-dialog v-model="showEventLogOutput">
|
||||
<EventLogCheckOutput
|
||||
@close="
|
||||
@@ -304,7 +295,6 @@ export default {
|
||||
WinSvcCheck,
|
||||
EventLogCheck,
|
||||
ScriptCheck,
|
||||
ScriptOutput,
|
||||
EventLogCheckOutput,
|
||||
},
|
||||
mixins: [mixins],
|
||||
@@ -319,9 +309,7 @@ export default {
|
||||
showWinSvcCheck: false,
|
||||
showEventLogCheck: false,
|
||||
showScriptCheck: false,
|
||||
showScriptOutput: false,
|
||||
showEventLogOutput: false,
|
||||
scriptInfo: {},
|
||||
evtlogdata: {},
|
||||
columns: [
|
||||
{ name: "smsalert", field: "text_alert", align: "left" },
|
||||
@@ -425,10 +413,6 @@ export default {
|
||||
html: true,
|
||||
});
|
||||
},
|
||||
scriptMoreInfo(props) {
|
||||
this.scriptInfo = props;
|
||||
this.showScriptOutput = true;
|
||||
},
|
||||
eventLogMoreInfo(props) {
|
||||
this.evtlogdata = props;
|
||||
this.showEventLogOutput = true;
|
||||
@@ -460,6 +444,13 @@ export default {
|
||||
check: check,
|
||||
});
|
||||
},
|
||||
showScriptOutput(script) {
|
||||
this.$q.dialog({
|
||||
component: ScriptOutput,
|
||||
parent: this,
|
||||
scriptInfo: script,
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["selectedAgentPk", "checks", "tabsTableHeight"]),
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
>
|
||||
<span
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
@click="scriptMoreInfo(props.row)"
|
||||
@click="showScriptOutput(props.row)"
|
||||
class="script-cell text-primary"
|
||||
>output</span
|
||||
>
|
||||
@@ -103,9 +103,6 @@
|
||||
</q-table>
|
||||
</q-card-section>
|
||||
|
||||
<q-dialog v-model="showScriptOutput" @hide="closeScriptOutput">
|
||||
<ScriptOutput @close="closeScriptOutput" :scriptInfo="scriptInfo" />
|
||||
</q-dialog>
|
||||
<q-dialog v-model="showEventLogOutput" @hide="closeEventLogOutput">
|
||||
<EventLogCheckOutput @close="closeEventLogOutput" :evtlogdata="evtLogData" />
|
||||
</q-dialog>
|
||||
@@ -120,7 +117,6 @@ import EventLogCheckOutput from "@/components/modals/checks/EventLogCheckOutput"
|
||||
export default {
|
||||
name: "PolicyStatus",
|
||||
components: {
|
||||
ScriptOutput,
|
||||
EventLogCheckOutput,
|
||||
},
|
||||
props: {
|
||||
@@ -139,10 +135,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showScriptOutput: false,
|
||||
showEventLogOutput: false,
|
||||
evtLogData: {},
|
||||
scriptInfo: {},
|
||||
data: [],
|
||||
columns: [
|
||||
{ name: "agent", label: "Hostname", field: "agent", align: "left", sortable: true },
|
||||
@@ -225,14 +219,17 @@ export default {
|
||||
html: true,
|
||||
});
|
||||
},
|
||||
scriptMoreInfo(check) {
|
||||
this.scriptInfo = check;
|
||||
this.showScriptOutput = true;
|
||||
},
|
||||
eventLogMoreInfo(check) {
|
||||
this.evtLogData = check;
|
||||
this.showEventLogOutput = true;
|
||||
},
|
||||
showScriptOutput(script) {
|
||||
this.$q.dialog({
|
||||
component: ScriptOutput,
|
||||
parent: this,
|
||||
scriptInfo: script,
|
||||
});
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
|
||||
@@ -208,6 +208,10 @@ export default {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (this.check.check_type === "diskspace") {
|
||||
this.chartOptions["yaxis"]["reversed"] = true;
|
||||
}
|
||||
} else {
|
||||
// Set the y-axis labels to Failing and Passing
|
||||
this.chartOptions["yaxis"] = {
|
||||
|
||||
@@ -56,6 +56,21 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-2 q-my-sm">Failure action timeout</div>
|
||||
<div class="col-10 q-mb-sm">
|
||||
<q-input
|
||||
outlined
|
||||
type="number"
|
||||
v-model.number="template.action_timeout"
|
||||
dense
|
||||
:rules="[
|
||||
val => !!val || 'Failure action timeout is required',
|
||||
val => val > 0 || 'Timeout must be greater than 0',
|
||||
val => val > 60 || 'Timeout must be 60 or less',
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-2 q-my-sm">
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Resolved action
|
||||
@@ -92,6 +107,21 @@
|
||||
new-value-mode="add"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-2 q-my-sm">Resolved action timeout</div>
|
||||
<div class="col-10 q-mb-sm">
|
||||
<q-input
|
||||
outlined
|
||||
type="number"
|
||||
v-model.number="template.resolved_action_timeout"
|
||||
dense
|
||||
:rules="[
|
||||
val => !!val || 'Resolved action timeout is required',
|
||||
val => val > 0 || 'Timeout must be greater than 0',
|
||||
val => val > 60 || 'Timeout must be 60 or less',
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<div class="q-pl-md text-subtitle1">Email Settings (Overrides global email settings)</div>
|
||||
@@ -222,7 +252,7 @@
|
||||
type="number"
|
||||
v-model.number="template.agent_periodic_alert_days"
|
||||
dense
|
||||
:rules="[val => val >= 0]"
|
||||
:rules="[val => val >= 0 || 'Periodic days must be 0 or greater']"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
@@ -338,7 +368,7 @@
|
||||
type="number"
|
||||
v-model.number="template.check_periodic_alert_days"
|
||||
dense
|
||||
:rules="[val => val >= 0]"
|
||||
:rules="[val => val >= 0 || 'Periodic days must be 0 or greater']"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
@@ -482,8 +512,10 @@ export default {
|
||||
is_active: true,
|
||||
action: null,
|
||||
action_args: [],
|
||||
action_timeout: 15,
|
||||
resolved_action: null,
|
||||
resolved_action_args: [],
|
||||
resolved_action_timeout: 15,
|
||||
email_recipients: [],
|
||||
email_from: "",
|
||||
text_recipients: [],
|
||||
|
||||
@@ -113,6 +113,24 @@
|
||||
<q-icon name="flag" size="sm" class="cursor-pointer" @click="resolveAlert(props.row)">
|
||||
<q-tooltip>Resolve alert</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon
|
||||
v-if="props.row.action_run"
|
||||
name="mdi-archive-alert"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
@click="showScriptOutput(props.row, true)"
|
||||
>
|
||||
<q-tooltip>Show failure action run results</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon
|
||||
v-if="props.row.resolved_action_run"
|
||||
name="mdi-archive-check"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
@click="showScriptOutput(props.row, false)"
|
||||
>
|
||||
<q-tooltip>Show resolved action run results</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
</q-td>
|
||||
</template>
|
||||
@@ -130,6 +148,7 @@
|
||||
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
import ScriptOutput from "@/components/modals/checks/ScriptOutput";
|
||||
|
||||
export default {
|
||||
name: "AlertsOverview",
|
||||
@@ -380,6 +399,30 @@ export default {
|
||||
});
|
||||
});
|
||||
},
|
||||
showScriptOutput(alert, failure = false) {
|
||||
let results = {};
|
||||
if (failure) {
|
||||
results.readable_desc = `${alert.alert_type} failure action results`;
|
||||
results.execution_time = alert.action_execution_time;
|
||||
results.retcode = alert.action_retcode;
|
||||
results.stdout = alert.action_stdout;
|
||||
results.errout = alert.action_errout;
|
||||
results.last_run = alert.action_run;
|
||||
} else {
|
||||
results.readable_desc = `${alert.alert_type} resolved action results`;
|
||||
results.execution_time = alert.resolved_action_execution_time;
|
||||
results.retcode = alert.resolved_action_retcode;
|
||||
results.stdout = alert.resolved_action_stdout;
|
||||
results.errout = alert.resolved_action_errout;
|
||||
results.last_run = alert.resolved_action_run;
|
||||
}
|
||||
|
||||
this.$q.dialog({
|
||||
component: ScriptOutput,
|
||||
parent: this,
|
||||
scriptInfo: results,
|
||||
});
|
||||
},
|
||||
alertColor(severity) {
|
||||
if (severity === "error") {
|
||||
return "red";
|
||||
|
||||
@@ -11,25 +11,19 @@
|
||||
<q-card-section>
|
||||
<q-input
|
||||
outlined
|
||||
type="number"
|
||||
v-model.number="cpuloadcheck.warning_threshold"
|
||||
label="Warning Threshold (%)"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 1 || 'Minimum threshold is 1',
|
||||
val => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
outlined
|
||||
type="number"
|
||||
v-model.number="cpuloadcheck.error_threshold"
|
||||
label="Error Threshold (%)"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 1 || 'Minimum threshold is 1',
|
||||
val => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -74,22 +68,12 @@ export default {
|
||||
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
thresholdIsValid() {
|
||||
return (
|
||||
this.cpuloadcheck.warning_threshold === 0 ||
|
||||
this.cpuloadcheck.error_threshold === 0 ||
|
||||
this.cpuloadcheck.warning_threshold < this.cpuloadcheck.error_threshold
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getCheck() {
|
||||
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.cpuloadcheck = r.data));
|
||||
},
|
||||
addCheck() {
|
||||
if (!this.thresholdIsValid) {
|
||||
this.notifyError("Warning Threshold needs to be less than Error threshold");
|
||||
if (!this.isValidThreshold(this.cpuloadcheck.warning_threshold, this.cpuloadcheck.error_threshold)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,8 +92,7 @@ export default {
|
||||
.catch(e => this.notifyError(e.response.data.non_field_errors));
|
||||
},
|
||||
editCheck() {
|
||||
if (!this.thresholdIsValid) {
|
||||
this.notifyError("Warning Threshold needs to be less than Error threshold");
|
||||
if (!this.isValidThreshold(this.cpuloadcheck.warning_threshold, this.cpuloadcheck.error_threshold)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,25 +20,19 @@
|
||||
<q-card-section>
|
||||
<q-input
|
||||
outlined
|
||||
type="number"
|
||||
v-model.number="diskcheck.warning_threshold"
|
||||
label="Warning Threshold (%)"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 1 || 'Minimum threshold is 1',
|
||||
val => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
label="Warning Threshold Remaining (%)"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
outlined
|
||||
type="number"
|
||||
v-model.number="diskcheck.error_threshold"
|
||||
label="Error Threshold (%)"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 1 || 'Minimum threshold is 1',
|
||||
val => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
label="Error Threshold Remaining (%)"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -62,7 +56,7 @@
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
import { mapGetters } from "vuex";
|
||||
import mixins from "@/mixins/mixins";
|
||||
export default {
|
||||
name: "DiskSpaceCheck",
|
||||
@@ -102,8 +96,7 @@ export default {
|
||||
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.diskcheck = r.data));
|
||||
},
|
||||
addCheck() {
|
||||
if (!this.thresholdIsValid) {
|
||||
this.notifyError("Warning Threshold needs to be greater than Error threshold");
|
||||
if (!this.isValidThreshold(this.diskcheck.warning_threshold, this.diskcheck.error_threshold, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,8 +115,7 @@ export default {
|
||||
.catch(e => this.notifyError(e.response.data.non_field_errors));
|
||||
},
|
||||
editCheck() {
|
||||
if (!this.thresholdIsValid) {
|
||||
this.notifyError("Warning Threshold needs to be greater than Error threshold");
|
||||
if (!this.isValidThreshold(this.diskcheck.warning_threshold, this.diskcheck.error_threshold, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -144,13 +136,6 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["agentDisks"]),
|
||||
thresholdIsValid() {
|
||||
return (
|
||||
!!this.diskcheck.warning_threshold ||
|
||||
!!this.diskcheck.error_threshold ||
|
||||
this.diskcheck.warning_threshold > this.diskcheck.error_threshold
|
||||
);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.mode === "add") {
|
||||
|
||||
@@ -11,25 +11,19 @@
|
||||
<q-card-section>
|
||||
<q-input
|
||||
outlined
|
||||
type="number"
|
||||
v-model.number="memcheck.warning_threshold"
|
||||
label="Warning Threshold (%)"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 1 || 'Minimum threshold is 1',
|
||||
val => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
outlined
|
||||
type="number"
|
||||
v-model.number="memcheck.error_threshold"
|
||||
label="Error Threshold (%)"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 1 || 'Minimum threshold is 1',
|
||||
val => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -74,22 +68,12 @@ export default {
|
||||
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
thresholdIsValid() {
|
||||
return (
|
||||
this.memcheck.warning_threshold === 0 ||
|
||||
this.memcheck.error_threshold === 0 ||
|
||||
this.memcheck.warning_threshold < this.memcheck.error_threshold
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getCheck() {
|
||||
axios.get(`/checks/${this.checkpk}/check/`).then(r => (this.memcheck = r.data));
|
||||
},
|
||||
addCheck() {
|
||||
if (!this.thresholdIsValid) {
|
||||
this.notifyError("Warning Threshold needs to be less than Error threshold");
|
||||
if (!this.isValidThreshold(this.memcheck.warning_threshold, this.memcheck.error_threshold)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,8 +92,7 @@ export default {
|
||||
.catch(e => this.notifyError(e.response.data.non_field_errors));
|
||||
},
|
||||
editCheck() {
|
||||
if (!this.thresholdIsValid) {
|
||||
this.notifyError("Warning Threshold needs to be less than Error threshold");
|
||||
if (!this.isValidThreshold(this.memcheck.warning_threshold, this.memcheck.error_threshold)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +1,56 @@
|
||||
<template>
|
||||
<q-card style="min-width: 70vw" class="q-pa-xs">
|
||||
<q-card-section>
|
||||
<div class="row items-center">
|
||||
<div class="text-h6">{{ scriptInfo.readable_desc }}</div>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin q-pa-xs" style="min-width: 70vw">
|
||||
<q-bar>
|
||||
{{ scriptInfo.readable_desc }}
|
||||
<q-space />
|
||||
<q-btn icon="close" flat round dense v-close-popup />
|
||||
</div>
|
||||
<div>
|
||||
Last Run:
|
||||
<code>{{ scriptInfo.last_run }}</code>
|
||||
<br />Run Time:
|
||||
<code>{{ scriptInfo.execution_time}} seconds</code>
|
||||
<br />Return Code:
|
||||
<code>{{ scriptInfo.retcode }}</code>
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
|
||||
</q-btn>
|
||||
</q-bar>
|
||||
<q-card-section>
|
||||
<div>
|
||||
Last Run:
|
||||
<code>{{ scriptInfo.last_run }}</code>
|
||||
<br />Run Time:
|
||||
<code>{{ scriptInfo.execution_time }} seconds</code>
|
||||
<br />Return Code:
|
||||
<code>{{ scriptInfo.retcode }}</code>
|
||||
<br />
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
<br />
|
||||
<div v-if="scriptInfo.stdout">
|
||||
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: 50vh; max-height: 70vh;">
|
||||
<pre>{{ scriptInfo.stderr }}</pre>
|
||||
</q-scroll-area>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
<div v-if="scriptInfo.stdout">
|
||||
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: 50vh; max-height: 70vh">
|
||||
<pre>{{ scriptInfo.stderr }}</pre>
|
||||
</q-scroll-area>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ScriptOutput",
|
||||
props: ["scriptInfo"],
|
||||
beforeDestroy() {
|
||||
this.$emit("close");
|
||||
methods: {
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.dialog.hide();
|
||||
},
|
||||
onHide() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -84,6 +84,25 @@ export default {
|
||||
notifyInfo(msg, timeout = 2000) {
|
||||
Notify.create(notifyInfoConfig(msg, timeout));
|
||||
},
|
||||
|
||||
isValidThreshold(warning, error, diskcheck = false) {
|
||||
if (warning === 0 && error === 0) {
|
||||
Notify.create(notifyErrorConfig("Warning Threshold or Error Threshold need to be set", 2000));
|
||||
return false
|
||||
}
|
||||
|
||||
if (!diskcheck && warning > error && warning > 0 && error > 0) {
|
||||
Notify.create(notifyErrorConfig("Warning Threshold must be less than Error Threshold", 2000));
|
||||
return false
|
||||
}
|
||||
|
||||
if (diskcheck && warning < error && warning > 0 && error > 0) {
|
||||
Notify.create(notifyErrorConfig("Warning Threshold must be more than Error Threshold", 2000));
|
||||
return false
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
isValidEmail(val) {
|
||||
const email = /^(?=[a-zA-Z0-9@._%+-]{6,254}$)[a-zA-Z0-9._%+-]{1,64}@(?:[a-zA-Z0-9-]{1,63}\.){1,8}[a-zA-Z]{2,63}$/;
|
||||
return email.test(val);
|
||||
|
||||
Reference in New Issue
Block a user