Skip to content

Commit

Permalink
Release 0.19.2
Browse files Browse the repository at this point in the history
  • Loading branch information
wh1te909 committed Jul 22, 2024
2 parents 48db3d3 + c8d72dd commit 4a768de
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 33 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Tactical RMM is a remote monitoring & management tool, built with Django and Vue
It uses an [agent](https://github.com/amidaware/rmmagent) written in golang and integrates with [MeshCentral](https://github.com/Ylianst/MeshCentral)

# [LIVE DEMO](https://demo.tacticalrmm.com/)

Demo database resets every hour. A lot of features are disabled for obvious reasons due to the nature of this app.

### [Discord Chat](https://discord.gg/upGTkWp)
Expand All @@ -23,7 +24,7 @@ Demo database resets every hour. A lot of features are disabled for obvious reas
- Event log viewer
- Services management
- Windows patch management
- Automated checks with email/SMS alerting (cpu, disk, memory, services, scripts, event logs)
- Automated checks with email/SMS/Webhook alerting (cpu, disk, memory, services, scripts, event logs)
- Automated task runner (run scripts on a schedule)
- Remote software installation via chocolatey
- Software and hardware inventory
Expand All @@ -33,9 +34,11 @@ Demo database resets every hour. A lot of features are disabled for obvious reas
- Windows 7, 8.1, 10, 11, Server 2008R2, 2012R2, 2016, 2019, 2022

## Linux agent versions supported

- Any distro with systemd which includes but is not limited to: Debian (10, 11), Ubuntu x86_64 (18.04, 20.04, 22.04), Synology 7, centos, freepbx and more!

## Mac agent versions supported

- 64 bit Intel and Apple Silicon (M1, M2)

## Installation / Backup / Restore / Usage
Expand Down
4 changes: 2 additions & 2 deletions api/tacticalrmm/agents/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,8 +969,8 @@ def should_create_alert(
return bool(
has_agent_notification
or has_alert_template_notification
or has_webhook(alert_template)
or has_script_actions(alert_template)
or has_webhook(alert_template, "agent")
or has_script_actions(alert_template, "agent")
)

def send_outage_email(self) -> None:
Expand Down
43 changes: 24 additions & 19 deletions api/tacticalrmm/alerts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def create_or_return_availability_alert(
agent=agent,
alert_type=AlertType.AVAILABILITY,
severity=AlertSeverity.ERROR,
message=f"{agent.hostname} in {agent.client.name}\\{agent.site.name} is overdue.",
message=f"{agent.hostname} in {agent.client.name}, {agent.site.name} is overdue.",
hidden=True,
),
)
Expand Down Expand Up @@ -306,7 +306,7 @@ def handle_alert_failure(
alert_interval = None
email_task = None
text_task = None
run_script_action = None
should_run_script_or_webhook = False

# check what the instance passed is
if isinstance(instance, Agent):
Expand All @@ -332,7 +332,7 @@ def handle_alert_failure(
always_email = alert_template.agent_always_email
always_text = alert_template.agent_always_text
alert_interval = alert_template.agent_periodic_alert_days
run_script_action = alert_template.agent_script_actions
should_run_script_or_webhook = alert_template.agent_script_actions

elif isinstance(instance, CheckResult):
from checks.tasks import (
Expand Down Expand Up @@ -383,7 +383,7 @@ def handle_alert_failure(
always_email = alert_template.check_always_email
always_text = alert_template.check_always_text
alert_interval = alert_template.check_periodic_alert_days
run_script_action = alert_template.check_script_actions
should_run_script_or_webhook = alert_template.check_script_actions

elif isinstance(instance, TaskResult):
from autotasks.tasks import handle_task_email_alert, handle_task_sms_alert
Expand Down Expand Up @@ -417,7 +417,7 @@ def handle_alert_failure(
always_email = alert_template.task_always_email
always_text = alert_template.task_always_text
alert_interval = alert_template.task_periodic_alert_days
run_script_action = alert_template.task_script_actions
should_run_script_or_webhook = alert_template.task_script_actions

else:
return
Expand Down Expand Up @@ -490,11 +490,10 @@ def handle_alert_failure(
text_task.delay(pk=alert.pk, alert_interval=alert_interval)

# check if any scripts/webhooks should be run
if alert_template and not alert.action_run:
if alert_template and not alert.action_run and should_run_script_or_webhook:
if (
alert_template.action_type == AlertTemplateActionType.SCRIPT
and alert_template.action
and run_script_action
):
hist = AgentHistory.objects.create(
agent=agent,
Expand All @@ -516,7 +515,6 @@ def handle_alert_failure(
elif (
alert_template.action_type == AlertTemplateActionType.SERVER
and alert_template.action
and run_script_action
):
stdout, stderr, execution_time, retcode = run_server_script(
body=alert_template.action.script_body,
Expand Down Expand Up @@ -595,7 +593,7 @@ def handle_alert_resolve(
text_on_resolved = False
resolved_email_task = None
resolved_text_task = None
run_script_action = None
should_run_script_or_webhook = False

# check what the instance passed is
if isinstance(instance, Agent):
Expand All @@ -611,7 +609,7 @@ def handle_alert_resolve(
if alert_template:
email_on_resolved = alert_template.agent_email_on_resolved
text_on_resolved = alert_template.agent_text_on_resolved
run_script_action = alert_template.agent_script_actions
should_run_script_or_webhook = alert_template.agent_script_actions
email_severities = [AlertSeverity.ERROR]
text_severities = [AlertSeverity.ERROR]

Expand All @@ -636,7 +634,7 @@ def handle_alert_resolve(
if alert_template:
email_on_resolved = alert_template.check_email_on_resolved
text_on_resolved = alert_template.check_text_on_resolved
run_script_action = alert_template.check_script_actions
should_run_script_or_webhook = alert_template.check_script_actions
email_severities = alert_template.check_email_alert_severity or [
AlertSeverity.ERROR,
AlertSeverity.WARNING,
Expand All @@ -662,7 +660,7 @@ def handle_alert_resolve(
if alert_template:
email_on_resolved = alert_template.task_email_on_resolved
text_on_resolved = alert_template.task_text_on_resolved
run_script_action = alert_template.task_script_actions
should_run_script_or_webhook = alert_template.task_script_actions
email_severities = alert_template.task_email_alert_severity or [
AlertSeverity.ERROR,
AlertSeverity.WARNING,
Expand Down Expand Up @@ -714,11 +712,14 @@ def handle_alert_resolve(
resolved_text_task.delay(pk=alert.pk)

# check if resolved script/webhook should be run
if alert_template and not alert.resolved_action_run:
if (
alert_template
and not alert.resolved_action_run
and should_run_script_or_webhook
):
if (
alert_template.resolved_action_type == AlertTemplateActionType.SCRIPT
and alert_template.resolved_action
and run_script_action
):
hist = AgentHistory.objects.create(
agent=agent,
Expand All @@ -740,7 +741,6 @@ def handle_alert_resolve(
elif (
alert_template.resolved_action_type == AlertTemplateActionType.SERVER
and alert_template.resolved_action
and run_script_action
):
stdout, stderr, execution_time, retcode = run_server_script(
body=alert_template.resolved_action.script_body,
Expand Down Expand Up @@ -863,7 +863,9 @@ class AlertTemplate(BaseAuditModel):
)
action_timeout = models.PositiveIntegerField(default=15)
resolved_action_type = models.CharField(
max_length=10, choices=AlertTemplateActionType.choices, default="script"
max_length=10,
choices=AlertTemplateActionType.choices,
default=AlertTemplateActionType.SCRIPT,
)
resolved_action = models.ForeignKey(
"scripts.Script",
Expand Down Expand Up @@ -917,7 +919,8 @@ class AlertTemplate(BaseAuditModel):
agent_always_text = BooleanField(null=True, blank=True, default=None)
agent_always_alert = BooleanField(null=True, blank=True, default=None)
agent_periodic_alert_days = PositiveIntegerField(blank=True, null=True, default=0)
agent_script_actions = BooleanField(null=True, blank=True, default=True)
# fmt: off
agent_script_actions = BooleanField(null=True, blank=True, default=True) # should be renamed because also deals with webhooks

# check alert settings
check_email_alert_severity = ArrayField(
Expand All @@ -941,7 +944,8 @@ class AlertTemplate(BaseAuditModel):
check_always_text = BooleanField(null=True, blank=True, default=None)
check_always_alert = BooleanField(null=True, blank=True, default=None)
check_periodic_alert_days = PositiveIntegerField(blank=True, null=True, default=0)
check_script_actions = BooleanField(null=True, blank=True, default=True)
# fmt: off
check_script_actions = BooleanField(null=True, blank=True, default=True) # should be renamed because also deals with webhooks

# task alert settings
task_email_alert_severity = ArrayField(
Expand All @@ -965,7 +969,8 @@ class AlertTemplate(BaseAuditModel):
task_always_text = BooleanField(null=True, blank=True, default=None)
task_always_alert = BooleanField(null=True, blank=True, default=None)
task_periodic_alert_days = PositiveIntegerField(blank=True, null=True, default=0)
task_script_actions = BooleanField(null=True, blank=True, default=True)
# fmt: off
task_script_actions = BooleanField(null=True, blank=True, default=True) # should be renamed because also deals with webhooks

# exclusion settings
exclude_workstations = BooleanField(null=True, blank=True, default=False)
Expand Down
4 changes: 2 additions & 2 deletions api/tacticalrmm/autotasks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,8 @@ def should_create_alert(self, alert_template=None):
return (
has_autotask_notification
or has_alert_template_notification
or has_webhook(alert_template)
or has_script_actions(alert_template)
or has_webhook(alert_template, "task")
or has_script_actions(alert_template, "task")
)


Expand Down
4 changes: 2 additions & 2 deletions api/tacticalrmm/checks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ def should_create_alert(self, alert_template=None):
return (
has_check_notifications
or has_alert_template_notification
or has_webhook(alert_template)
or has_script_actions(alert_template)
or has_webhook(alert_template, "check")
or has_script_actions(alert_template, "check")
)

def add_check_history(
Expand Down
2 changes: 2 additions & 0 deletions api/tacticalrmm/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
AgentPlat,
MeshAgentIdent,
)
from tacticalrmm.logger import logger

if TYPE_CHECKING:
from core.models import CoreSettings
Expand Down Expand Up @@ -264,6 +265,7 @@ def run_url_rest_action(*, action_id: int, instance=None) -> tuple[str, int]:
url=url, method=method, body=body, headers=headers, instance=instance
)
except Exception as e:
logger.error(str(e))
return (str(e), 500)

return (response.text, response.status_code)
Expand Down
2 changes: 1 addition & 1 deletion api/tacticalrmm/logs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def audit_bulk_action(
target = f"on all agents within client: {client.name}"
elif affected["target"] == "site":
site = Site.objects.get(pk=affected["site"])
target = f"on all agents within site: {site.client.name}\\{site.name}"
target = f"on all agents within site: {site.client.name} - {site.name}"
elif affected["target"] == "agents":
agents = Agent.objects.filter(agent_id__in=affected["agents"]).values_list(
"hostname", flat=True
Expand Down
30 changes: 25 additions & 5 deletions api/tacticalrmm/tacticalrmm/helpers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from __future__ import annotations

import os
import random
import secrets
import string
from pathlib import Path
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Literal
from urllib.parse import urlparse
from zoneinfo import ZoneInfo

Expand Down Expand Up @@ -140,11 +142,29 @@ def days_until_cert_expires() -> int:
return delta.days


def has_webhook(alert_templ: "AlertTemplate") -> bool:
def has_webhook(
alert_templ: AlertTemplate | None, instance: Literal["agent", "check", "task"]
) -> bool:
return bool(
alert_templ and (alert_templ.action_rest or alert_templ.resolved_action_rest)
alert_templ
and (alert_templ.action_rest or alert_templ.resolved_action_rest)
and (
(instance == "agent" and alert_templ.agent_script_actions)
or (instance == "check" and alert_templ.check_script_actions)
or (instance == "task" and alert_templ.task_script_actions)
)
)


def has_script_actions(alert_templ: "AlertTemplate") -> bool:
return bool(alert_templ and (alert_templ.action or alert_templ.resolved_action))
def has_script_actions(
alert_templ: AlertTemplate | None, instance: Literal["agent", "check", "task"]
) -> bool:
return bool(
alert_templ
and (alert_templ.action or alert_templ.resolved_action)
and (
(instance == "agent" and alert_templ.agent_script_actions)
or (instance == "check" and alert_templ.check_script_actions)
or (instance == "task" and alert_templ.task_script_actions)
)
)
2 changes: 1 addition & 1 deletion api/tacticalrmm/tacticalrmm/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
AUTH_USER_MODEL = "accounts.User"

# latest release
TRMM_VERSION = "0.19.1"
TRMM_VERSION = "0.19.2"

# https://github.com/amidaware/tacticalrmm-web
WEB_VERSION = "0.101.47"
Expand Down

0 comments on commit 4a768de

Please sign in to comment.