Skip to content

Commit

Permalink
Release 0.10.0
Browse files Browse the repository at this point in the history
  • Loading branch information
wh1te909 committed Nov 19, 2021
2 parents 3969208 + 9cb952b commit ff25083
Show file tree
Hide file tree
Showing 78 changed files with 2,371 additions and 1,879 deletions.
6 changes: 1 addition & 5 deletions .devcontainer/api.dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.9.6-slim
FROM python:3.9.9-slim

ENV TACTICAL_DIR /opt/tactical
ENV TACTICAL_READY_FILE ${TACTICAL_DIR}/tmp/tactical.ready
Expand All @@ -13,10 +13,6 @@ EXPOSE 8000 8383 8005
RUN groupadd -g 1000 tactical && \
useradd -u 1000 -g 1000 tactical

# Copy nats-api file
COPY natsapi/bin/nats-api /usr/local/bin/
RUN chmod +x /usr/local/bin/nats-api

# Copy dev python reqs
COPY .devcontainer/requirements.txt /

Expand Down
1 change: 1 addition & 0 deletions .devcontainer/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ EOF
"${VIRTUAL_ENV}"/bin/python manage.py load_chocos
"${VIRTUAL_ENV}"/bin/python manage.py load_community_scripts
"${VIRTUAL_ENV}"/bin/python manage.py reload_nats
"${VIRTUAL_ENV}"/bin/python manage.py create_natsapi_conf
"${VIRTUAL_ENV}"/bin/python manage.py create_installer_user

# create super user
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ nats-rmm.conf
docs/site/
reset_db.sh
run_go_cmd.py
nats-api.conf

20 changes: 20 additions & 0 deletions api/tacticalrmm/agents/management/commands/update_agents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django.conf import settings
from django.core.management.base import BaseCommand
from packaging import version as pyver

from agents.models import Agent
from agents.tasks import send_agent_update_task
from tacticalrmm.utils import AGENT_DEFER


class Command(BaseCommand):
help = "Triggers an agent update task to run"

def handle(self, *args, **kwargs):
q = Agent.objects.defer(*AGENT_DEFER).exclude(version=settings.LATEST_AGENT_VER)
agent_ids: list[str] = [
i.agent_id
for i in q
if pyver.parse(i.version) < pyver.parse(settings.LATEST_AGENT_VER)
]
send_agent_update_task.delay(agent_ids=agent_ids)
2 changes: 1 addition & 1 deletion api/tacticalrmm/agents/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,8 @@ async def nats_cmd(self, data: dict, timeout: int = 30, wait: bool = True):
try:
ret = msgpack.loads(msg.data) # type: ignore
except Exception as e:
DebugLog.error(agent=self, log_type="agent_issues", message=e)
ret = str(e)
DebugLog.error(agent=self, log_type="agent_issues", message=ret)

await nc.close()
return ret
Expand Down
4 changes: 3 additions & 1 deletion api/tacticalrmm/agents/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ class AgentSerializer(serializers.ModelSerializer):
client = serializers.ReadOnlyField(source="client.name")
site_name = serializers.ReadOnlyField(source="site.name")
custom_fields = AgentCustomFieldSerializer(many=True, read_only=True)
patches_last_installed = serializers.ReadOnlyField()
last_seen = serializers.ReadOnlyField()

def get_all_timezones(self, obj):
return pytz.all_timezones

class Meta:
model = Agent
exclude = ["last_seen", "id", "patches_last_installed"]
exclude = ["id"]


class AgentTableSerializer(serializers.ModelSerializer):
Expand Down
24 changes: 2 additions & 22 deletions api/tacticalrmm/agents/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from packaging import version as pyver
from scripts.models import Script
from tacticalrmm.celery import app
from tacticalrmm.utils import run_nats_api_cmd

from agents.models import Agent
from agents.utils import get_winagent_url
Expand Down Expand Up @@ -80,7 +79,7 @@ def force_code_sign(agent_ids: list[str]) -> None:

@app.task
def send_agent_update_task(agent_ids: list[str]) -> None:
chunks = (agent_ids[i : i + 30] for i in range(0, len(agent_ids), 30))
chunks = (agent_ids[i : i + 50] for i in range(0, len(agent_ids), 50))
for chunk in chunks:
for agent_id in chunk:
agent_update(agent_id)
Expand Down Expand Up @@ -268,7 +267,7 @@ def run_script_email_results_task(
server.send_message(msg)
server.quit()
except Exception as e:
DebugLog.error(message=e)
DebugLog.error(message=str(e))


@app.task
Expand Down Expand Up @@ -299,25 +298,6 @@ def clear_faults_task(older_than_days: int) -> None:
)


@app.task
def get_wmi_task() -> None:
agents = Agent.objects.only(
"pk", "agent_id", "last_seen", "overdue_time", "offline_time"
)
ids = [i.agent_id for i in agents if i.status == "online"]
run_nats_api_cmd("wmi", ids, timeout=45)


@app.task
def agent_checkin_task() -> None:
run_nats_api_cmd("checkin", timeout=30)


@app.task
def agent_getinfo_task() -> None:
run_nats_api_cmd("agentinfo", timeout=30)


@app.task
def prune_agent_history(older_than_days: int) -> str:
from .models import AgentHistory
Expand Down
40 changes: 11 additions & 29 deletions api/tacticalrmm/agents/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@
from logs.models import AuditLog, DebugLog, PendingAction
from scripts.models import Script
from scripts.tasks import handle_bulk_command_task, handle_bulk_script_task
from tacticalrmm.utils import get_default_timezone, notify_error, reload_nats
from tacticalrmm.utils import (
get_default_timezone,
notify_error,
reload_nats,
AGENT_DEFER,
)
from winupdate.serializers import WinUpdatePolicySerializer
from winupdate.tasks import bulk_check_for_updates_task, bulk_install_updates_task
from tacticalrmm.permissions import (
Expand Down Expand Up @@ -74,42 +79,21 @@ def get(self, request):
or "detail" in request.query_params.keys()
and request.query_params["detail"] == "true"
):

agents = (
Agent.objects.filter_by_role(request.user)
Agent.objects.filter_by_role(request.user) # type: ignore
.select_related("site", "policy", "alert_template")
.prefetch_related("agentchecks")
.filter(filter)
.only(
"pk",
"hostname",
"agent_id",
"site",
"policy",
"alert_template",
"monitoring_type",
"description",
"needs_reboot",
"overdue_text_alert",
"overdue_email_alert",
"overdue_time",
"offline_time",
"last_seen",
"boot_time",
"logged_in_username",
"last_logged_in_user",
"time_zone",
"maintenance_mode",
"pending_actions_count",
"has_patches_pending",
)
.defer(*AGENT_DEFER)
)
ctx = {"default_tz": get_default_timezone()}
serializer = AgentTableSerializer(agents, many=True, context=ctx)

# if detail=false
else:
agents = (
Agent.objects.filter_by_role(request.user)
Agent.objects.filter_by_role(request.user) # type: ignore
.select_related("site")
.filter(filter)
.only("agent_id", "hostname", "site")
Expand All @@ -125,9 +109,7 @@ class GetUpdateDeleteAgent(APIView):
# get agent details
def get(self, request, agent_id):
agent = get_object_or_404(Agent, agent_id=agent_id)
return Response(
AgentSerializer(agent, context={"default_tz": get_default_timezone()}).data
)
return Response(AgentSerializer(agent).data)

# edit agent
def put(self, request, agent_id):
Expand Down
2 changes: 1 addition & 1 deletion api/tacticalrmm/alerts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ def parse_script_args(self, args: list[str]):
try:
temp_args.append(re.sub("\\{\\{.*\\}\\}", value, arg)) # type: ignore
except Exception as e:
DebugLog.error(log_type="scripting", message=e)
DebugLog.error(log_type="scripting", message=str(e))
continue

else:
Expand Down
30 changes: 6 additions & 24 deletions api/tacticalrmm/alerts/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from tacticalrmm.test import TacticalTestCase

from alerts.tasks import cache_agents_alert_template
from agents.tasks import handle_agents_task

from .models import Alert, AlertTemplate
from .serializers import (
Expand Down Expand Up @@ -676,25 +677,14 @@ def test_handle_agent_alerts(
url = "/api/v3/checkin/"

agent_template_text.version = settings.LATEST_AGENT_VER
agent_template_text.last_seen = djangotime.now()
agent_template_text.save()

agent_template_email.version = settings.LATEST_AGENT_VER
agent_template_email.last_seen = djangotime.now()
agent_template_email.save()

data = {
"agent_id": agent_template_text.agent_id,
"version": settings.LATEST_AGENT_VER,
}

resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)

data = {
"agent_id": agent_template_email.agent_id,
"version": settings.LATEST_AGENT_VER,
}

resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)
handle_agents_task()

recovery_sms.assert_called_with(
pk=Alert.objects.get(agent=agent_template_text).pk
Expand Down Expand Up @@ -1365,15 +1355,7 @@ def test_alert_actions(
agent.last_seen = djangotime.now()
agent.save()

url = "/api/v3/checkin/"

data = {
"agent_id": agent.agent_id,
"version": settings.LATEST_AGENT_VER,
}

resp = self.client.patch(url, data, format="json")
self.assertEqual(resp.status_code, 200)
handle_agents_task()

# this is what data should be
data = {
Expand Down
36 changes: 0 additions & 36 deletions api/tacticalrmm/apiv3/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,42 +130,6 @@ def test_run_checks(self):
self.assertIsInstance(r.json()["check_interval"], int)
self.assertEqual(len(r.json()["checks"]), 15)

def test_checkin_patch(self):
from logs.models import PendingAction

url = "/api/v3/checkin/"
agent_updated = baker.make_recipe("agents.agent", version="1.3.0")
PendingAction.objects.create(
agent=agent_updated,
action_type="agentupdate",
details={
"url": agent_updated.winagent_dl,
"version": agent_updated.version,
"inno": agent_updated.win_inno_exe,
},
)
action = agent_updated.pendingactions.filter(action_type="agentupdate").first()
self.assertEqual(action.status, "pending")

# test agent failed to update and still on same version
payload = {
"func": "hello",
"agent_id": agent_updated.agent_id,
"version": "1.3.0",
}
r = self.client.patch(url, payload, format="json")
self.assertEqual(r.status_code, 200)
action = agent_updated.pendingactions.filter(action_type="agentupdate").first()
self.assertEqual(action.status, "pending")

# test agent successful update
payload["version"] = settings.LATEST_AGENT_VER
r = self.client.patch(url, payload, format="json")
self.assertEqual(r.status_code, 200)
action = agent_updated.pendingactions.filter(action_type="agentupdate").first()
self.assertEqual(action.status, "completed")
action.delete()

@patch("apiv3.views.reload_nats")
def test_agent_recovery(self, reload_nats):
reload_nats.return_value = "ok"
Expand Down
Loading

0 comments on commit ff25083

Please sign in to comment.