Skip to content

Commit

Permalink
Release 0.4.3
Browse files Browse the repository at this point in the history
  • Loading branch information
wh1te909 committed Jan 30, 2021
2 parents b5c28de + af9cb65 commit 01ee524
Show file tree
Hide file tree
Showing 22 changed files with 244 additions and 128 deletions.
14 changes: 5 additions & 9 deletions api/tacticalrmm/accounts/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,15 +278,11 @@ def test_user_ui(self):
r = self.client.patch(url, data, format="json")
self.assertEqual(r.status_code, 200)

data = {"agent_dblclick_action": "editagent"}
r = self.client.patch(url, data, format="json")
self.assertEqual(r.status_code, 200)

data = {"agent_dblclick_action": "remotebg"}
r = self.client.patch(url, data, format="json")
self.assertEqual(r.status_code, 200)

data = {"agent_dblclick_action": "takecontrol"}
data = {
"userui": True,
"agent_dblclick_action": "editagent",
"default_agent_tbl_tab": "mixed",
}
r = self.client.patch(url, data, format="json")
self.assertEqual(r.status_code, 200)

Expand Down
78 changes: 0 additions & 78 deletions api/tacticalrmm/agents/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,47 +16,6 @@
logger.configure(**settings.LOG_CONFIG)


def _check_agent_service(pk: int) -> None:
agent = Agent.objects.get(pk=pk)
r = asyncio.run(agent.nats_cmd({"func": "ping"}, timeout=2))
# if the agent is respoding to pong from the rpc service but is not showing as online (handled by tacticalagent service)
# then tacticalagent service is hung. forcefully restart it
if r == "pong":
logger.info(
f"Detected crashed tacticalagent service on {agent.hostname} v{agent.version}, attempting recovery"
)
data = {"func": "recover", "payload": {"mode": "tacagent"}}
asyncio.run(agent.nats_cmd(data, wait=False))


def _check_in_full(pk: int) -> None:
agent = Agent.objects.get(pk=pk)
asyncio.run(agent.nats_cmd({"func": "checkinfull"}, wait=False))


@app.task
def check_in_task() -> None:
q = Agent.objects.only("pk", "version")
agents: List[int] = [
i.pk for i in q if pyver.parse(i.version) == pyver.parse("1.1.12")
]
chunks = (agents[i : i + 50] for i in range(0, len(agents), 50))
for chunk in chunks:
for pk in chunk:
_check_in_full(pk)
sleep(0.1)
rand = random.randint(3, 7)
sleep(rand)


@app.task
def monitor_agents_task() -> None:
q = Agent.objects.only("pk", "version", "last_seen", "overdue_time")
agents: List[int] = [i.pk for i in q if i.has_nats and i.status != "online"]
for agent in agents:
_check_agent_service(agent)


def agent_update(pk: int) -> str:
agent = Agent.objects.get(pk=pk)
# skip if we can't determine the arch
Expand Down Expand Up @@ -154,43 +113,6 @@ def auto_self_agent_update_task() -> None:
sleep(4)


@app.task
def get_wmi_task():
agents = Agent.objects.only("pk", "version", "last_seen", "overdue_time")
online = [
i
for i in agents
if pyver.parse(i.version) >= pyver.parse("1.2.0") and i.status == "online"
]
chunks = (online[i : i + 50] for i in range(0, len(online), 50))
for chunk in chunks:
for agent in chunk:
asyncio.run(agent.nats_cmd({"func": "wmi"}, wait=False))
sleep(0.1)
rand = random.randint(3, 7)
sleep(rand)


@app.task
def sync_sysinfo_task():
agents = Agent.objects.only("pk", "version", "last_seen", "overdue_time")
online = [
i
for i in agents
if pyver.parse(i.version) >= pyver.parse("1.1.3")
and pyver.parse(i.version) <= pyver.parse("1.1.12")
and i.status == "online"
]

chunks = (online[i : i + 50] for i in range(0, len(online), 50))
for chunk in chunks:
for agent in chunk:
asyncio.run(agent.nats_cmd({"func": "sync"}, wait=False))
sleep(0.1)
rand = random.randint(3, 7)
sleep(rand)


@app.task
def agent_outage_email_task(pk):
sleep(random.randint(1, 15))
Expand Down
34 changes: 30 additions & 4 deletions api/tacticalrmm/agents/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,18 +162,44 @@ def test_kill_proc(self, nats_cmd):
self.check_not_authenticated("get", url)

@patch("agents.models.Agent.nats_cmd")
def test_get_event_log(self, mock_ret):
url = f"/agents/{self.agent.pk}/geteventlog/Application/30/"
def test_get_event_log(self, nats_cmd):
url = f"/agents/{self.agent.pk}/geteventlog/Application/22/"

with open(
os.path.join(settings.BASE_DIR, "tacticalrmm/test_data/appeventlog.json")
) as f:
mock_ret.return_value = json.load(f)
nats_cmd.return_value = json.load(f)

r = self.client.get(url)
self.assertEqual(r.status_code, 200)
nats_cmd.assert_called_with(
{
"func": "eventlog",
"timeout": 30,
"payload": {
"logname": "Application",
"days": str(22),
},
},
timeout=32,
)

mock_ret.return_value = "timeout"
url = f"/agents/{self.agent.pk}/geteventlog/Security/6/"
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
nats_cmd.assert_called_with(
{
"func": "eventlog",
"timeout": 180,
"payload": {
"logname": "Security",
"days": str(6),
},
},
timeout=182,
)

nats_cmd.return_value = "timeout"
r = self.client.get(url)
self.assertEqual(r.status_code, 400)

Expand Down
5 changes: 3 additions & 2 deletions api/tacticalrmm/agents/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,16 @@ def get_event_log(request, pk, logtype, days):
agent = get_object_or_404(Agent, pk=pk)
if not agent.has_nats:
return notify_error("Requires agent version 1.1.0 or greater")
timeout = 180 if logtype == "Security" else 30
data = {
"func": "eventlog",
"timeout": 30,
"timeout": timeout,
"payload": {
"logname": logtype,
"days": str(days),
},
}
r = asyncio.run(agent.nats_cmd(data, timeout=32))
r = asyncio.run(agent.nats_cmd(data, timeout=timeout + 2))
if r == "timeout":
return notify_error("Unable to contact the agent")

Expand Down
23 changes: 23 additions & 0 deletions api/tacticalrmm/natsapi/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from model_bakery import baker
from tacticalrmm.test import TacticalTestCase
from django.conf import settings


class TestNatsAPIViews(TacticalTestCase):
def setUp(self):
self.authenticate()
self.setup_coresettings()

def test_nats_wmi(self):
url = "/natsapi/wmi/"
baker.make_recipe("agents.online_agent", version="1.2.0", _quantity=14)
baker.make_recipe(
"agents.online_agent", version=settings.LATEST_AGENT_VER, _quantity=3
)
baker.make_recipe(
"agents.overdue_agent", version=settings.LATEST_AGENT_VER, _quantity=5
)
baker.make_recipe("agents.online_agent", version="1.1.12", _quantity=7)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertEqual(len(r.json()["agent_ids"]), 17)
3 changes: 3 additions & 0 deletions api/tacticalrmm/natsapi/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
path("syncmesh/", views.SyncMeshNodeID.as_view()),
path("winupdates/", views.NatsWinUpdates.as_view()),
path("choco/", views.NatsChoco.as_view()),
path("wmi/", views.NatsWMI.as_view()),
path("offline/", views.OfflineAgents.as_view()),
path("logcrash/", views.LogCrash.as_view()),
]
47 changes: 47 additions & 0 deletions api/tacticalrmm/natsapi/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import time
from django.utils import timezone as djangotime
from loguru import logger
from packaging import version as pyver
from typing import List

from rest_framework.response import Response
from rest_framework.views import APIView
Expand Down Expand Up @@ -237,3 +239,48 @@ def post(self, request):

agent.delete_superseded_updates()
return Response("ok")


class NatsWMI(APIView):

authentication_classes = []
permission_classes = []

def get(self, request):
agents = Agent.objects.only(
"pk", "agent_id", "version", "last_seen", "overdue_time"
)
online: List[str] = [
i.agent_id
for i in agents
if pyver.parse(i.version) >= pyver.parse("1.2.0") and i.status == "online"
]
return Response({"agent_ids": online})


class OfflineAgents(APIView):
authentication_classes = []
permission_classes = []

def get(self, request):
agents = Agent.objects.only(
"pk", "agent_id", "version", "last_seen", "overdue_time"
)
offline: List[str] = [
i.agent_id for i in agents if i.has_nats and i.status != "online"
]
return Response({"agent_ids": offline})


class LogCrash(APIView):
authentication_classes = []
permission_classes = []

def post(self, request):
agent = get_object_or_404(Agent, agent_id=request.data["agentid"])
logger.info(
f"Detected crashed tacticalagent service on {agent.hostname} v{agent.version}, attempting recovery"
)
agent.last_seen = djangotime.now()
agent.save(update_fields=["last_seen"])
return Response("ok")
10 changes: 5 additions & 5 deletions api/tacticalrmm/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
amqp==5.0.2
amqp==5.0.5
asgiref==3.3.1
asyncio-nats-client==0.11.4
billiard==3.6.3.0
Expand All @@ -9,7 +9,7 @@ chardet==4.0.0
cryptography==3.3.1
decorator==4.4.2
Django==3.1.5
django-cors-headers==3.6.0
django-cors-headers==3.7.0
django-rest-knox==4.1.0
djangorestframework==3.12.2
future==0.18.2
Expand All @@ -21,16 +21,16 @@ packaging==20.8
psycopg2-binary==2.8.6
pycparser==2.20
pycryptodome==3.9.9
pyotp==2.4.1
pyotp==2.5.0
pyparsing==2.4.7
pytz==2020.5
qrcode==6.1
redis==3.5.3
requests==2.25.1
six==1.15.0
sqlparse==0.4.1
twilio==6.51.0
urllib3==1.26.2
twilio==6.51.1
urllib3==1.26.3
uWSGI==2.0.19.1
validators==0.18.2
vine==5.0.0
Expand Down
2 changes: 1 addition & 1 deletion api/tacticalrmm/scripts/community_scripts.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,4 @@
"description": "Windows Defender Exclusions for Tactical RMM",
"shell": "powershell"
}
]
]
12 changes: 9 additions & 3 deletions api/tacticalrmm/scripts/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,21 @@ def test_community_script_json_file(self):
info = json.load(f)

for script in info:
self.assertTrue(
os.path.exists(os.path.join(scripts_dir, script["filename"]))
)
fn: str = script["filename"]
self.assertTrue(os.path.exists(os.path.join(scripts_dir, fn)))
self.assertTrue(script["filename"])
self.assertTrue(script["name"])
self.assertTrue(script["description"])
self.assertTrue(script["shell"])
self.assertIn(script["shell"], valid_shells)

if fn.endswith(".ps1"):
self.assertEqual(script["shell"], "powershell")
elif fn.endswith(".bat"):
self.assertEqual(script["shell"], "cmd")
elif fn.endswith(".py"):
self.assertEqual(script["shell"], "python")

def test_load_community_scripts(self):
with open(
os.path.join(settings.BASE_DIR, "scripts/community_scripts.json")
Expand Down
16 changes: 0 additions & 16 deletions api/tacticalrmm/tacticalrmm/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,10 @@
"task": "winupdate.tasks.check_agent_update_schedule_task",
"schedule": crontab(minute=5, hour="*"),
},
"agents-checkinfull": {
"task": "agents.tasks.check_in_task",
"schedule": crontab(minute="*/24"),
},
"agent-auto-update": {
"task": "agents.tasks.auto_self_agent_update_task",
"schedule": crontab(minute=35, hour="*"),
},
"agents-sync": {
"task": "agents.tasks.sync_sysinfo_task",
"schedule": crontab(minute=55, hour="*"),
},
"get-wmi": {
"task": "agents.tasks.get_wmi_task",
"schedule": crontab(minute="*/18"),
},
"check-agentservice": {
"task": "agents.tasks.monitor_agents_task",
"schedule": crontab(minute="*/15"),
},
"remove-salt": {
"task": "agents.tasks.remove_salt_task",
"schedule": crontab(minute=14, hour="*/2"),
Expand Down
4 changes: 2 additions & 2 deletions api/tacticalrmm/tacticalrmm/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
AUTH_USER_MODEL = "accounts.User"

# latest release
TRMM_VERSION = "0.4.2"
TRMM_VERSION = "0.4.3"

# bump this version everytime vue code is changed
# to alert user they need to manually refresh their browser
Expand All @@ -27,7 +27,7 @@
MESH_VER = "0.7.54"

# for the update script, bump when need to recreate venv or npm install
PIP_VER = "7"
PIP_VER = "8"
NPM_VER = "7"

DL_64 = f"https://github.com/wh1te909/rmmagent/releases/download/v{LATEST_AGENT_VER}/winagent-v{LATEST_AGENT_VER}.exe"
Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
source env/bin/activate
cd /myagent/_work/1/s/api/tacticalrmm
pip install --no-cache-dir --upgrade pip
pip install --no-cache-dir setuptools==51.1.2 wheel==0.36.2
pip install --no-cache-dir setuptools==52.0.0 wheel==0.36.2
pip install --no-cache-dir -r requirements.txt -r requirements-test.txt -r requirements-dev.txt
displayName: "Install Python Dependencies"
Expand Down
Loading

0 comments on commit 01ee524

Please sign in to comment.