Compare commits

...

52 Commits

Author SHA1 Message Date
wh1te909
715982e40a Release 0.6.14 2021-06-11 04:41:48 +00:00
wh1te909
d00cd4453a bump versions 2021-06-11 04:40:57 +00:00
wh1te909
429c08c24a fix width on q-file caused by recent quasar update 2021-06-11 03:58:57 +00:00
wh1te909
6a71490e20 update reqs 2021-06-11 02:40:22 +00:00
Dan
9bceda0646 Merge pull request #562 from diekinderwelt/nginx_enable_ipv6
enable ipv6 in nginx config
2021-06-10 18:59:34 -07:00
Dan
a1027a6773 Merge pull request #565 from silversword411/develop
Docs Update - adding design and tipsntricks
2021-06-10 18:59:12 -07:00
silversword411
302d4b75f9 formatting fix 2021-06-08 15:39:43 -04:00
silversword411
5f6ee0e883 Docs Update - adding design and tipsntricks 2021-06-08 14:45:02 -04:00
Silvio
27f9720de1 enable ipv6 in nginx config
Signed-off-by: Silvio <silvio.zimmer@die-kinderwelt.com>
2021-06-08 11:43:55 +02:00
sadnub
22aa3fdbbc fix bug with policy copy and task that triggers on check failure. Fix check history tests 2021-06-06 23:19:07 -04:00
sadnub
069ecdd33f apply redis configuration after restore 2021-06-06 22:58:32 -04:00
sadnub
dd545ae933 catch an exception that a celery task could potentially throw and configure automation task retries 2021-06-06 22:55:47 -04:00
sadnub
6650b705c4 configure redis to use an appendonly file for celery task reliability 2021-06-06 22:54:52 -04:00
sadnub
59b0350289 fix duplicate tasks when there is an assigned check 2021-06-06 22:54:06 -04:00
sadnub
1ad159f820 remove foreign key from checkhistory to make mass check deletes reliable. (This will not migrate check history data) 2021-06-06 22:53:11 -04:00
Dan
0bf42190e9 Merge pull request #544 from bbrendon/patch-1
check for proper OS support
2021-05-30 23:10:21 -07:00
bbrendon
d2fa836232 check for proper OS support 2021-05-30 10:39:08 -07:00
Dan
c387774093 Merge pull request #543 from bbrendon/develop
fixed an edge case and warning notes
2021-05-29 22:39:52 -07:00
bbrendon
e99736ba3c fixed an edge case and warning notes 2021-05-29 19:25:53 -07:00
wh1te909
16cb54fcc9 fix multiline output not working for automation task 2021-05-29 18:47:09 +00:00
wh1te909
5aa15c51ec Release 0.6.13 2021-05-29 07:35:29 +00:00
wh1te909
a8aedd9cf3 bump version 2021-05-29 07:35:10 +00:00
wh1te909
b851b632bc fix agent_outages_task async error 2021-05-29 07:26:10 +00:00
wh1te909
541e07fb65 Release 0.6.12 2021-05-29 05:16:37 +00:00
wh1te909
6ad16a897d bump versions 2021-05-29 05:15:26 +00:00
wh1te909
72f1053a93 change interval 2021-05-29 04:49:17 +00:00
sadnub
fb15a2762c allow saving multiple script output in custom fields #533 2021-05-28 23:52:23 -04:00
wh1te909
9165248b91 update go/codec 2021-05-29 03:20:12 +00:00
sadnub
add18b29db fix agent dropdown 2021-05-28 22:59:44 -04:00
wh1te909
1971653548 bump nats/mesh 2021-05-29 02:53:16 +00:00
wh1te909
392cd64d7b hide settings in hosted 2021-05-29 02:20:07 +00:00
wh1te909
b5affbb7c8 change function name 2021-05-29 02:18:57 +00:00
wh1te909
71d1206277 more checks rework 2021-05-29 01:37:20 +00:00
wh1te909
26e6a8c409 update reqs 2021-05-28 18:12:32 +00:00
wh1te909
eb54fae11a more checks rework 2021-05-28 17:54:57 +00:00
wh1te909
ee773e5966 remove deprecated func 2021-05-28 17:54:14 +00:00
wh1te909
7218ccdba8 start checks rework 2021-05-27 07:16:06 +00:00
wh1te909
332400e48a autogrow text field fixes #533 2021-05-27 07:09:40 +00:00
Dan
ad1a5d3702 Merge pull request #534 from silversword411/develop
Script library and docs tweaks
2021-05-26 23:59:08 -07:00
silversword411
3006b4184d Docs update on regular patching 2021-05-26 21:36:28 -04:00
silversword411
84eb84a080 Script library adding comments 2021-05-26 10:19:30 -04:00
sadnub
60beea548b Allow clearing resolved/failure actions in alert template 2021-05-24 22:18:12 -04:00
Dan
5f9c149e59 Merge pull request #528 from bbrendon/develop
updated timeouts and fixed one script
2021-05-21 18:36:07 -07:00
bbrendon
53367c6f04 update timeouts on some scripts 2021-05-21 18:01:16 -07:00
bbrendon
d7f817ee44 syntax error fix. 2021-05-21 17:56:53 -07:00
Dan
d33a87da54 Merge pull request #526 from silversword411/develop
script library - Screenconnect collector
2021-05-20 20:13:51 -07:00
silversword411
3aebfb12b7 Merge branch 'develop' of https://github.com/silversword411/tacticalrmm into develop 2021-05-20 21:50:10 -04:00
silversword411
1d6c55ffa6 Script library - screenconnect collector 2021-05-20 21:49:01 -04:00
Dan
5e7080aac3 Merge pull request #522 from silversword411/develop
Docs Example and wip tweaks
2021-05-20 18:37:33 -07:00
silversword411
fad739bc01 Updating script delegated folders 2021-05-20 10:10:59 -04:00
silversword411
c6b7f23884 Adding URL Action Example to docs 2021-05-19 02:46:51 -04:00
silversword411
a6f7e446de tweaking wip scripts 2021-05-18 23:22:45 -04:00
71 changed files with 1408 additions and 1490 deletions

View File

@@ -115,7 +115,10 @@ services:
redis-dev:
container_name: trmm-redis-dev
restart: always
command: redis-server --appendonly yes
image: redis:6.0-alpine
volumes:
- redis-data-dev:/data
networks:
dev:
aliases:
@@ -247,6 +250,7 @@ volumes:
postgres-data-dev:
mongo-dev-data:
mesh-data-dev:
redis-data-dev:
networks:
dev:

View File

@@ -211,6 +211,7 @@ def agent_outages_task() -> None:
agents = Agent.objects.only(
"pk",
"agent_id",
"last_seen",
"offline_time",
"overdue_time",

View File

@@ -321,11 +321,16 @@ class CheckRunner(APIView):
def patch(self, request):
check = get_object_or_404(Check, pk=request.data["id"])
if pyver.parse(check.agent.version) < pyver.parse("1.5.7"):
return notify_error("unsupported")
check.last_run = djangotime.now()
check.save(update_fields=["last_run"])
status = check.handle_checkv2(request.data)
status = check.handle_check(request.data)
if status == "failing" and check.assignedtask.exists(): # type: ignore
check.handle_assigned_task()
return Response(status)
return Response("ok")
class CheckRunnerInterval(APIView):
@@ -378,9 +383,18 @@ class TaskRunner(APIView):
)
# get last line of stdout
value = new_task.stdout.split("\n")[-1].strip()
value = (
new_task.stdout
if task.collector_all_output
else new_task.stdout.split("\n")[-1].strip()
)
if task.custom_field.type in ["text", "number", "single", "datetime"]:
if task.custom_field.type in [
"text",
"number",
"single",
"datetime",
]:
agent_field.string_value = value
agent_field.save()
elif task.custom_field.type == "multiple":

View File

@@ -3,7 +3,7 @@ from typing import Any, Dict, List, Union
from tacticalrmm.celery import app
@app.task
@app.task(retry_backoff=5, retry_jitter=True, retry_kwargs={"max_retries": 5})
def generate_agent_checks_task(
policy: int = None,
site: int = None,
@@ -57,7 +57,9 @@ def generate_agent_checks_task(
return "ok"
@app.task
@app.task(
acks_late=True, retry_backoff=5, retry_jitter=True, retry_kwargs={"max_retries": 5}
)
# updates policy managed check fields on agents
def update_policy_check_fields_task(check: int) -> str:
from checks.models import Check
@@ -73,7 +75,7 @@ def update_policy_check_fields_task(check: int) -> str:
return "ok"
@app.task
@app.task(retry_backoff=5, retry_jitter=True, retry_kwargs={"max_retries": 5})
# generates policy tasks on agents affected by a policy
def generate_agent_autotasks_task(policy: int = None) -> str:
from agents.models import Agent
@@ -100,7 +102,12 @@ def generate_agent_autotasks_task(policy: int = None) -> str:
return "ok"
@app.task
@app.task(
acks_late=True,
retry_backoff=5,
retry_jitter=True,
retry_kwargs={"max_retries": 5},
)
def delete_policy_autotasks_task(task: int) -> str:
from autotasks.models import AutomatedTask
@@ -120,7 +127,12 @@ def run_win_policy_autotasks_task(task: int) -> str:
return "ok"
@app.task
@app.task(
acks_late=True,
retry_backoff=5,
retry_jitter=True,
retry_kwargs={"max_retries": 5},
)
def update_policy_autotasks_fields_task(task: int, update_agent: bool = False) -> str:
from autotasks.models import AutomatedTask

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.1 on 2021-05-29 03:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('autotasks', '0021_alter_automatedtask_custom_field'),
]
operations = [
migrations.AddField(
model_name='automatedtask',
name='collector_all_output',
field=models.BooleanField(default=False),
),
]

View File

@@ -10,6 +10,7 @@ from django.conf import settings
from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.db.models.fields import DateTimeField
from django.db.utils import DatabaseError
from django.utils import timezone as djangotime
from logs.models import BaseAuditModel
from loguru import logger
@@ -104,6 +105,7 @@ class AutomatedTask(BaseAuditModel):
task_type = models.CharField(
max_length=100, choices=TASK_TYPE_CHOICES, default="manual"
)
collector_all_output = models.BooleanField(default=False)
run_time_date = DateTimeField(null=True, blank=True)
remove_if_not_scheduled = models.BooleanField(default=False)
run_asap_after_missed = models.BooleanField(default=False) # added in agent v1.4.7
@@ -182,6 +184,7 @@ class AutomatedTask(BaseAuditModel):
"remove_if_not_scheduled",
"run_asap_after_missed",
"custom_field",
"collector_all_output",
]
@staticmethod
@@ -363,9 +366,14 @@ class AutomatedTask(BaseAuditModel):
if r != "ok" and "The system cannot find the file specified" not in r:
self.sync_status = "pendingdeletion"
self.save(update_fields=["sync_status"])
try:
self.save(update_fields=["sync_status"])
except DatabaseError:
pass
logger.warning(
f"{agent.hostname} task {self.name} was successfully modified"
f"{agent.hostname} task {self.name} will be deleted on next checkin"
)
return "timeout"
else:

View File

@@ -0,0 +1,22 @@
# Generated by Django 3.2.1 on 2021-06-06 16:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('checks', '0023_check_run_interval'),
]
operations = [
migrations.RemoveField(
model_name='checkhistory',
name='check_history',
),
migrations.AddField(
model_name='checkhistory',
name='check_id',
field=models.PositiveIntegerField(default=0),
),
]

View File

@@ -1,4 +1,3 @@
import asyncio
import json
import os
import string
@@ -14,9 +13,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from logs.models import BaseAuditModel
from loguru import logger
from packaging import version as pyver
from .utils import bytes2human
logger.configure(**settings.LOG_CONFIG)
@@ -316,9 +313,9 @@ class Check(BaseAuditModel):
)
def add_check_history(self, value: int, more_info: Any = None) -> None:
CheckHistory.objects.create(check_history=self, y=value, results=more_info)
CheckHistory.objects.create(check_id=self.pk, y=value, results=more_info)
def handle_checkv2(self, data):
def handle_check(self, data):
from alerts.models import Alert
# cpuload or mem checks
@@ -349,9 +346,6 @@ class Check(BaseAuditModel):
elif self.check_type == "diskspace":
if data["exists"]:
percent_used = round(data["percent_used"])
total = bytes2human(data["total"])
free = bytes2human(data["free"])
if self.error_threshold and (100 - percent_used) < self.error_threshold:
self.status = "failing"
self.alert_severity = "error"
@@ -365,7 +359,7 @@ class Check(BaseAuditModel):
else:
self.status = "passing"
self.more_info = f"Total: {total}B, Free: {free}B"
self.more_info = data["more_info"]
# add check history
self.add_check_history(100 - percent_used)
@@ -381,12 +375,7 @@ class Check(BaseAuditModel):
self.stdout = data["stdout"]
self.stderr = data["stderr"]
self.retcode = data["retcode"]
try:
# python agent
self.execution_time = "{:.4f}".format(data["stop"] - data["start"])
except:
# golang agent
self.execution_time = "{:.4f}".format(data["runtime"])
self.execution_time = "{:.4f}".format(data["runtime"])
if data["retcode"] in self.info_return_codes:
self.alert_severity = "info"
@@ -422,22 +411,8 @@ class Check(BaseAuditModel):
# ping checks
elif self.check_type == "ping":
output = data["output"]
if pyver.parse(self.agent.version) <= pyver.parse("1.5.2"):
# DEPRECATED
success = ["Reply", "bytes", "time", "TTL"]
if data["has_stdout"]:
if all(x in output for x in success):
self.status = "passing"
else:
self.status = "failing"
elif data["has_stderr"]:
self.status = "failing"
else:
self.status = data["status"]
self.more_info = output
self.status = data["status"]
self.more_info = data["output"]
self.save(update_fields=["more_info"])
self.add_check_history(
@@ -446,41 +421,8 @@ class Check(BaseAuditModel):
# windows service checks
elif self.check_type == "winsvc":
svc_stat = data["status"]
self.more_info = f"Status {svc_stat.upper()}"
if data["exists"]:
if svc_stat == "running":
self.status = "passing"
elif svc_stat == "start_pending" and self.pass_if_start_pending:
self.status = "passing"
else:
if self.agent and self.restart_if_stopped:
nats_data = {
"func": "winsvcaction",
"payload": {"name": self.svc_name, "action": "start"},
}
r = asyncio.run(self.agent.nats_cmd(nats_data, timeout=32))
if r == "timeout" or r == "natsdown":
self.status = "failing"
elif not r["success"] and r["errormsg"]:
self.status = "failing"
elif r["success"]:
self.status = "passing"
self.more_info = f"Status RUNNING"
else:
self.status = "failing"
else:
self.status = "failing"
else:
if self.pass_if_svc_not_exist:
self.status = "passing"
else:
self.status = "failing"
self.more_info = f"Service {self.svc_name} does not exist"
self.status = data["status"]
self.more_info = data["more_info"]
self.save(update_fields=["more_info"])
self.add_check_history(
@@ -488,49 +430,7 @@ class Check(BaseAuditModel):
)
elif self.check_type == "eventlog":
log = []
is_wildcard = self.event_id_is_wildcard
eventType = self.event_type
eventID = self.event_id
source = self.event_source
message = self.event_message
r = data["log"]
for i in r:
if i["eventType"] == eventType:
if not is_wildcard and not int(i["eventID"]) == eventID:
continue
if not source and not message:
if is_wildcard:
log.append(i)
elif int(i["eventID"]) == eventID:
log.append(i)
continue
if source and message:
if is_wildcard:
if source in i["source"] and message in i["message"]:
log.append(i)
elif int(i["eventID"]) == eventID:
if source in i["source"] and message in i["message"]:
log.append(i)
continue
if source and source in i["source"]:
if is_wildcard:
log.append(i)
elif int(i["eventID"]) == eventID:
log.append(i)
if message and message in i["message"]:
if is_wildcard:
log.append(i)
elif int(i["eventID"]) == eventID:
log.append(i)
log = data["log"]
if self.fail_when == "contains":
if log and len(log) >= self.number_of_events_b4_alert:
self.status = "failing"
@@ -567,6 +467,11 @@ class Check(BaseAuditModel):
return self.status
def handle_assigned_task(self) -> None:
for task in self.assignedtask.all(): # type: ignore
if task.enabled:
task.run_win_task()
@staticmethod
def serialize(check):
# serializes the check and returns json
@@ -604,7 +509,12 @@ class Check(BaseAuditModel):
)
for task in self.assignedtask.all(): # type: ignore
task.create_policy_task(agent=agent, policy=policy, assigned_check=check)
if policy or (
agent and not agent.autotasks.filter(parent_task=task.pk).exists()
):
task.create_policy_task(
agent=agent, policy=policy, assigned_check=check
)
for field in self.policy_fields_to_copy:
setattr(check, field, getattr(self, field))
@@ -778,14 +688,10 @@ class Check(BaseAuditModel):
class CheckHistory(models.Model):
check_history = models.ForeignKey(
Check,
related_name="check_history",
on_delete=models.CASCADE,
)
check_id = models.PositiveIntegerField(default=0)
x = models.DateTimeField(auto_now_add=True)
y = models.PositiveIntegerField(null=True, blank=True, default=None)
results = models.JSONField(null=True, blank=True)
def __str__(self):
return self.check_history.readable_desc
return self.x

View File

@@ -158,14 +158,8 @@ class AssignedTaskCheckRunnerField(serializers.ModelSerializer):
class CheckRunnerGetSerializer(serializers.ModelSerializer):
# only send data needed for agent to run a check
assigned_tasks = serializers.SerializerMethodField()
script = ScriptCheckSerializer(read_only=True)
def get_assigned_tasks(self, obj):
if obj.assignedtask.exists():
tasks = obj.assignedtask.all()
return AssignedTaskCheckRunnerField(tasks, many=True).data
class Meta:
model = Check
exclude = [
@@ -193,6 +187,7 @@ class CheckRunnerGetSerializer(serializers.ModelSerializer):
"modified_by",
"modified_time",
"history",
"dashboard_alert",
]

View File

@@ -363,10 +363,10 @@ class TestCheckViews(TacticalTestCase):
# setup data
agent = baker.make_recipe("agents.agent")
check = baker.make_recipe("checks.diskspace_check", agent=agent)
baker.make("checks.CheckHistory", check_history=check, _quantity=30)
baker.make("checks.CheckHistory", check_id=check.id, _quantity=30)
check_history_data = baker.make(
"checks.CheckHistory",
check_history=check,
check_id=check.id,
_quantity=30,
)
@@ -400,17 +400,17 @@ class TestCheckTasks(TacticalTestCase):
def setUp(self):
self.authenticate()
self.setup_coresettings()
self.agent = baker.make_recipe("agents.agent")
self.agent = baker.make_recipe("agents.agent", version="1.5.7")
def test_prune_check_history(self):
from .tasks import prune_check_history
# setup data
check = baker.make_recipe("checks.diskspace_check")
baker.make("checks.CheckHistory", check_history=check, _quantity=30)
baker.make("checks.CheckHistory", check_id=check.id, _quantity=30)
check_history_data = baker.make(
"checks.CheckHistory",
check_history=check,
check_id=check.id,
_quantity=30,
)
@@ -526,6 +526,7 @@ class TestCheckTasks(TacticalTestCase):
"percent_used": 85,
"total": 500,
"free": 400,
"more_info": "More info",
}
resp = self.client.patch(url, data, format="json")
@@ -543,6 +544,7 @@ class TestCheckTasks(TacticalTestCase):
"percent_used": 95,
"total": 500,
"free": 400,
"more_info": "More info",
}
resp = self.client.patch(url, data, format="json")
@@ -573,6 +575,7 @@ class TestCheckTasks(TacticalTestCase):
"percent_used": 95,
"total": 500,
"free": 400,
"more_info": "More info",
}
resp = self.client.patch(url, data, format="json")
@@ -592,6 +595,7 @@ class TestCheckTasks(TacticalTestCase):
"percent_used": 95,
"total": 500,
"free": 400,
"more_info": "More info",
}
resp = self.client.patch(url, data, format="json")
@@ -608,6 +612,7 @@ class TestCheckTasks(TacticalTestCase):
"percent_used": 50,
"total": 500,
"free": 400,
"more_info": "More info",
}
resp = self.client.patch(url, data, format="json")
@@ -791,12 +796,7 @@ class TestCheckTasks(TacticalTestCase):
)
# test failing info
data = {
"id": ping.id,
"output": "Reply from 192.168.1.27: Destination host unreachable",
"has_stdout": True,
"has_stderr": False,
}
data = {"id": ping.id, "status": "failing", "output": "reply from a.com"}
resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)
@@ -806,13 +806,6 @@ class TestCheckTasks(TacticalTestCase):
self.assertEqual(new_check.alert_severity, "info")
# test failing warning
data = {
"id": ping.id,
"output": "Reply from 192.168.1.27: Destination host unreachable",
"has_stdout": True,
"has_stderr": False,
}
ping.alert_severity = "warning"
ping.save()
@@ -824,13 +817,6 @@ class TestCheckTasks(TacticalTestCase):
self.assertEqual(new_check.alert_severity, "warning")
# test failing error
data = {
"id": ping.id,
"output": "Reply from 192.168.1.27: Destination host unreachable",
"has_stdout": True,
"has_stderr": False,
}
ping.alert_severity = "error"
ping.save()
@@ -842,13 +828,6 @@ class TestCheckTasks(TacticalTestCase):
self.assertEqual(new_check.alert_severity, "error")
# test failing error
data = {
"id": ping.id,
"output": "some output",
"has_stdout": False,
"has_stderr": True,
}
resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)
@@ -857,12 +836,7 @@ class TestCheckTasks(TacticalTestCase):
self.assertEqual(new_check.alert_severity, "error")
# test passing
data = {
"id": ping.id,
"output": "Reply from 192.168.1.1: bytes=32 time<1ms TTL=64",
"has_stdout": True,
"has_stderr": False,
}
data = {"id": ping.id, "status": "passing", "output": "reply from a.com"}
resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)
@@ -881,7 +855,7 @@ class TestCheckTasks(TacticalTestCase):
)
# test passing running
data = {"id": winsvc.id, "exists": True, "status": "running"}
data = {"id": winsvc.id, "status": "passing", "more_info": "ok"}
resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)
@@ -889,20 +863,8 @@ class TestCheckTasks(TacticalTestCase):
new_check = Check.objects.get(pk=winsvc.id)
self.assertEqual(new_check.status, "passing")
# test passing start pending
winsvc.pass_if_start_pending = True
winsvc.save()
data = {"id": winsvc.id, "exists": True, "status": "start_pending"}
resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)
new_check = Check.objects.get(pk=winsvc.id)
self.assertEqual(new_check.status, "passing")
# test failing no start
data = {"id": winsvc.id, "exists": True, "status": "not running"}
# test failing
data = {"id": winsvc.id, "status": "failing", "more_info": "ok"}
resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)
@@ -911,7 +873,7 @@ class TestCheckTasks(TacticalTestCase):
self.assertEqual(new_check.status, "failing")
self.assertEqual(new_check.alert_severity, "info")
# test failing and attempt start
""" # test failing and attempt start
winsvc.restart_if_stopped = True
winsvc.alert_severity = "warning"
winsvc.save()
@@ -976,9 +938,9 @@ class TestCheckTasks(TacticalTestCase):
self.assertEqual(resp.status_code, 200)
new_check = Check.objects.get(pk=winsvc.id)
self.assertEqual(new_check.status, "passing")
self.assertEqual(new_check.status, "passing") """
def test_handle_eventlog_check(self):
""" def test_handle_eventlog_check(self):
from checks.models import Check
url = "/api/v3/checkrunner/"
@@ -1180,4 +1142,4 @@ class TestCheckTasks(TacticalTestCase):
new_check = Check.objects.get(pk=eventlog.id)
self.assertEquals(new_check.status, "passing")
self.assertEquals(new_check.status, "passing") """

View File

@@ -8,5 +8,5 @@ urlpatterns = [
path("<pk>/loadchecks/", views.load_checks),
path("getalldisks/", views.get_disks_for_policies),
path("runchecks/<pk>/", views.run_checks),
path("history/<int:checkpk>/", views.CheckHistory.as_view()),
path("history/<int:checkpk>/", views.GetCheckHistory.as_view()),
]

View File

@@ -15,7 +15,7 @@ from automation.models import Policy
from scripts.models import Script
from tacticalrmm.utils import notify_error
from .models import Check
from .models import Check, CheckHistory
from .permissions import ManageChecksPerms, RunChecksPerms
from .serializers import CheckHistorySerializer, CheckSerializer
@@ -146,7 +146,7 @@ class GetUpdateDeleteCheck(APIView):
return Response(f"{check.readable_desc} was deleted!")
class CheckHistory(APIView):
class GetCheckHistory(APIView):
def patch(self, request, checkpk):
check = get_object_or_404(Check, pk=checkpk)
@@ -160,7 +160,7 @@ class CheckHistory(APIView):
- djangotime.timedelta(days=request.data["timeFilter"]),
)
check_history = check.check_history.filter(timeFilter).order_by("-x") # type: ignore
check_history = CheckHistory.objects.filter(check_id=checkpk).filter(timeFilter).order_by("-x") # type: ignore
return Response(
CheckHistorySerializer(

View File

@@ -1,6 +1,5 @@
from django.core.management.base import BaseCommand
from agents.models import Agent
from logs.models import PendingAction
from scripts.models import Script
@@ -9,22 +8,6 @@ class Command(BaseCommand):
help = "Collection of tasks to run after updating the rmm, after migrations"
def handle(self, *args, **kwargs):
# 10-16-2020 changed the type of the agent's 'disks' model field
# from a dict of dicts, to a list of disks in the golang agent
# the following will convert dicts to lists for agent's still on the python agent
agents = Agent.objects.only("pk", "disks")
for agent in agents:
if agent.disks is not None and isinstance(agent.disks, dict):
new = []
for k, v in agent.disks.items():
new.append(v)
agent.disks = new
agent.save(update_fields=["disks"])
self.stdout.write(
self.style.SUCCESS(f"Migrated disks on {agent.hostname}")
)
# remove task pending actions. deprecated 4/20/2021
PendingAction.objects.filter(action_type="taskaction").delete()

View File

@@ -85,7 +85,7 @@ def dashboard_info(request):
"client_tree_sort": request.user.client_tree_sort,
"client_tree_splitter": request.user.client_tree_splitter,
"loading_bar_color": request.user.loading_bar_color,
"no_code_sign": hasattr(settings, "NOCODESIGN") and settings.NOCODESIGN,
"hosted": hasattr(settings, "HOSTED") and settings.HOSTED,
}
)

View File

@@ -1,19 +1,18 @@
asgiref==3.3.4
asyncio-nats-client==0.11.4
celery==5.0.5
certifi==2020.12.5
celery==5.1.0
certifi==2021.5.30
cffi==1.14.5
channels==3.0.3
channels_redis==3.2.0
chardet==4.0.0
cryptography==3.4.7
daphne==3.0.2
Django==3.2.2
Django==3.2.4
django-cors-headers==3.7.0
django-rest-knox==4.1.0
djangorestframework==3.12.4
future==0.18.2
kombu==5.0.2
loguru==0.5.3
msgpack==1.0.2
packaging==20.9
@@ -26,10 +25,10 @@ pytz==2021.1
qrcode==6.1
redis==3.5.3
requests==2.25.1
six==1.15.0
six==1.16.0
sqlparse==0.4.1
twilio==6.57.0
urllib3==1.26.4
twilio==6.59.1
urllib3==1.26.5
uWSGI==2.0.19.1
validators==0.18.2
vine==5.0.0

View File

@@ -6,7 +6,9 @@
"name": "Firefox - Clean Cache",
"description": "This script will clean up Mozilla Firefox for all users.",
"shell": "powershell",
"category": "TRMM (Win):Browsers"
"category": "TRMM (Win):Browsers",
"default_timeout": "300"
},
{
"guid": "3ff6a386-11d1-4f9d-8cca-1b0563bb6443",
@@ -15,7 +17,8 @@
"name": "Chrome - Clear Cache for All Users",
"description": "This script will clean up Google Chrome for all users.",
"shell": "powershell",
"category": "TRMM (Win):Browsers"
"category": "TRMM (Win):Browsers",
"default_timeout": "300"
},
{
"guid": "be1de837-f677-4ac5-aa0c-37a0fc9991fc",
@@ -24,7 +27,8 @@
"name": "Adobe Reader DC - Install",
"description": "Installs Adobe Reader DC.",
"shell": "powershell",
"category": "TRMM (Win):3rd Party Software>Chocolatey"
"category": "TRMM (Win):3rd Party Software>Chocolatey",
"default_timeout": "300"
},
{
"guid": "2ee134d5-76aa-4160-b334-a1efbc62079f",
@@ -33,7 +37,8 @@
"name": "Duplicati - Install",
"description": "This script installs Duplicati 2.0.5.1 as a service.",
"shell": "powershell",
"category": "TRMM (Win):3rd Party Software"
"category": "TRMM (Win):3rd Party Software",
"default_timeout": "300"
},
{
"guid": "81cc5bcb-01bf-4b0c-89b9-0ac0f3fe0c04",
@@ -42,7 +47,8 @@
"name": "Windows Update - Reset",
"description": "This script will reset all of the Windows Updates components to DEFAULT SETTINGS.",
"shell": "powershell",
"category": "TRMM (Win):Updates"
"category": "TRMM (Win):Updates",
"default_timeout": "300"
},
{
"guid": "8db87ff0-a9b4-4d9d-bc55-377bbcb85b6d",
@@ -51,7 +57,8 @@
"name": "Disk - Cleanup C: drive",
"description": "Cleans the C: drive's Window Temperary files, Windows SoftwareDistribution folder, the local users Temperary folder, IIS logs (if applicable) and empties the recycling bin. All deleted files will go into a log transcript in $env:TEMP. By default this script leaves files that are newer than 7 days old however this variable can be edited.",
"shell": "powershell",
"category": "TRMM (Win):Maintenance"
"category": "TRMM (Win):Maintenance",
"default_timeout": "25000"
},
{
"guid": "2f28e8c1-ae0f-4b46-a826-f513974526a3",
@@ -78,7 +85,8 @@
"name": "Speed Test - Python",
"description": "Runs a Speed Test using Python",
"shell": "python",
"category": "TRMM (Win):Network"
"category": "TRMM (Win):Network",
"default_timeout": "120"
},
{
"guid": "9d34f482-1f0c-4b2f-b65f-a9cf3c13ef5f",
@@ -161,6 +169,18 @@
"shell": "powershell",
"category": "TRMM (Win):Collectors"
},
{
"guid": "973c34d7-cab0-4fda-999c-b4933655f946",
"filename": "Win_Screenconnect_GetGUID.ps1",
"submittedBy": "https://github.com/silversword411",
"name": "Screenconnect - Get GUID for client",
"description": "Returns Screenconnect GUID for client - Use with Custom Fields for later use. ",
"args": [
"-serviceName {{client.ScreenConnectService}}"
],
"shell": "powershell",
"category": "TRMM (Win):Collectors"
},
{
"guid": "95a2ee6f-b89b-4551-856e-3081b041caa7",
"filename": "Win_Power_Profile_Reset_High_Performance_to_Defaults.ps1",
@@ -186,7 +206,8 @@
"name": "Windows 10 Upgrade",
"description": "Forces an upgrade to the latest release of Windows 10.",
"shell": "powershell",
"category": "TRMM (Win):Updates"
"category": "TRMM (Win):Updates",
"default_timeout": "25000"
},
{
"guid": "375323e5-cac6-4f35-a304-bb7cef35902d",
@@ -222,7 +243,8 @@
"name": "SSH - Install Feature and Enable",
"description": "Installs and enabled OpenSSH Server Feature in Win10",
"shell": "powershell",
"category": "TRMM (Win):Windows Features"
"category": "TRMM (Win):Windows Features",
"default_timeout": "300"
},
{
"guid": "2435297a-6263-4e90-8688-1847400d0e22",
@@ -339,7 +361,8 @@
"name": "Update Installed Apps",
"description": "Update all apps that were installed using Chocolatey.",
"shell": "cmd",
"category": "TRMM (Win):3rd Party Software>Chocolatey"
"category": "TRMM (Win):3rd Party Software>Chocolatey",
"default_timeout": "3600"
},
{
"guid": "fff8024d-d72e-4457-84fa-6c780f69a16f",
@@ -660,4 +683,4 @@
"category": "TRMM (Win):Misc>Reference",
"default_timeout": "1"
}
]
]

View File

@@ -41,7 +41,7 @@ app.conf.beat_schedule = {
},
"get-wmi": {
"task": "agents.tasks.get_wmi_task",
"schedule": crontab(minute="*/18"),
"schedule": crontab(minute=18, hour="*/5"),
},
}

View File

@@ -15,22 +15,22 @@ EXE_DIR = os.path.join(BASE_DIR, "tacticalrmm/private/exe")
AUTH_USER_MODEL = "accounts.User"
# latest release
TRMM_VERSION = "0.6.11"
TRMM_VERSION = "0.6.14"
# bump this version everytime vue code is changed
# to alert user they need to manually refresh their browser
APP_VER = "0.0.136"
APP_VER = "0.0.138"
# https://github.com/wh1te909/rmmagent
LATEST_AGENT_VER = "1.5.6"
LATEST_AGENT_VER = "1.5.8"
MESH_VER = "0.8.35"
MESH_VER = "0.8.60"
# for the update script, bump when need to recreate venv or npm install
PIP_VER = "16"
NPM_VER = "15"
PIP_VER = "18"
NPM_VER = "17"
SETUPTOOLS_VER = "56.1.0"
SETUPTOOLS_VER = "57.0.0"
WHEEL_VER = "0.36.2"
DL_64 = f"https://github.com/wh1te909/rmmagent/releases/download/v{LATEST_AGENT_VER}/winagent-v{LATEST_AGENT_VER}.exe"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
SCRIPT_VERSION="12"
SCRIPT_VERSION="13"
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/backup.sh'
GREEN='\033[0;32m'
@@ -59,6 +59,7 @@ mkdir ${tmp_dir}/nginx
mkdir ${tmp_dir}/systemd
mkdir ${tmp_dir}/rmm
mkdir ${tmp_dir}/confd
mkdir ${tmp_dir}/redis
pg_dump --dbname=postgresql://"${POSTGRES_USER}":"${POSTGRES_PW}"@127.0.0.1:5432/tacticalrmm | gzip -9 > ${tmp_dir}/postgres/db-${dt_now}.psql.gz
@@ -72,6 +73,8 @@ sudo tar -czvf ${tmp_dir}/nginx/etc-nginx.tar.gz -C /etc/nginx .
sudo tar -czvf ${tmp_dir}/confd/etc-confd.tar.gz -C /etc/conf.d .
sudo tar -czvf ${tmp_dir}/redis/etc-redis.tar.gz -C /var/lib/redis/appendonly.aof
sudo cp ${sysd}/rmm.service ${sysd}/celery.service ${sysd}/celerybeat.service ${sysd}/meshcentral.service ${sysd}/nats.service ${tmp_dir}/systemd/
if [ -f "${sysd}/daphne.service" ]; then
sudo cp ${sysd}/daphne.service ${tmp_dir}/systemd/

View File

@@ -1,4 +1,4 @@
FROM nats:2.2-alpine
FROM nats:2.2.6-alpine
ENV TACTICAL_DIR /opt/tactical
ENV TACTICAL_READY_FILE ${TACTICAL_DIR}/tmp/tactical.ready

View File

@@ -18,6 +18,7 @@ volumes:
postgres_data:
mongo_data:
mesh_data:
redis_data:
services:
# postgres database for api service
@@ -38,7 +39,10 @@ services:
tactical-redis:
container_name: trmm-redis
image: redis:6.0-alpine
command: redis-server --appendonly yes
restart: always
volumes:
- redis_data:/data
networks:
- redis

View File

@@ -61,6 +61,8 @@ Category or Function - What It Does
![json_name_examples](images/community_scripts_name_field_example1.png)
*****
## Making Script Files
### Good Habits
@@ -117,6 +119,8 @@ c:\ProgramData\TacticalRMM\
- Doesn't play well with other community scripts (reused names etc.)
*****
## Useful Reference Script Examples
RunAsUser (since Tactical RMM runs as system)
@@ -128,6 +132,8 @@ Command Paramater Ninja
Optional Command Parameters and testing for errors
[https://github.com/wh1te909/tacticalrmm/blob/develop/scripts/Win_Rename_Computer.ps1](https://github.com/wh1te909/tacticalrmm/blob/develop/scripts/Win_Rename_Computer.ps1)
*****
## Volunteers Needed
If you want to contribute back to the project there are a lot of scripts that need some TLC (Tender Loving Care) please paruse thru them here: [https://github.com/wh1te909/tacticalrmm/tree/develop/scripts_wip](https://github.com/wh1te909/tacticalrmm/tree/develop/scripts_wip)

View File

@@ -105,6 +105,7 @@ Then you're `push`ing that updated local repo to your online Github fork
Check your Github fork in browser, should be up to date now with original. Repeat 6 or 7 as necessary
*****
## Reference
### Customizing the Admin Web Interface

View File

@@ -0,0 +1,31 @@
# Examples
## Create Run URL Action to Computer support page
This will create a URL link that will take you to the support page for a computer based on the computers Serial Number
1. Goto `Settings | Global Settings | Custom Fields`
Under Agents tab Add Custom Field (CaSe SeNsItIve)
![Custom Field](../images/example1_customfield.png)
2. Create Task (best to use `Settings | Automation Manager` if you want to apply it to all computers). Add script that has an output of the data you want.
![Collector Script](../images/example1_taskcollectorscript.png)
3. Create URL Action (under `Settings | Global Settings | URL ACTIONS`) for Manufacturer websites
![URL Actions](../images/example1_urlaction.png)
Dell Support Page
```
https://www.dell.com/support/home/en-us/product-support/servicetag/{{agent.SerialNumber}}/overview
```
Lenovo Support Page
```
https://www.dell.com/support/home/en-us/product-support/servicetag/{{agent.SerialNumber}}/overview
```

View File

@@ -0,0 +1,58 @@
# How It All Works
INSERT WIREFRAME GRAPHIC HERE USING <https://www.yworks.com/yed-live/>
## Server
## Windows Agent
Found in `%programfiles%\TacticalAgent`
### Services
3 services exist on all clients
* `Mesh Agent`
![MeshService](images/trmm_services_mesh.png)
![MeshAgentTaskManager](images/trmm_services__taskmanager_mesh.png)
**AND**
* `TacticalAgent` and `Tactical RMM RPC Service`
![TacticalAgentServices](images/trmm_services.png)
![TacticalAgentTaskManager](images/trmm_services__taskmanager_agent.png)
The [MeshCentral](https://meshcentral.com/) system which is accessible from <https://mesh.example.com> and is used
`Tactical RMM Agent`
* It runs 2 goroutines
* one is the checkrunner which runs all the checks and then just sleeps until it's time to run more checks
* 2nd goroutine periodically sends info about the agent to the rmm and also handles agent recovery
!!!note
In Task Manager you will see additional `Tactical RMM Agent` processes appear and disappear. These are your Checks and Tasks running at scheduled intervals
`Tactical RMM RPC Service`
* Uses the pub/sub model so anytime you do anything realtime from rmm (like a send command or run script)
* It maintains a persistent connection to your to the api.example.com rmm server on port **443 CONFIRM** and is listening for events
* It handles your Agent updates (Auto triggers at 35mins past every hour or when run manually from server Agents | Update Agents menu)
***
### Agent Installation Process
Adds Defender AV exclusions
Copies
***
### Agent Update Process
Downloads latest `winagent-vx.x.x-x86/64.exe` to `%programfiles%`
Executes the file (INNO setup exe)
Files create `c:\Windows\temp\Tacticalxxxx\` folder for install (and log files)

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -14,6 +14,10 @@
## Install
!!!info
It is recommended that you keep your server updated regularly (monthly). SSL wildcard certs will expire every 3 months and need manual updating as well. <br/><br/>
Until we reach production release, there may be architectural changes that may be made to Tactical RMM and only a regular patching schedule is supported by developers.
#### Run updates and setup the linux user
SSH into the server as **root**.<br/><br/>
Download and run the prereqs and latest updates<br/>

52
docs/docs/tipsntricks.md Normal file
View File

@@ -0,0 +1,52 @@
# Tips and Tricks
## Customize User Interface
Top right click Username, look at preferences pane. Set default tab: Servers|Workstations|Mixed
![User Preferences](images/trmm_user_preferences.png)
*****
## Screenconnect / Connectwise Control
### Install Tactical RMM via Screeconnect commands window
1. Create a Deplopment under Agents | Manage Deployments
2. Replace `<deployment URL>` below with your Deployment Download Link.
**x64**
```cmd
#!ps
#maxlength=500000
#timeout=600000
Invoke-WebRequest "<deployment URL>" -OutFile ( New-Item -Path "C:\temp\trmminstallx64.exe" -Force )
$proc = Start-Process c:\temp\trmminstallx64.exe -ArgumentList '-silent' -PassThru
Wait-Process -InputObject $proc
if ($proc.ExitCode -ne 0) {
Write-Warning "$_ exited with status code $($proc.ExitCode)"
}
Remove-Item -Path "c:\temp\trmminstallx64.exe" -Force
```
**x86**
```cmd
#!ps
#maxlength=500000
#timeout=600000
Invoke-WebRequest "<deployment URL>" -OutFile ( New-Item -Path "C:\temp\trmminstallx86.exe" -Force )
$proc = Start-Process c:\temp\trmminstallx86.exe -ArgumentList '-silent' -PassThru
Wait-Process -InputObject $proc
if ($proc.ExitCode -ne 0) {
Write-Warning "$_ exited with status code $($proc.ExitCode)"
}
Remove-Item -Path "c:\temp\trmminstallx86.exe" -Force
```
###

View File

@@ -23,6 +23,7 @@ nav:
- "User Interface Preferences": functions/user_ui.md
- "Django Admin": functions/django_admin.md
- "Settings Override": functions/settings_override.md
- "Examples": functions/examples.md
- Backup: backup.md
- Restore: restore.md
- Troubleshooting: troubleshooting.md

2
go.mod
View File

@@ -5,6 +5,6 @@ go 1.16
require (
github.com/nats-io/nats-server/v2 v2.1.8-0.20201129161730-ebe63db3e3ed // indirect
github.com/nats-io/nats.go v1.11.0
github.com/ugorji/go/codec v1.2.5
github.com/ugorji/go/codec v1.2.6
golang.org/x/sys v0.0.0-20210122235752-a8b976e07c7b // indirect
)

8
go.sum
View File

@@ -34,10 +34,10 @@ github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/ugorji/go v1.2.5 h1:NozRHfUeEta89taVkyfsDVSy2f7v89Frft4pjnWuGuc=
github.com/ugorji/go v1.2.5/go.mod h1:gat2tIT8KJG8TVI8yv77nEO/KYT6dV7JE1gfUa8Xuls=
github.com/ugorji/go/codec v1.2.5 h1:8WobZKAk18Msm2CothY2jnztY56YVY8kF1oQrj21iis=
github.com/ugorji/go/codec v1.2.5/go.mod h1:QPxoTbPKSEAlAHPYt02++xp/en9B/wUdwFCz+hj5caA=
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=

View File

@@ -1,6 +1,6 @@
#!/bin/bash
SCRIPT_VERSION="48"
SCRIPT_VERSION="50"
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/install.sh'
sudo apt install -y curl wget dirmngr gnupg lsb-release
@@ -167,11 +167,11 @@ sudo chmod 775 -R /etc/letsencrypt
print_green 'Downloading NATS'
nats_tmp=$(mktemp -d -t nats-XXXXXXXXXX)
wget https://github.com/nats-io/nats-server/releases/download/v2.2.3/nats-server-v2.2.3-linux-amd64.tar.gz -P ${nats_tmp}
wget https://github.com/nats-io/nats-server/releases/download/v2.2.6/nats-server-v2.2.6-linux-amd64.tar.gz -P ${nats_tmp}
tar -xzf ${nats_tmp}/nats-server-v2.2.3-linux-amd64.tar.gz -C ${nats_tmp}
tar -xzf ${nats_tmp}/nats-server-v2.2.6-linux-amd64.tar.gz -C ${nats_tmp}
sudo mv ${nats_tmp}/nats-server-v2.2.3-linux-amd64/nats-server /usr/local/bin/
sudo mv ${nats_tmp}/nats-server-v2.2.6-linux-amd64/nats-server /usr/local/bin/
sudo chmod +x /usr/local/bin/nats-server
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
rm -rf ${nats_tmp}
@@ -217,6 +217,10 @@ sudo rm -rf Python-3.9.2 Python-3.9.2.tgz
print_green 'Installing redis and git'
sudo apt install -y ca-certificates redis git
# apply redis configuration
sudo redis-cli config set appendonly yes
sudo redis-cli config rewrite
print_green 'Installing postgresql'
echo "$postgresql_repo" | sudo tee /etc/apt/sources.list.d/pgdg.list
@@ -487,12 +491,14 @@ map \$http_user_agent \$ignore_ua {
server {
listen 80;
listen [::]:80;
server_name ${rmmdomain};
return 301 https://\$server_name\$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name ${rmmdomain};
client_max_body_size 300M;
access_log /rmm/api/tacticalrmm/tacticalrmm/private/log/access.log combined if=\$ignore_ua;
@@ -549,6 +555,7 @@ echo "${nginxrmm}" | sudo tee /etc/nginx/sites-available/rmm.conf > /dev/null
nginxmesh="$(cat << EOF
server {
listen 80;
listen [::]:80;
server_name ${meshdomain};
return 301 https://\$server_name\$request_uri;
}
@@ -556,6 +563,7 @@ server {
server {
listen 443 ssl;
listen [::]:443 ssl;
proxy_send_timeout 330s;
proxy_read_timeout 330s;
server_name ${meshdomain};
@@ -710,6 +718,7 @@ server {
access_log /var/log/nginx/frontend-access.log;
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate ${CERT_PUB_KEY};
ssl_certificate_key ${CERT_PRIV_KEY};
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
@@ -720,7 +729,8 @@ server {
return 301 https://\$host\$request_uri;
}
listen 80;
listen 80;
listen [::]:80;
server_name ${frontenddomain};
return 404;
}

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#!/bin/bash
SCRIPT_VERSION="26"
SCRIPT_VERSION="28"
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/restore.sh'
sudo apt update
@@ -108,11 +108,11 @@ sudo apt update
print_green 'Downloading NATS'
nats_tmp=$(mktemp -d -t nats-XXXXXXXXXX)
wget https://github.com/nats-io/nats-server/releases/download/v2.2.3/nats-server-v2.2.3-linux-amd64.tar.gz -P ${nats_tmp}
wget https://github.com/nats-io/nats-server/releases/download/v2.2.6/nats-server-v2.2.6-linux-amd64.tar.gz -P ${nats_tmp}
tar -xzf ${nats_tmp}/nats-server-v2.2.3-linux-amd64.tar.gz -C ${nats_tmp}
tar -xzf ${nats_tmp}/nats-server-v2.2.6-linux-amd64.tar.gz -C ${nats_tmp}
sudo mv ${nats_tmp}/nats-server-v2.2.3-linux-amd64/nats-server /usr/local/bin/
sudo mv ${nats_tmp}/nats-server-v2.2.6-linux-amd64/nats-server /usr/local/bin/
sudo chmod +x /usr/local/bin/nats-server
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
rm -rf ${nats_tmp}
@@ -189,6 +189,13 @@ sudo rm -rf Python-3.9.2 Python-3.9.2.tgz
print_green 'Installing redis and git'
sudo apt install -y ca-certificates redis git
# redis configuration
sudo tar -xzf ${tmp_dir}/redis/etc-redis.tar.gz -C /var/lib/redis
sudo redis-check-aof --fix /var/lib/redis/appendonly.aof
sudo redis-cli config set appendonly yes
sudo redis-cli config rewrite
print_green 'Installing postgresql'
echo "$postgresql_repo" | sudo tee /etc/apt/sources.list.d/pgdg.list

View File

@@ -4,6 +4,8 @@
#antivirusName must match the "displayName" exactly
#If no antivirusName parameter is specified, the tool returns success if there is any active up to date antivirus on the system
# OS Build must be greater than 14393 to support this script. If it's not it returns exit code 2
param($antivirusName = "*")
@@ -93,6 +95,11 @@ function Add-ProductStates {
}
}
if ([environment]::OSVersion.Version.Build -le 14393) {
write-host "Antivirus check not supported on this OS. Returning Exit Code 2."
exit 2
}
$return = Get-CimInstance -Namespace root/SecurityCenter2 -className AntivirusProduct |
Where-Object {

View File

@@ -1,4 +1,9 @@
## Copied from https://github.com/ThatsNASt/tacticalrmm to add to new pull request for https://github.com/wh1te909/tacticalrmm
#
# WARNING
# 1. Only applies to drive C
# 2. Assumes you're encrypting more than the used space. "Used Space Only Encrypted" is the default windows behavior which is not compatible here.
function Log-Message {
Param
(
@@ -22,7 +27,7 @@ function Log-Message {
$log = "BitlockerReport.txt"
#Find BL info
$mbde = [string](manage-bde -status)
$mbde = [string](manage-bde -status C:)
$mbdeProt = (manage-bde -protectors -get c: | Select-Object -Skip 6)
#Dig out the recovery password, check for PIN
ForEach ($line in $mbdeProt) {
@@ -94,4 +99,4 @@ if ($Encrypted -eq "Yes" -and $RecoveryPassword -and $PIN -eq $true) {
Log-Message "SUCCESS: Encrypted, PIN enabled, password is set." $log e
Write-Host "Script check passed"
exit 0
}
}

View File

@@ -1 +1 @@
cup -y all
cup all -y

View File

@@ -31,6 +31,7 @@ else {
Install-Module -Name RunAsUser -Force
}
# Used to pull variables in and use them inside the script block. Contains message to show user
Set-Content -Path c:\windows\temp\message.txt -Value $args
Invoke-AsCurrentUser -scriptblock {
@@ -55,5 +56,5 @@ Invoke-AsCurrentUser -scriptblock {
Submit-BTNotification -Content $Content
}
# Cleanup temp file for message variables
Remove-Item -Path c:\windows\temp\message.txt

View File

@@ -10,28 +10,6 @@
Submitted by: https://github.com/dinger1986
#>
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$regpath = HKCU:\Software\Microsoft\Office\16.0\Outlook\Preferences
$regname = DelegateSentItemsStyle
$regvalue = 1
$regproperty = Dword
If (!(test-path '%ProgramData%\Tactical RMM\temp')) {
New-Item -ItemType Directory -Force -Path '%ProgramData%\Tactical RMM\temp'
}
If (!(test-path C:\TEMP\curpsxpolicy.txt)) {
$curexpolicy = Get-ExecutionPolicy
(
echo $curexpolicy
)>"%ProgramData%\Tactical RMM\temp\curpsxpolicy.txt"
}
Set-ExecutionPolicy -ExecutionPolicy Unrestricted
if (Get-PackageProvider -Name NuGet) {
Write-Output "NuGet Already Added"
}
@@ -48,14 +26,30 @@ else {
Install-Module -Name RunAsUser -Force
}
If (!(test-path $env:programdata\TacticalRMM\temp\)) {
New-Item -ItemType Directory -Force -Path $env:programdata\TacticalRMM\temp\
}
If (!(test-path $env:programdata\TacticalRMM\temp\curpsxpolicy.txt)) {
$curexpolicy = Get-ExecutionPolicy
(
Write-Output $curexpolicy
)>$env:programdata\TacticalRMM\temp\curpsxpolicy.txt
}
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell -Name ExecutionPolicy -Value Unrestricted
Invoke-AsCurrentUser -scriptblock {
New-ItemProperty -Path "$regpath" -Name "$regname" -Value "$regvalue" -PropertyType "$regproperty"
# Modify below for other versions of Office
$regpath = 'Software\Microsoft\Office\16.0\Outlook\Preferences'
$regname = "DelegateSentItemsStyle"
$regvalue = "1"
$regproperty = "Dword"
New-ItemProperty -Path HKCU:\$regpath -Name $regname -Value $regvalue -PropertyType $regproperty
}
Write-Output "Successfully changed Sent Items for Delegated folders"
$curpsxpol = Get-Content -Path "%ProgramData%\Tactical RMM\temp\curpsxpolicy.txt";
$curpsxpol = Get-Content -Path $env:programdata\TacticalRMM\temp\curpsxpolicy.txt;
Set-ExecutionPolicy -ExecutionPolicy $curpsxpol
del "%ProgramData%\Tactical RMM\temp\curpsxpolicy.txt"
Set-ExecutionPolicy -ExecutionPolicy $curpsxpol

View File

@@ -0,0 +1,26 @@
<#
Requires global variables for serviceName "ScreenConnectService"
serviceName is the name of the ScreenConnect Service once it is installed EG: "ScreenConnect Client (1327465grctq84yrtocq)"
Variable value must start and end with " (Prior to TRMM Version 0.6.5), remove / don't use " on TRMM Version 0.6.5 or later.
Requires Custom Fields Agent entry Name: ScreenConnectGUID Type: text
URL Action entry (check your screenconnect to see what folder name is your "All Machines" folder): https://YOURNAME.screenconnect.com/Host#Access/All%20Machines//{{agent.ScreenConnectGUID}}/Join
or https://YOURNAME.screenconnect.com/Host#Access/All%20Machines%20by%20Company//{{agent.ScreenConnectGUID}}/Join
#>
param (
[string] $serviceName
)
if (!$serviceName) {
write-output "Variable not specified ScreenConnectService, please create a global custom field under Client called ScreenConnectService, Example Value: `"ScreenConnect Client (1327465grctq84yrtocq)`" `n"
$ErrorCount += 1
}
if (!$ErrorCount -eq 0) {
exit 1
}
$imagePath = Get-Itempropertyvalue "HKLM:\SYSTEM\ControlSet001\Services\$serviceName" -Name "ImagePath"
$imagePath2 = ($imagePath -split "&s=")[1]
$machineGUID = ($imagePath2 -split "&k=")[0]
Write-Output $machineGUID

View File

@@ -1,18 +0,0 @@
# Needs to be parameterized: $icofile, $URL, $ShortcutPath
# Need to change paths and test/create if don't exist
wget "https://www.example.com/logos/example.ico" -outfile "c:\agent\example.ico"
$WshShell = New-Object -comObject WScript.Shell
$path = "C:\Users\All Users\desktop\example.url"
$targetpath = "https://example.com/"
$iconlocation = "c:\agent\example.ico"
$iconfile = "IconFile=" + $iconlocation
$Shortcut = $WshShell.CreateShortcut($path)
$Shortcut.TargetPath = $targetpath
$Shortcut.Save()
Add-Content $path "HotKey=0"
Add-Content $path "$iconfile"
Add-Content $path "IconIndex=0"

View File

@@ -1,3 +1,5 @@
REM Print Spooler reset script. Will stop spooler, fix permissions on print folders, clear all files in print queues, and restart spooler service.
REM Stop Print Spooler
net stop "Spooler"

View File

@@ -1,2 +0,0 @@
net stop "Print Spooler"
net start "Print Spooler"

View File

@@ -0,0 +1,25 @@
<#
.Synopsis
Restart Print Spooler Service
.DESCRIPTION
Will force-restart the spooler service. With additional command parameter will also delete any pending print jobs
.EXAMPLE
Another example of how to use this cmdlet
.OUTPUTS
Any print jobs that are deleted
.NOTES
v1.0 5/2021
https://github.com/silversword411
.FUNCTIONALITY
Print Spooler Troubleshooting, restarts spooler service. Can also delete all print jobs that are pending
#>
#Restart Spooler service
Restart-Service -Name spooler -Force
#Deletes All print jobs within the last 15 years
$PrintJobs = get-wmiobject -class "Win32_PrintJob" -namespace "root\CIMV2" -computername . | Where-Object { [System.Management.ManagementDateTimeConverter]::ToDateTime($_.TimeSubmitted) -lt (Get-Date).AddDays(-5500) }
foreach ($job in $PrintJobs) {
# Write-Host "Canceling job $($job.JobId)"
$job.Delete()
}

View File

@@ -1,8 +0,0 @@
#Update with command parameters
#Deletes All print jobs within the last 2 days
$PrintJobs = get-wmiobject -class "Win32_PrintJob" -namespace "root\CIMV2" -computername . | Where-Object { [System.Management.ManagementDateTimeConverter]::ToDateTime($_.TimeSubmitted) -lt (Get-Date).AddDays(-2) }
foreach ($job in $PrintJobs) {
# Write-Host "Canceling job $($job.JobId)"
$job.Delete()
}

View File

@@ -1,7 +1,9 @@
md -Path 'C:\agent' -Force
wget "http://www.yourwebsite.com/logos/yourico.ico" -outfile "c:\agent\yourico.ico"
mkdir -Path 'C:\agent' -Force
Invoke-WebRequest "http://www.yourwebsite.com/logos/yourico.ico" -outfile "c:\agent\yourico.ico"
$WshShell = New-Object -comObject WScript.Shell
$path = "C:\Users\All Users\desktop\Jaxsupport.url"
$path = "C:\Users\All Users\desktop\Shortcut.url"
$targetpath = "https://yourwebsite.com"
$iconlocation = "c:\agent\yourico.ico"
$iconfile = "IconFile=" + $iconlocation

View File

@@ -1,6 +1,6 @@
#!/bin/bash
SCRIPT_VERSION="121"
SCRIPT_VERSION="123"
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/update.sh'
LATEST_SETTINGS_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/api/tacticalrmm/tacticalrmm/settings.py'
YELLOW='\033[1;33m'
@@ -184,14 +184,14 @@ if ! [[ $HAS_PY39 ]]; then
sudo rm -rf Python-3.9.2 Python-3.9.2.tgz
fi
HAS_NATS220=$(/usr/local/bin/nats-server -version | grep v2.2.3)
HAS_NATS220=$(/usr/local/bin/nats-server -version | grep v2.2.6)
if ! [[ $HAS_NATS220 ]]; then
printf >&2 "${GREEN}Updating nats to v2.2.3${NC}\n"
printf >&2 "${GREEN}Updating nats to v2.2.6${NC}\n"
nats_tmp=$(mktemp -d -t nats-XXXXXXXXXX)
wget https://github.com/nats-io/nats-server/releases/download/v2.2.3/nats-server-v2.2.3-linux-amd64.tar.gz -P ${nats_tmp}
tar -xzf ${nats_tmp}/nats-server-v2.2.3-linux-amd64.tar.gz -C ${nats_tmp}
wget https://github.com/nats-io/nats-server/releases/download/v2.2.6/nats-server-v2.2.6-linux-amd64.tar.gz -P ${nats_tmp}
tar -xzf ${nats_tmp}/nats-server-v2.2.6-linux-amd64.tar.gz -C ${nats_tmp}
sudo rm -f /usr/local/bin/nats-server
sudo mv ${nats_tmp}/nats-server-v2.2.3-linux-amd64/nats-server /usr/local/bin/
sudo mv ${nats_tmp}/nats-server-v2.2.6-linux-amd64/nats-server /usr/local/bin/
sudo chmod +x /usr/local/bin/nats-server
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
rm -rf ${nats_tmp}
@@ -307,5 +307,9 @@ if [[ "${CURRENT_MESH_VER}" != "${LATEST_MESH_VER}" ]] || [[ "$force" = true ]];
sudo systemctl start meshcentral
fi
# apply redis configuration
sudo redis-cli config set appendonly yes
sudo redis-cli config rewrite
rm -f $TMP_SETTINGS
printf >&2 "${GREEN}Update finished!${NC}\n"

1996
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,33 +10,27 @@
"test:e2e:ci": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\""
},
"dependencies": {
"@quasar/extras": "^1.10.4",
"@quasar/extras": "^1.10.6",
"apexcharts": "^3.23.1",
"axios": "^0.21.1",
"dotenv": "^8.2.0",
"prismjs": "^1.22.0",
"qrcode.vue": "^1.7.0",
"quasar": "^1.15.13",
"quasar": "^1.15.20",
"vue-apexcharts": "^1.6.0",
"vue-prism-editor": "^1.2.2"
},
"devDependencies": {
"@quasar/app": "^2.2.6",
"@quasar/cli": "^1.1.3",
"core-js": "^3.11.2",
"@quasar/app": "^2.2.10",
"@quasar/cli": "^1.2.1",
"core-js": "^3.14.0",
"eslint-plugin-cypress": "^2.11.2",
"flush-promises": "^1.0.2",
"fs-extra": "^9.1.0"
},
"browserslist": [
"last 4 Chrome versions",
"last 4 Firefox versions",
"last 2 Edge versions",
"last 3 Safari versions",
"last 3 Android versions",
"last 3 ChromeAndroid versions",
"last 3 FirefoxAndroid versions",
"last 3 iOS versions",
"last 2 Opera versions"
"last 3 Chrome versions",
"last 3 Firefox versions",
"last 2 Edge versions"
]
}
}

View File

@@ -261,6 +261,9 @@
@click="eventLogMoreInfo(props.row)"
>Last Output</span
>
<span v-else-if="props.row.check_type === 'diskspace' || props.row.check_type === 'winsvc'">{{
props.row.more_info
}}</span>
</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"

View File

@@ -12,6 +12,7 @@
@input="value => $emit('input', value)"
:rules="[...validationRules]"
reactive-rules
autogrow
/>
<q-toggle

View File

@@ -94,7 +94,7 @@
<q-item-section>Global Settings</q-item-section>
</q-item>
<!-- code sign -->
<q-item v-if="!noCodeSigning" clickable v-close-popup @click="showCodeSign = true">
<q-item v-if="!hosted" clickable v-close-popup @click="showCodeSign = true">
<q-item-section>Code Signing</q-item-section>
</q-item>
</q-list>
@@ -124,7 +124,7 @@
</q-menu>
</q-btn>
<!-- help -->
<q-btn size="md" dense no-caps flat label="Help">
<q-btn v-if="!hosted" size="md" dense no-caps flat label="Help">
<q-menu auto-close>
<q-list dense style="min-width: 100px">
<q-item clickable v-close-popup @click="openHelp('docs')">
@@ -272,8 +272,8 @@ export default {
};
},
computed: {
noCodeSigning() {
return this.$store.state.noCodeSign;
hosted() {
return this.$store.state.hosted;
},
},
methods: {

View File

@@ -136,7 +136,7 @@ export default {
getOptions() {
this.getClients();
this.getSites();
this.agentOptions = Object.freeze(this.getAgentOptions());
this.agentOptions = this.getAgentOptions();
},
show() {
this.$refs.dialog.show();
@@ -152,7 +152,7 @@ export default {
this.hide();
},
},
mounted() {
created() {
this.getOptions();
// copy prop data locally

View File

@@ -143,7 +143,7 @@ export default {
getOptions() {
this.getClients();
this.getSites();
this.agentOptions = Object.freeze(this.getAgentOptions());
this.agentOptions = this.getAgentOptions();
},
show() {
this.$refs.dialog.show();
@@ -159,7 +159,7 @@ export default {
this.hide();
},
},
mounted() {
created() {
this.getOptions();
// copy prop data locally

View File

@@ -111,6 +111,7 @@
dense
options-dense
outlined
clearable
v-model="template.action"
:options="scriptOptions"
map-options
@@ -174,6 +175,7 @@
dense
options-dense
outlined
clearable
v-model="template.resolved_action"
:options="scriptOptions"
map-options
@@ -696,4 +698,4 @@ export default {
if (this.editing) Object.assign(this.template, this.alertTemplate);
},
};
</script>
</script>

View File

@@ -19,6 +19,7 @@
stack-label
filled
counter
class="full-width"
accept=".exe"
>
<template v-slot:prepend>

View File

@@ -138,6 +138,7 @@
v-model="localField.default_value_string"
:rules="[...defaultValueRules]"
reactive-rules
autogrow
/>
</q-card-section>
<q-card-section>

View File

@@ -46,6 +46,7 @@
stack-label
filled
counter
class="full-width"
accept=".ps1, .bat, .py"
>
<template v-slot:prepend>

View File

@@ -73,7 +73,12 @@
label="Collector Task"
v-model="collector"
class="q-pb-sm"
@input="autotask.custom_field = null"
@input="
() => {
autotask.custom_field = null;
autotask.collector_all_ouput = false;
}
"
/>
<q-select
v-if="collector"
@@ -87,6 +92,13 @@
options-dense
hint="The last line of script output will be saved to custom field selected"
/>
<q-checkbox
v-if="collector"
dense
label="Save all output (Only for text area)"
v-model="autotask.collector_all_output"
class="q-py-sm"
/>
</q-card-section>
<q-card-section>
<q-select
@@ -229,6 +241,7 @@ export default {
task_type: "scheduled",
timeout: 120,
alert_severity: "info",
collector_all_output: false,
},
policyChecks: [],
severityOptions: [

View File

@@ -90,6 +90,13 @@
options-dense
hint="The return value of script will be saved to custom field selected"
/>
<q-checkbox
v-if="collector"
dense
label="Save all output (Only for text area)"
v-model="autotask.collector_all_output"
class="q-py-sm"
/>
</q-card-section>
<q-card-section>
<q-input
@@ -131,6 +138,7 @@ export default {
alert_severity: null,
timeout: 120,
custom_field: null,
collector_all_output: false,
},
collector: false,
customFieldOptions: [],
@@ -197,6 +205,7 @@ export default {
this.autotask.alert_severity = this.task.alert_severity;
this.autotask.timeout = this.task.timeout;
this.autotask.custom_field = this.task.custom_field;
this.autotask.collector_all_output = this.task.collector_all_output;
},
};
</script>

View File

@@ -72,18 +72,18 @@ export default {
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
Notify.create({ type: "negative", timeout: 2000, message: "Warning Threshold or Error Threshold need to be set" });
return false;
}
if (!diskcheck && warning > error && warning > 0 && error > 0) {
Notify.create(notifyErrorConfig("Warning Threshold must be less than Error Threshold", 2000));
return false
Notify.create({ type: "negative", timeout: 2000, message: "Warning Threshold must be less than Error Threshold" });
return false;
}
if (diskcheck && warning < error && warning > 0 && error > 0) {
Notify.create(notifyErrorConfig("Warning Threshold must be more than Error Threshold", 2000));
return false
Notify.create({ type: "negative", timeout: 2000, message: "Warning Threshold must be more than Error Threshold" });
return false;
}
return true;

View File

@@ -35,7 +35,7 @@ export default function () {
defaultAgentTblTab: "server",
clientTreeSort: "alphafail",
clientTreeSplitter: 11,
noCodeSign: false,
hosted: false,
},
getters: {
clientTreeSplitterModel(state) {
@@ -159,8 +159,8 @@ export default function () {
SET_CLIENT_TREE_SORT(state, val) {
state.clientTreeSort = val
},
SET_NO_CODE_SIGN(state, val) {
state.noCodeSign = val
SET_HOSTED(state, val) {
state.hosted = val
}
},
actions: {

View File

@@ -742,7 +742,7 @@ export default {
this.$store.commit("SET_AGENT_DBLCLICK_ACTION", r.data.dbl_click_action);
this.$store.commit("SET_URL_ACTION", r.data.url_action);
this.$store.commit("setShowCommunityScripts", r.data.show_community_scripts);
this.$store.commit("SET_NO_CODE_SIGN", r.data.no_code_sign);
this.$store.commit("SET_HOSTED", r.data.hosted);
});
},
showToggleMaintenance(node) {

View File

@@ -37,6 +37,7 @@
stack-label
filled
counter
class="full-width"
accept=".exe"
>
<template v-slot:prepend>