Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5aa15c51ec | ||
|
|
a8aedd9cf3 | ||
|
|
b851b632bc | ||
|
|
541e07fb65 | ||
|
|
6ad16a897d | ||
|
|
72f1053a93 | ||
|
|
fb15a2762c | ||
|
|
9165248b91 | ||
|
|
add18b29db | ||
|
|
1971653548 | ||
|
|
392cd64d7b | ||
|
|
b5affbb7c8 | ||
|
|
71d1206277 | ||
|
|
26e6a8c409 | ||
|
|
eb54fae11a | ||
|
|
ee773e5966 | ||
|
|
7218ccdba8 | ||
|
|
332400e48a | ||
|
|
ad1a5d3702 | ||
|
|
3006b4184d | ||
|
|
84eb84a080 | ||
|
|
60beea548b | ||
|
|
5f9c149e59 | ||
|
|
53367c6f04 | ||
|
|
d7f817ee44 | ||
|
|
d33a87da54 | ||
|
|
3aebfb12b7 | ||
|
|
1d6c55ffa6 | ||
|
|
5e7080aac3 | ||
|
|
fad739bc01 | ||
|
|
c6b7f23884 | ||
|
|
a6f7e446de | ||
|
|
89d95d3ae1 | ||
|
|
764208698f | ||
|
|
57129cf934 | ||
|
|
aae1a842d5 | ||
|
|
623f35aec7 | ||
|
|
870bf842cf | ||
|
|
07f2d7dd5c | ||
|
|
f223f2edc5 | ||
|
|
e848a9a577 | ||
|
|
7569d98e07 | ||
|
|
596dee2f24 | ||
|
|
8eb27b5875 | ||
|
|
d1457b312b | ||
|
|
c9dd2af196 | ||
|
|
827cfe4e8f |
@@ -211,6 +211,7 @@ def agent_outages_task() -> None:
|
|||||||
|
|
||||||
agents = Agent.objects.only(
|
agents = Agent.objects.only(
|
||||||
"pk",
|
"pk",
|
||||||
|
"agent_id",
|
||||||
"last_seen",
|
"last_seen",
|
||||||
"offline_time",
|
"offline_time",
|
||||||
"overdue_time",
|
"overdue_time",
|
||||||
|
|||||||
@@ -213,7 +213,8 @@ class TestAPIv3(TacticalTestCase):
|
|||||||
|
|
||||||
# setup data
|
# setup data
|
||||||
agent = baker.make_recipe("agents.agent")
|
agent = baker.make_recipe("agents.agent")
|
||||||
task = baker.make("autotasks.AutomatedTask", agent=agent)
|
script = baker.make_recipe("scripts.script")
|
||||||
|
task = baker.make("autotasks.AutomatedTask", agent=agent, script=script)
|
||||||
|
|
||||||
url = f"/api/v3/{task.pk}/{agent.agent_id}/taskrunner/" # type: ignore
|
url = f"/api/v3/{task.pk}/{agent.agent_id}/taskrunner/" # type: ignore
|
||||||
|
|
||||||
|
|||||||
@@ -321,11 +321,16 @@ class CheckRunner(APIView):
|
|||||||
|
|
||||||
def patch(self, request):
|
def patch(self, request):
|
||||||
check = get_object_or_404(Check, pk=request.data["id"])
|
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.last_run = djangotime.now()
|
||||||
check.save(update_fields=["last_run"])
|
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):
|
class CheckRunnerInterval(APIView):
|
||||||
@@ -378,9 +383,18 @@ class TaskRunner(APIView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# get last line of stdout
|
# 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.string_value = value
|
||||||
agent_field.save()
|
agent_field.save()
|
||||||
elif task.custom_field.type == "multiple":
|
elif task.custom_field.type == "multiple":
|
||||||
|
|||||||
@@ -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),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -104,6 +104,7 @@ class AutomatedTask(BaseAuditModel):
|
|||||||
task_type = models.CharField(
|
task_type = models.CharField(
|
||||||
max_length=100, choices=TASK_TYPE_CHOICES, default="manual"
|
max_length=100, choices=TASK_TYPE_CHOICES, default="manual"
|
||||||
)
|
)
|
||||||
|
collector_all_output = models.BooleanField(default=False)
|
||||||
run_time_date = DateTimeField(null=True, blank=True)
|
run_time_date = DateTimeField(null=True, blank=True)
|
||||||
remove_if_not_scheduled = models.BooleanField(default=False)
|
remove_if_not_scheduled = models.BooleanField(default=False)
|
||||||
run_asap_after_missed = models.BooleanField(default=False) # added in agent v1.4.7
|
run_asap_after_missed = models.BooleanField(default=False) # added in agent v1.4.7
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ class TaskRunnerGetSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class TaskGOGetSerializer(serializers.ModelSerializer):
|
class TaskGOGetSerializer(serializers.ModelSerializer):
|
||||||
script = ScriptCheckSerializer(read_only=True)
|
script = ScriptCheckSerializer(read_only=True)
|
||||||
|
script_args = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
def get_script_args(self, obj):
|
||||||
|
return Script.parse_script_args(
|
||||||
|
agent=obj.agent, shell=obj.script.shell, args=obj.script_args
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AutomatedTask
|
model = AutomatedTask
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import asyncio
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
@@ -14,9 +13,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from logs.models import BaseAuditModel
|
from logs.models import BaseAuditModel
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from packaging import version as pyver
|
|
||||||
|
|
||||||
from .utils import bytes2human
|
|
||||||
|
|
||||||
logger.configure(**settings.LOG_CONFIG)
|
logger.configure(**settings.LOG_CONFIG)
|
||||||
|
|
||||||
@@ -318,7 +315,7 @@ class Check(BaseAuditModel):
|
|||||||
def add_check_history(self, value: int, more_info: Any = None) -> None:
|
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_history=self, y=value, results=more_info)
|
||||||
|
|
||||||
def handle_checkv2(self, data):
|
def handle_check(self, data):
|
||||||
from alerts.models import Alert
|
from alerts.models import Alert
|
||||||
|
|
||||||
# cpuload or mem checks
|
# cpuload or mem checks
|
||||||
@@ -349,9 +346,6 @@ class Check(BaseAuditModel):
|
|||||||
elif self.check_type == "diskspace":
|
elif self.check_type == "diskspace":
|
||||||
if data["exists"]:
|
if data["exists"]:
|
||||||
percent_used = round(data["percent_used"])
|
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:
|
if self.error_threshold and (100 - percent_used) < self.error_threshold:
|
||||||
self.status = "failing"
|
self.status = "failing"
|
||||||
self.alert_severity = "error"
|
self.alert_severity = "error"
|
||||||
@@ -365,7 +359,7 @@ class Check(BaseAuditModel):
|
|||||||
else:
|
else:
|
||||||
self.status = "passing"
|
self.status = "passing"
|
||||||
|
|
||||||
self.more_info = f"Total: {total}B, Free: {free}B"
|
self.more_info = data["more_info"]
|
||||||
|
|
||||||
# add check history
|
# add check history
|
||||||
self.add_check_history(100 - percent_used)
|
self.add_check_history(100 - percent_used)
|
||||||
@@ -381,12 +375,7 @@ class Check(BaseAuditModel):
|
|||||||
self.stdout = data["stdout"]
|
self.stdout = data["stdout"]
|
||||||
self.stderr = data["stderr"]
|
self.stderr = data["stderr"]
|
||||||
self.retcode = data["retcode"]
|
self.retcode = data["retcode"]
|
||||||
try:
|
self.execution_time = "{:.4f}".format(data["runtime"])
|
||||||
# python agent
|
|
||||||
self.execution_time = "{:.4f}".format(data["stop"] - data["start"])
|
|
||||||
except:
|
|
||||||
# golang agent
|
|
||||||
self.execution_time = "{:.4f}".format(data["runtime"])
|
|
||||||
|
|
||||||
if data["retcode"] in self.info_return_codes:
|
if data["retcode"] in self.info_return_codes:
|
||||||
self.alert_severity = "info"
|
self.alert_severity = "info"
|
||||||
@@ -422,22 +411,8 @@ class Check(BaseAuditModel):
|
|||||||
|
|
||||||
# ping checks
|
# ping checks
|
||||||
elif self.check_type == "ping":
|
elif self.check_type == "ping":
|
||||||
output = data["output"]
|
self.status = data["status"]
|
||||||
|
self.more_info = 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.save(update_fields=["more_info"])
|
self.save(update_fields=["more_info"])
|
||||||
|
|
||||||
self.add_check_history(
|
self.add_check_history(
|
||||||
@@ -446,41 +421,8 @@ class Check(BaseAuditModel):
|
|||||||
|
|
||||||
# windows service checks
|
# windows service checks
|
||||||
elif self.check_type == "winsvc":
|
elif self.check_type == "winsvc":
|
||||||
svc_stat = data["status"]
|
self.status = data["status"]
|
||||||
self.more_info = f"Status {svc_stat.upper()}"
|
self.more_info = data["more_info"]
|
||||||
|
|
||||||
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.save(update_fields=["more_info"])
|
self.save(update_fields=["more_info"])
|
||||||
|
|
||||||
self.add_check_history(
|
self.add_check_history(
|
||||||
@@ -488,49 +430,7 @@ class Check(BaseAuditModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
elif self.check_type == "eventlog":
|
elif self.check_type == "eventlog":
|
||||||
log = []
|
log = data["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)
|
|
||||||
|
|
||||||
if self.fail_when == "contains":
|
if self.fail_when == "contains":
|
||||||
if log and len(log) >= self.number_of_events_b4_alert:
|
if log and len(log) >= self.number_of_events_b4_alert:
|
||||||
self.status = "failing"
|
self.status = "failing"
|
||||||
@@ -567,6 +467,11 @@ class Check(BaseAuditModel):
|
|||||||
|
|
||||||
return self.status
|
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
|
@staticmethod
|
||||||
def serialize(check):
|
def serialize(check):
|
||||||
# serializes the check and returns json
|
# serializes the check and returns json
|
||||||
|
|||||||
@@ -158,14 +158,8 @@ class AssignedTaskCheckRunnerField(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class CheckRunnerGetSerializer(serializers.ModelSerializer):
|
class CheckRunnerGetSerializer(serializers.ModelSerializer):
|
||||||
# only send data needed for agent to run a check
|
# only send data needed for agent to run a check
|
||||||
assigned_tasks = serializers.SerializerMethodField()
|
|
||||||
script = ScriptCheckSerializer(read_only=True)
|
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:
|
class Meta:
|
||||||
model = Check
|
model = Check
|
||||||
exclude = [
|
exclude = [
|
||||||
@@ -193,6 +187,7 @@ class CheckRunnerGetSerializer(serializers.ModelSerializer):
|
|||||||
"modified_by",
|
"modified_by",
|
||||||
"modified_time",
|
"modified_time",
|
||||||
"history",
|
"history",
|
||||||
|
"dashboard_alert",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.authenticate()
|
self.authenticate()
|
||||||
self.setup_coresettings()
|
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):
|
def test_prune_check_history(self):
|
||||||
from .tasks import prune_check_history
|
from .tasks import prune_check_history
|
||||||
@@ -526,6 +526,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
"percent_used": 85,
|
"percent_used": 85,
|
||||||
"total": 500,
|
"total": 500,
|
||||||
"free": 400,
|
"free": 400,
|
||||||
|
"more_info": "More info",
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = self.client.patch(url, data, format="json")
|
resp = self.client.patch(url, data, format="json")
|
||||||
@@ -543,6 +544,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
"percent_used": 95,
|
"percent_used": 95,
|
||||||
"total": 500,
|
"total": 500,
|
||||||
"free": 400,
|
"free": 400,
|
||||||
|
"more_info": "More info",
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = self.client.patch(url, data, format="json")
|
resp = self.client.patch(url, data, format="json")
|
||||||
@@ -573,6 +575,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
"percent_used": 95,
|
"percent_used": 95,
|
||||||
"total": 500,
|
"total": 500,
|
||||||
"free": 400,
|
"free": 400,
|
||||||
|
"more_info": "More info",
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = self.client.patch(url, data, format="json")
|
resp = self.client.patch(url, data, format="json")
|
||||||
@@ -592,6 +595,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
"percent_used": 95,
|
"percent_used": 95,
|
||||||
"total": 500,
|
"total": 500,
|
||||||
"free": 400,
|
"free": 400,
|
||||||
|
"more_info": "More info",
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = self.client.patch(url, data, format="json")
|
resp = self.client.patch(url, data, format="json")
|
||||||
@@ -608,6 +612,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
"percent_used": 50,
|
"percent_used": 50,
|
||||||
"total": 500,
|
"total": 500,
|
||||||
"free": 400,
|
"free": 400,
|
||||||
|
"more_info": "More info",
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = self.client.patch(url, data, format="json")
|
resp = self.client.patch(url, data, format="json")
|
||||||
@@ -791,12 +796,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# test failing info
|
# test failing info
|
||||||
data = {
|
data = {"id": ping.id, "status": "failing", "output": "reply from a.com"}
|
||||||
"id": ping.id,
|
|
||||||
"output": "Reply from 192.168.1.27: Destination host unreachable",
|
|
||||||
"has_stdout": True,
|
|
||||||
"has_stderr": False,
|
|
||||||
}
|
|
||||||
|
|
||||||
resp = self.client.patch(url, data, format="json")
|
resp = self.client.patch(url, data, format="json")
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
@@ -806,13 +806,6 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
self.assertEqual(new_check.alert_severity, "info")
|
self.assertEqual(new_check.alert_severity, "info")
|
||||||
|
|
||||||
# test failing warning
|
# 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.alert_severity = "warning"
|
||||||
ping.save()
|
ping.save()
|
||||||
|
|
||||||
@@ -824,13 +817,6 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
self.assertEqual(new_check.alert_severity, "warning")
|
self.assertEqual(new_check.alert_severity, "warning")
|
||||||
|
|
||||||
# test failing error
|
# 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.alert_severity = "error"
|
||||||
ping.save()
|
ping.save()
|
||||||
|
|
||||||
@@ -842,13 +828,6 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
self.assertEqual(new_check.alert_severity, "error")
|
self.assertEqual(new_check.alert_severity, "error")
|
||||||
|
|
||||||
# test failing 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")
|
resp = self.client.patch(url, data, format="json")
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
@@ -857,12 +836,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
self.assertEqual(new_check.alert_severity, "error")
|
self.assertEqual(new_check.alert_severity, "error")
|
||||||
|
|
||||||
# test passing
|
# test passing
|
||||||
data = {
|
data = {"id": ping.id, "status": "passing", "output": "reply from a.com"}
|
||||||
"id": ping.id,
|
|
||||||
"output": "Reply from 192.168.1.1: bytes=32 time<1ms TTL=64",
|
|
||||||
"has_stdout": True,
|
|
||||||
"has_stderr": False,
|
|
||||||
}
|
|
||||||
|
|
||||||
resp = self.client.patch(url, data, format="json")
|
resp = self.client.patch(url, data, format="json")
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
@@ -881,7 +855,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# test passing running
|
# 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")
|
resp = self.client.patch(url, data, format="json")
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
@@ -889,20 +863,8 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
new_check = Check.objects.get(pk=winsvc.id)
|
new_check = Check.objects.get(pk=winsvc.id)
|
||||||
self.assertEqual(new_check.status, "passing")
|
self.assertEqual(new_check.status, "passing")
|
||||||
|
|
||||||
# test passing start pending
|
# test failing
|
||||||
winsvc.pass_if_start_pending = True
|
data = {"id": winsvc.id, "status": "failing", "more_info": "ok"}
|
||||||
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"}
|
|
||||||
|
|
||||||
resp = self.client.patch(url, data, format="json")
|
resp = self.client.patch(url, data, format="json")
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
@@ -911,7 +873,7 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
self.assertEqual(new_check.status, "failing")
|
self.assertEqual(new_check.status, "failing")
|
||||||
self.assertEqual(new_check.alert_severity, "info")
|
self.assertEqual(new_check.alert_severity, "info")
|
||||||
|
|
||||||
# test failing and attempt start
|
""" # test failing and attempt start
|
||||||
winsvc.restart_if_stopped = True
|
winsvc.restart_if_stopped = True
|
||||||
winsvc.alert_severity = "warning"
|
winsvc.alert_severity = "warning"
|
||||||
winsvc.save()
|
winsvc.save()
|
||||||
@@ -976,9 +938,9 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
new_check = Check.objects.get(pk=winsvc.id)
|
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
|
from checks.models import Check
|
||||||
|
|
||||||
url = "/api/v3/checkrunner/"
|
url = "/api/v3/checkrunner/"
|
||||||
@@ -1180,4 +1142,4 @@ class TestCheckTasks(TacticalTestCase):
|
|||||||
|
|
||||||
new_check = Check.objects.get(pk=eventlog.id)
|
new_check = Check.objects.get(pk=eventlog.id)
|
||||||
|
|
||||||
self.assertEquals(new_check.status, "passing")
|
self.assertEquals(new_check.status, "passing") """
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
from agents.models import Agent
|
|
||||||
from logs.models import PendingAction
|
from logs.models import PendingAction
|
||||||
from scripts.models import Script
|
from scripts.models import Script
|
||||||
|
|
||||||
@@ -9,22 +8,6 @@ class Command(BaseCommand):
|
|||||||
help = "Collection of tasks to run after updating the rmm, after migrations"
|
help = "Collection of tasks to run after updating the rmm, after migrations"
|
||||||
|
|
||||||
def handle(self, *args, **kwargs):
|
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
|
# remove task pending actions. deprecated 4/20/2021
|
||||||
PendingAction.objects.filter(action_type="taskaction").delete()
|
PendingAction.objects.filter(action_type="taskaction").delete()
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ def dashboard_info(request):
|
|||||||
"client_tree_sort": request.user.client_tree_sort,
|
"client_tree_sort": request.user.client_tree_sort,
|
||||||
"client_tree_splitter": request.user.client_tree_splitter,
|
"client_tree_splitter": request.user.client_tree_splitter,
|
||||||
"loading_bar_color": request.user.loading_bar_color,
|
"loading_bar_color": request.user.loading_bar_color,
|
||||||
"no_code_sign": hasattr(settings, "NOCODESIGN") and settings.NOCODESIGN,
|
"hosted": hasattr(settings, "HOSTED") and settings.HOSTED,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
asgiref==3.3.4
|
asgiref==3.3.4
|
||||||
asyncio-nats-client==0.11.4
|
asyncio-nats-client==0.11.4
|
||||||
celery==5.0.5
|
celery==5.1.0
|
||||||
certifi==2020.12.5
|
certifi==2020.12.5
|
||||||
cffi==1.14.5
|
cffi==1.14.5
|
||||||
channels==3.0.3
|
channels==3.0.3
|
||||||
@@ -8,12 +8,11 @@ channels_redis==3.2.0
|
|||||||
chardet==4.0.0
|
chardet==4.0.0
|
||||||
cryptography==3.4.7
|
cryptography==3.4.7
|
||||||
daphne==3.0.2
|
daphne==3.0.2
|
||||||
Django==3.2.2
|
Django==3.2.3
|
||||||
django-cors-headers==3.7.0
|
django-cors-headers==3.7.0
|
||||||
django-rest-knox==4.1.0
|
django-rest-knox==4.1.0
|
||||||
djangorestframework==3.12.4
|
djangorestframework==3.12.4
|
||||||
future==0.18.2
|
future==0.18.2
|
||||||
kombu==5.0.2
|
|
||||||
loguru==0.5.3
|
loguru==0.5.3
|
||||||
msgpack==1.0.2
|
msgpack==1.0.2
|
||||||
packaging==20.9
|
packaging==20.9
|
||||||
@@ -26,10 +25,10 @@ pytz==2021.1
|
|||||||
qrcode==6.1
|
qrcode==6.1
|
||||||
redis==3.5.3
|
redis==3.5.3
|
||||||
requests==2.25.1
|
requests==2.25.1
|
||||||
six==1.15.0
|
six==1.16.0
|
||||||
sqlparse==0.4.1
|
sqlparse==0.4.1
|
||||||
twilio==6.57.0
|
twilio==6.59.0
|
||||||
urllib3==1.26.4
|
urllib3==1.26.5
|
||||||
uWSGI==2.0.19.1
|
uWSGI==2.0.19.1
|
||||||
validators==0.18.2
|
validators==0.18.2
|
||||||
vine==5.0.0
|
vine==5.0.0
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
"name": "Firefox - Clean Cache",
|
"name": "Firefox - Clean Cache",
|
||||||
"description": "This script will clean up Mozilla Firefox for all users.",
|
"description": "This script will clean up Mozilla Firefox for all users.",
|
||||||
"shell": "powershell",
|
"shell": "powershell",
|
||||||
"category": "TRMM (Win):Browsers"
|
"category": "TRMM (Win):Browsers",
|
||||||
|
"default_timeout": "300"
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"guid": "3ff6a386-11d1-4f9d-8cca-1b0563bb6443",
|
"guid": "3ff6a386-11d1-4f9d-8cca-1b0563bb6443",
|
||||||
@@ -15,7 +17,8 @@
|
|||||||
"name": "Chrome - Clear Cache for All Users",
|
"name": "Chrome - Clear Cache for All Users",
|
||||||
"description": "This script will clean up Google Chrome for all users.",
|
"description": "This script will clean up Google Chrome for all users.",
|
||||||
"shell": "powershell",
|
"shell": "powershell",
|
||||||
"category": "TRMM (Win):Browsers"
|
"category": "TRMM (Win):Browsers",
|
||||||
|
"default_timeout": "300"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"guid": "be1de837-f677-4ac5-aa0c-37a0fc9991fc",
|
"guid": "be1de837-f677-4ac5-aa0c-37a0fc9991fc",
|
||||||
@@ -24,7 +27,8 @@
|
|||||||
"name": "Adobe Reader DC - Install",
|
"name": "Adobe Reader DC - Install",
|
||||||
"description": "Installs Adobe Reader DC.",
|
"description": "Installs Adobe Reader DC.",
|
||||||
"shell": "powershell",
|
"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",
|
"guid": "2ee134d5-76aa-4160-b334-a1efbc62079f",
|
||||||
@@ -33,7 +37,8 @@
|
|||||||
"name": "Duplicati - Install",
|
"name": "Duplicati - Install",
|
||||||
"description": "This script installs Duplicati 2.0.5.1 as a service.",
|
"description": "This script installs Duplicati 2.0.5.1 as a service.",
|
||||||
"shell": "powershell",
|
"shell": "powershell",
|
||||||
"category": "TRMM (Win):3rd Party Software"
|
"category": "TRMM (Win):3rd Party Software",
|
||||||
|
"default_timeout": "300"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"guid": "81cc5bcb-01bf-4b0c-89b9-0ac0f3fe0c04",
|
"guid": "81cc5bcb-01bf-4b0c-89b9-0ac0f3fe0c04",
|
||||||
@@ -42,7 +47,8 @@
|
|||||||
"name": "Windows Update - Reset",
|
"name": "Windows Update - Reset",
|
||||||
"description": "This script will reset all of the Windows Updates components to DEFAULT SETTINGS.",
|
"description": "This script will reset all of the Windows Updates components to DEFAULT SETTINGS.",
|
||||||
"shell": "powershell",
|
"shell": "powershell",
|
||||||
"category": "TRMM (Win):Updates"
|
"category": "TRMM (Win):Updates",
|
||||||
|
"default_timeout": "300"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"guid": "8db87ff0-a9b4-4d9d-bc55-377bbcb85b6d",
|
"guid": "8db87ff0-a9b4-4d9d-bc55-377bbcb85b6d",
|
||||||
@@ -51,7 +57,8 @@
|
|||||||
"name": "Disk - Cleanup C: drive",
|
"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.",
|
"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",
|
"shell": "powershell",
|
||||||
"category": "TRMM (Win):Maintenance"
|
"category": "TRMM (Win):Maintenance",
|
||||||
|
"default_timeout": "25000"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"guid": "2f28e8c1-ae0f-4b46-a826-f513974526a3",
|
"guid": "2f28e8c1-ae0f-4b46-a826-f513974526a3",
|
||||||
@@ -78,7 +85,8 @@
|
|||||||
"name": "Speed Test - Python",
|
"name": "Speed Test - Python",
|
||||||
"description": "Runs a Speed Test using Python",
|
"description": "Runs a Speed Test using Python",
|
||||||
"shell": "python",
|
"shell": "python",
|
||||||
"category": "TRMM (Win):Network"
|
"category": "TRMM (Win):Network",
|
||||||
|
"default_timeout": "120"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"guid": "9d34f482-1f0c-4b2f-b65f-a9cf3c13ef5f",
|
"guid": "9d34f482-1f0c-4b2f-b65f-a9cf3c13ef5f",
|
||||||
@@ -161,6 +169,18 @@
|
|||||||
"shell": "powershell",
|
"shell": "powershell",
|
||||||
"category": "TRMM (Win):Collectors"
|
"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",
|
"guid": "95a2ee6f-b89b-4551-856e-3081b041caa7",
|
||||||
"filename": "Win_Power_Profile_Reset_High_Performance_to_Defaults.ps1",
|
"filename": "Win_Power_Profile_Reset_High_Performance_to_Defaults.ps1",
|
||||||
@@ -186,7 +206,8 @@
|
|||||||
"name": "Windows 10 Upgrade",
|
"name": "Windows 10 Upgrade",
|
||||||
"description": "Forces an upgrade to the latest release of Windows 10.",
|
"description": "Forces an upgrade to the latest release of Windows 10.",
|
||||||
"shell": "powershell",
|
"shell": "powershell",
|
||||||
"category": "TRMM (Win):Updates"
|
"category": "TRMM (Win):Updates",
|
||||||
|
"default_timeout": "25000"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"guid": "375323e5-cac6-4f35-a304-bb7cef35902d",
|
"guid": "375323e5-cac6-4f35-a304-bb7cef35902d",
|
||||||
@@ -222,7 +243,8 @@
|
|||||||
"name": "SSH - Install Feature and Enable",
|
"name": "SSH - Install Feature and Enable",
|
||||||
"description": "Installs and enabled OpenSSH Server Feature in Win10",
|
"description": "Installs and enabled OpenSSH Server Feature in Win10",
|
||||||
"shell": "powershell",
|
"shell": "powershell",
|
||||||
"category": "TRMM (Win):Windows Features"
|
"category": "TRMM (Win):Windows Features",
|
||||||
|
"default_timeout": "300"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"guid": "2435297a-6263-4e90-8688-1847400d0e22",
|
"guid": "2435297a-6263-4e90-8688-1847400d0e22",
|
||||||
@@ -339,7 +361,8 @@
|
|||||||
"name": "Update Installed Apps",
|
"name": "Update Installed Apps",
|
||||||
"description": "Update all apps that were installed using Chocolatey.",
|
"description": "Update all apps that were installed using Chocolatey.",
|
||||||
"shell": "cmd",
|
"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",
|
"guid": "fff8024d-d72e-4457-84fa-6c780f69a16f",
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ app.conf.beat_schedule = {
|
|||||||
},
|
},
|
||||||
"get-wmi": {
|
"get-wmi": {
|
||||||
"task": "agents.tasks.get_wmi_task",
|
"task": "agents.tasks.get_wmi_task",
|
||||||
"schedule": crontab(minute="*/18"),
|
"schedule": crontab(minute=18, hour="*/5"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,22 +15,22 @@ EXE_DIR = os.path.join(BASE_DIR, "tacticalrmm/private/exe")
|
|||||||
AUTH_USER_MODEL = "accounts.User"
|
AUTH_USER_MODEL = "accounts.User"
|
||||||
|
|
||||||
# latest release
|
# latest release
|
||||||
TRMM_VERSION = "0.6.10"
|
TRMM_VERSION = "0.6.13"
|
||||||
|
|
||||||
# bump this version everytime vue code is changed
|
# bump this version everytime vue code is changed
|
||||||
# to alert user they need to manually refresh their browser
|
# to alert user they need to manually refresh their browser
|
||||||
APP_VER = "0.0.136"
|
APP_VER = "0.0.137"
|
||||||
|
|
||||||
# https://github.com/wh1te909/rmmagent
|
# https://github.com/wh1te909/rmmagent
|
||||||
LATEST_AGENT_VER = "1.5.6"
|
LATEST_AGENT_VER = "1.5.7"
|
||||||
|
|
||||||
MESH_VER = "0.8.35"
|
MESH_VER = "0.8.49"
|
||||||
|
|
||||||
# for the update script, bump when need to recreate venv or npm install
|
# for the update script, bump when need to recreate venv or npm install
|
||||||
PIP_VER = "16"
|
PIP_VER = "17"
|
||||||
NPM_VER = "15"
|
NPM_VER = "16"
|
||||||
|
|
||||||
SETUPTOOLS_VER = "56.1.0"
|
SETUPTOOLS_VER = "57.0.0"
|
||||||
WHEEL_VER = "0.36.2"
|
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"
|
DL_64 = f"https://github.com/wh1te909/rmmagent/releases/download/v{LATEST_AGENT_VER}/winagent-v{LATEST_AGENT_VER}.exe"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM nats:2.2-alpine
|
FROM nats:2.2.6-alpine
|
||||||
|
|
||||||
ENV TACTICAL_DIR /opt/tactical
|
ENV TACTICAL_DIR /opt/tactical
|
||||||
ENV TACTICAL_READY_FILE ${TACTICAL_DIR}/tmp/tactical.ready
|
ENV TACTICAL_READY_FILE ${TACTICAL_DIR}/tmp/tactical.ready
|
||||||
|
|||||||
31
docs/docs/functions/examples.md
Normal file
31
docs/docs/functions/examples.md
Normal 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)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
3. Create URL Action (under `Settings | Global Settings | URL ACTIONS`) for Manufacturer websites
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
19
docs/docs/functions/settings_override.md
Normal file
19
docs/docs/functions/settings_override.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Settings Override
|
||||||
|
|
||||||
|
### Browser token expiration
|
||||||
|
|
||||||
|
The default browser token expiration is set to 5 hours. See this [ticket](https://github.com/wh1te909/tacticalrmm/issues/503) for reference.
|
||||||
|
|
||||||
|
To change it, add the following code block to the end of `/rmm/api/tacticalrmm/tacticalrmm/local_settings.py`
|
||||||
|
|
||||||
|
```python
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
REST_KNOX = {
|
||||||
|
"TOKEN_TTL": timedelta(days=30),
|
||||||
|
"AUTO_REFRESH": True,
|
||||||
|
"MIN_REFRESH_INTERVAL": 600,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Change `(days=30)` to whatever you prefer. Then run `sudo systemctl restart rmm` for changes to take effect.
|
||||||
BIN
docs/docs/images/example1_customfield.png
Normal file
BIN
docs/docs/images/example1_customfield.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/docs/images/example1_taskcollectorscript.png
Normal file
BIN
docs/docs/images/example1_taskcollectorscript.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/docs/images/example1_urlaction.png
Normal file
BIN
docs/docs/images/example1_urlaction.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -14,6 +14,10 @@
|
|||||||
|
|
||||||
## Install
|
## 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
|
#### Run updates and setup the linux user
|
||||||
SSH into the server as **root**.<br/><br/>
|
SSH into the server as **root**.<br/><br/>
|
||||||
Download and run the prereqs and latest updates<br/>
|
Download and run the prereqs and latest updates<br/>
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ nav:
|
|||||||
- "Alerting": functions/alerting.md
|
- "Alerting": functions/alerting.md
|
||||||
- "User Interface Preferences": functions/user_ui.md
|
- "User Interface Preferences": functions/user_ui.md
|
||||||
- "Django Admin": functions/django_admin.md
|
- "Django Admin": functions/django_admin.md
|
||||||
|
- "Settings Override": functions/settings_override.md
|
||||||
|
- "Examples": functions/examples.md
|
||||||
- Backup: backup.md
|
- Backup: backup.md
|
||||||
- Restore: restore.md
|
- Restore: restore.md
|
||||||
- Troubleshooting: troubleshooting.md
|
- Troubleshooting: troubleshooting.md
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -5,6 +5,6 @@ go 1.16
|
|||||||
require (
|
require (
|
||||||
github.com/nats-io/nats-server/v2 v2.1.8-0.20201129161730-ebe63db3e3ed // indirect
|
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/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
|
golang.org/x/sys v0.0.0-20210122235752-a8b976e07c7b // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -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/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 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
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.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
|
||||||
github.com/ugorji/go v1.2.5/go.mod h1:gat2tIT8KJG8TVI8yv77nEO/KYT6dV7JE1gfUa8Xuls=
|
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||||
github.com/ugorji/go/codec v1.2.5 h1:8WobZKAk18Msm2CothY2jnztY56YVY8kF1oQrj21iis=
|
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
||||||
github.com/ugorji/go/codec v1.2.5/go.mod h1:QPxoTbPKSEAlAHPYt02++xp/en9B/wUdwFCz+hj5caA=
|
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-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-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
SCRIPT_VERSION="48"
|
SCRIPT_VERSION="49"
|
||||||
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/install.sh'
|
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/install.sh'
|
||||||
|
|
||||||
sudo apt install -y curl wget dirmngr gnupg lsb-release
|
sudo apt install -y curl wget dirmngr gnupg lsb-release
|
||||||
@@ -167,11 +167,11 @@ sudo chmod 775 -R /etc/letsencrypt
|
|||||||
print_green 'Downloading NATS'
|
print_green 'Downloading NATS'
|
||||||
|
|
||||||
nats_tmp=$(mktemp -d -t nats-XXXXXXXXXX)
|
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 chmod +x /usr/local/bin/nats-server
|
||||||
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
|
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
|
||||||
rm -rf ${nats_tmp}
|
rm -rf ${nats_tmp}
|
||||||
|
|||||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
SCRIPT_VERSION="26"
|
SCRIPT_VERSION="27"
|
||||||
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/restore.sh'
|
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/restore.sh'
|
||||||
|
|
||||||
sudo apt update
|
sudo apt update
|
||||||
@@ -108,11 +108,11 @@ sudo apt update
|
|||||||
print_green 'Downloading NATS'
|
print_green 'Downloading NATS'
|
||||||
|
|
||||||
nats_tmp=$(mktemp -d -t nats-XXXXXXXXXX)
|
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 chmod +x /usr/local/bin/nats-server
|
||||||
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
|
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
|
||||||
rm -rf ${nats_tmp}
|
rm -rf ${nats_tmp}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
cup -y all
|
cup all -y
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ else {
|
|||||||
Install-Module -Name RunAsUser -Force
|
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
|
Set-Content -Path c:\windows\temp\message.txt -Value $args
|
||||||
|
|
||||||
Invoke-AsCurrentUser -scriptblock {
|
Invoke-AsCurrentUser -scriptblock {
|
||||||
@@ -55,5 +56,5 @@ Invoke-AsCurrentUser -scriptblock {
|
|||||||
Submit-BTNotification -Content $Content
|
Submit-BTNotification -Content $Content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Cleanup temp file for message variables
|
||||||
Remove-Item -Path c:\windows\temp\message.txt
|
Remove-Item -Path c:\windows\temp\message.txt
|
||||||
|
|||||||
@@ -10,28 +10,6 @@
|
|||||||
Submitted by: https://github.com/dinger1986
|
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) {
|
if (Get-PackageProvider -Name NuGet) {
|
||||||
Write-Output "NuGet Already Added"
|
Write-Output "NuGet Already Added"
|
||||||
}
|
}
|
||||||
@@ -48,14 +26,30 @@ else {
|
|||||||
Install-Module -Name RunAsUser -Force
|
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 {
|
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"
|
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
|
Set-ExecutionPolicy -ExecutionPolicy $curpsxpol
|
||||||
|
|
||||||
del "%ProgramData%\Tactical RMM\temp\curpsxpolicy.txt"
|
|
||||||
26
scripts/Win_Screenconnect_GetGUID.ps1
Normal file
26
scripts/Win_Screenconnect_GetGUID.ps1
Normal 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
|
||||||
18
scripts_wip/Win_Print_Spooler_Reset.bat
Normal file
18
scripts_wip/Win_Print_Spooler_Reset.bat
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
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"
|
||||||
|
|
||||||
|
REM Kill service if its not stopping
|
||||||
|
tasklist | find /i "spoolsv.exe" && taskkill /im spoolsv.exe /F && net stop "Spooler"
|
||||||
|
|
||||||
|
REM Set Permissions on spool folders
|
||||||
|
icacls %systemroot%\System32\spool\PRINTERS /grant system:f /inheritance:e
|
||||||
|
icacls %systemroot%\System32\spool\SERVERS /grant system:f /inheritance:e
|
||||||
|
|
||||||
|
REM Clear files in print queue
|
||||||
|
del /F /Q %systemroot%\System32\spool\PRINTERS\*.*
|
||||||
|
del /F /Q %systemroot%\System32\spool\SERVERS\*.*
|
||||||
|
|
||||||
|
REM Start Print Spooler again
|
||||||
|
net start "Spooler"
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
net stop "Print Spooler"
|
|
||||||
net start "Print Spooler"
|
|
||||||
25
scripts_wip/Win_Print_Spooler_Restart_Service.ps1
Normal file
25
scripts_wip/Win_Print_Spooler_Restart_Service.ps1
Normal 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()
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#Update with command parameters
|
|
||||||
|
|
||||||
$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()
|
|
||||||
}
|
|
||||||
18
scripts_wip/Win_Shortcut_Creator.ps1
Normal file
18
scripts_wip/Win_Shortcut_Creator.ps1
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
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\Shortcut.url"
|
||||||
|
$targetpath = "https://yourwebsite.com"
|
||||||
|
$iconlocation = "c:\agent\yourico.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"
|
||||||
|
|
||||||
|
# This will create and agent directory then download the ico file
|
||||||
|
# change ico file and location to download
|
||||||
14
scripts_wip/Win_Shortcut_Creator2.ps1
Normal file
14
scripts_wip/Win_Shortcut_Creator2.ps1
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
param (
|
||||||
|
[string] $name,
|
||||||
|
[string] $url
|
||||||
|
)
|
||||||
|
|
||||||
|
$url = $url
|
||||||
|
$name = $name
|
||||||
|
$Shell = New-Object -ComObject ("WScript.Shell")
|
||||||
|
$ShortCut = $Shell.CreateShortcut("$env:Public\Desktop\$name.url")
|
||||||
|
$ShortCut.TargetPath="$url"
|
||||||
|
$ShortCut.Save()
|
||||||
|
|
||||||
|
|
||||||
|
# arguements: -name {{shortcut name}} -url {{url}}
|
||||||
12
update.sh
12
update.sh
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
SCRIPT_VERSION="121"
|
SCRIPT_VERSION="122"
|
||||||
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/update.sh'
|
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'
|
LATEST_SETTINGS_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/api/tacticalrmm/tacticalrmm/settings.py'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
@@ -184,14 +184,14 @@ if ! [[ $HAS_PY39 ]]; then
|
|||||||
sudo rm -rf Python-3.9.2 Python-3.9.2.tgz
|
sudo rm -rf Python-3.9.2 Python-3.9.2.tgz
|
||||||
fi
|
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
|
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)
|
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 rm -f /usr/local/bin/nats-server
|
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 chmod +x /usr/local/bin/nats-server
|
||||||
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
|
sudo chown ${USER}:${USER} /usr/local/bin/nats-server
|
||||||
rm -rf ${nats_tmp}
|
rm -rf ${nats_tmp}
|
||||||
|
|||||||
1946
web/package-lock.json
generated
1946
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,33 +10,27 @@
|
|||||||
"test:e2e:ci": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\""
|
"test:e2e:ci": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.10.4",
|
"@quasar/extras": "^1.10.5",
|
||||||
"apexcharts": "^3.23.1",
|
"apexcharts": "^3.23.1",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"prismjs": "^1.22.0",
|
"prismjs": "^1.22.0",
|
||||||
"qrcode.vue": "^1.7.0",
|
"qrcode.vue": "^1.7.0",
|
||||||
"quasar": "^1.15.13",
|
"quasar": "^1.15.18",
|
||||||
"vue-apexcharts": "^1.6.0",
|
"vue-apexcharts": "^1.6.0",
|
||||||
"vue-prism-editor": "^1.2.2"
|
"vue-prism-editor": "^1.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@quasar/app": "^2.2.6",
|
"@quasar/app": "^2.2.7",
|
||||||
"@quasar/cli": "^1.1.3",
|
"@quasar/cli": "^1.2.0",
|
||||||
"core-js": "^3.11.2",
|
"core-js": "^3.13.0",
|
||||||
"eslint-plugin-cypress": "^2.11.2",
|
"eslint-plugin-cypress": "^2.11.2",
|
||||||
"flush-promises": "^1.0.2",
|
"flush-promises": "^1.0.2",
|
||||||
"fs-extra": "^9.1.0"
|
"fs-extra": "^9.1.0"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 4 Chrome versions",
|
"last 3 Chrome versions",
|
||||||
"last 4 Firefox versions",
|
"last 3 Firefox versions",
|
||||||
"last 2 Edge 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"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -261,6 +261,9 @@
|
|||||||
@click="eventLogMoreInfo(props.row)"
|
@click="eventLogMoreInfo(props.row)"
|
||||||
>Last Output</span
|
>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>
|
||||||
<q-td>{{ props.row.last_run || "Never" }}</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"
|
<q-td v-if="props.row.assigned_task !== null && props.row.assigned_task.length > 1"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
@input="value => $emit('input', value)"
|
@input="value => $emit('input', value)"
|
||||||
:rules="[...validationRules]"
|
:rules="[...validationRules]"
|
||||||
reactive-rules
|
reactive-rules
|
||||||
|
autogrow
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-toggle
|
<q-toggle
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
<q-item-section>Global Settings</q-item-section>
|
<q-item-section>Global Settings</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<!-- code sign -->
|
<!-- 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-section>Code Signing</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
</q-menu>
|
</q-menu>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<!-- help -->
|
<!-- 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-menu auto-close>
|
||||||
<q-list dense style="min-width: 100px">
|
<q-list dense style="min-width: 100px">
|
||||||
<q-item clickable v-close-popup @click="openHelp('docs')">
|
<q-item clickable v-close-popup @click="openHelp('docs')">
|
||||||
@@ -272,8 +272,8 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
noCodeSigning() {
|
hosted() {
|
||||||
return this.$store.state.noCodeSign;
|
return this.$store.state.hosted;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export default {
|
|||||||
getOptions() {
|
getOptions() {
|
||||||
this.getClients();
|
this.getClients();
|
||||||
this.getSites();
|
this.getSites();
|
||||||
this.agentOptions = Object.freeze(this.getAgentOptions());
|
this.agentOptions = this.getAgentOptions();
|
||||||
},
|
},
|
||||||
show() {
|
show() {
|
||||||
this.$refs.dialog.show();
|
this.$refs.dialog.show();
|
||||||
@@ -152,7 +152,7 @@ export default {
|
|||||||
this.hide();
|
this.hide();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
created() {
|
||||||
this.getOptions();
|
this.getOptions();
|
||||||
|
|
||||||
// copy prop data locally
|
// copy prop data locally
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export default {
|
|||||||
getOptions() {
|
getOptions() {
|
||||||
this.getClients();
|
this.getClients();
|
||||||
this.getSites();
|
this.getSites();
|
||||||
this.agentOptions = Object.freeze(this.getAgentOptions());
|
this.agentOptions = this.getAgentOptions();
|
||||||
},
|
},
|
||||||
show() {
|
show() {
|
||||||
this.$refs.dialog.show();
|
this.$refs.dialog.show();
|
||||||
@@ -159,7 +159,7 @@ export default {
|
|||||||
this.hide();
|
this.hide();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
created() {
|
||||||
this.getOptions();
|
this.getOptions();
|
||||||
|
|
||||||
// copy prop data locally
|
// copy prop data locally
|
||||||
|
|||||||
@@ -111,6 +111,7 @@
|
|||||||
dense
|
dense
|
||||||
options-dense
|
options-dense
|
||||||
outlined
|
outlined
|
||||||
|
clearable
|
||||||
v-model="template.action"
|
v-model="template.action"
|
||||||
:options="scriptOptions"
|
:options="scriptOptions"
|
||||||
map-options
|
map-options
|
||||||
@@ -174,6 +175,7 @@
|
|||||||
dense
|
dense
|
||||||
options-dense
|
options-dense
|
||||||
outlined
|
outlined
|
||||||
|
clearable
|
||||||
v-model="template.resolved_action"
|
v-model="template.resolved_action"
|
||||||
:options="scriptOptions"
|
:options="scriptOptions"
|
||||||
map-options
|
map-options
|
||||||
|
|||||||
@@ -138,6 +138,7 @@
|
|||||||
v-model="localField.default_value_string"
|
v-model="localField.default_value_string"
|
||||||
:rules="[...defaultValueRules]"
|
:rules="[...defaultValueRules]"
|
||||||
reactive-rules
|
reactive-rules
|
||||||
|
autogrow
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
|
|||||||
@@ -73,7 +73,12 @@
|
|||||||
label="Collector Task"
|
label="Collector Task"
|
||||||
v-model="collector"
|
v-model="collector"
|
||||||
class="q-pb-sm"
|
class="q-pb-sm"
|
||||||
@input="autotask.custom_field = null"
|
@input="
|
||||||
|
() => {
|
||||||
|
autotask.custom_field = null;
|
||||||
|
autotask.collector_all_ouput = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<q-select
|
<q-select
|
||||||
v-if="collector"
|
v-if="collector"
|
||||||
@@ -87,6 +92,13 @@
|
|||||||
options-dense
|
options-dense
|
||||||
hint="The last line of script output will be saved to custom field selected"
|
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-card-section>
|
<q-card-section>
|
||||||
<q-select
|
<q-select
|
||||||
@@ -229,6 +241,7 @@ export default {
|
|||||||
task_type: "scheduled",
|
task_type: "scheduled",
|
||||||
timeout: 120,
|
timeout: 120,
|
||||||
alert_severity: "info",
|
alert_severity: "info",
|
||||||
|
collector_all_output: false,
|
||||||
},
|
},
|
||||||
policyChecks: [],
|
policyChecks: [],
|
||||||
severityOptions: [
|
severityOptions: [
|
||||||
|
|||||||
@@ -90,6 +90,13 @@
|
|||||||
options-dense
|
options-dense
|
||||||
hint="The return value of script will be saved to custom field selected"
|
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-card-section>
|
<q-card-section>
|
||||||
<q-input
|
<q-input
|
||||||
@@ -131,6 +138,7 @@ export default {
|
|||||||
alert_severity: null,
|
alert_severity: null,
|
||||||
timeout: 120,
|
timeout: 120,
|
||||||
custom_field: null,
|
custom_field: null,
|
||||||
|
collector_all_output: false,
|
||||||
},
|
},
|
||||||
collector: false,
|
collector: false,
|
||||||
customFieldOptions: [],
|
customFieldOptions: [],
|
||||||
@@ -197,6 +205,7 @@ export default {
|
|||||||
this.autotask.alert_severity = this.task.alert_severity;
|
this.autotask.alert_severity = this.task.alert_severity;
|
||||||
this.autotask.timeout = this.task.timeout;
|
this.autotask.timeout = this.task.timeout;
|
||||||
this.autotask.custom_field = this.task.custom_field;
|
this.autotask.custom_field = this.task.custom_field;
|
||||||
|
this.autotask.collector_all_output = this.task.collector_all_output;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -72,18 +72,18 @@ export default {
|
|||||||
|
|
||||||
isValidThreshold(warning, error, diskcheck = false) {
|
isValidThreshold(warning, error, diskcheck = false) {
|
||||||
if (warning === 0 && error === 0) {
|
if (warning === 0 && error === 0) {
|
||||||
Notify.create(notifyErrorConfig("Warning Threshold or Error Threshold need to be set", 2000));
|
Notify.create({ type: "negative", timeout: 2000, message: "Warning Threshold or Error Threshold need to be set" });
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!diskcheck && warning > error && warning > 0 && error > 0) {
|
if (!diskcheck && warning > error && warning > 0 && error > 0) {
|
||||||
Notify.create(notifyErrorConfig("Warning Threshold must be less than Error Threshold", 2000));
|
Notify.create({ type: "negative", timeout: 2000, message: "Warning Threshold must be less than Error Threshold" });
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diskcheck && warning < error && warning > 0 && error > 0) {
|
if (diskcheck && warning < error && warning > 0 && error > 0) {
|
||||||
Notify.create(notifyErrorConfig("Warning Threshold must be more than Error Threshold", 2000));
|
Notify.create({ type: "negative", timeout: 2000, message: "Warning Threshold must be more than Error Threshold" });
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export default function () {
|
|||||||
defaultAgentTblTab: "server",
|
defaultAgentTblTab: "server",
|
||||||
clientTreeSort: "alphafail",
|
clientTreeSort: "alphafail",
|
||||||
clientTreeSplitter: 11,
|
clientTreeSplitter: 11,
|
||||||
noCodeSign: false,
|
hosted: false,
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
clientTreeSplitterModel(state) {
|
clientTreeSplitterModel(state) {
|
||||||
@@ -159,8 +159,8 @@ export default function () {
|
|||||||
SET_CLIENT_TREE_SORT(state, val) {
|
SET_CLIENT_TREE_SORT(state, val) {
|
||||||
state.clientTreeSort = val
|
state.clientTreeSort = val
|
||||||
},
|
},
|
||||||
SET_NO_CODE_SIGN(state, val) {
|
SET_HOSTED(state, val) {
|
||||||
state.noCodeSign = val
|
state.hosted = val
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -742,7 +742,7 @@ export default {
|
|||||||
this.$store.commit("SET_AGENT_DBLCLICK_ACTION", r.data.dbl_click_action);
|
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("SET_URL_ACTION", r.data.url_action);
|
||||||
this.$store.commit("setShowCommunityScripts", r.data.show_community_scripts);
|
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) {
|
showToggleMaintenance(node) {
|
||||||
|
|||||||
Reference in New Issue
Block a user