Skip to content

Commit

Permalink
Merge branch 'amidaware:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
ssteeltm authored Oct 23, 2023
2 parents 744aa18 + f60c8a1 commit f15ff6e
Show file tree
Hide file tree
Showing 35 changed files with 506 additions and 65 deletions.
3 changes: 2 additions & 1 deletion api/tacticalrmm/agents/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ def run_script(
run_as_user = True

parsed_args = script.parse_script_args(self, script.shell, args)
parsed_env_vars = script.parse_script_env_vars(self, script.shell, env_vars)

data = {
"func": "runscriptfull" if full else "runscript",
Expand All @@ -566,7 +567,7 @@ def run_script(
"shell": script.shell,
},
"run_as_user": run_as_user,
"env_vars": env_vars,
"env_vars": parsed_env_vars,
}

if history_pk != 0:
Expand Down
11 changes: 6 additions & 5 deletions api/tacticalrmm/agents/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,9 @@ def install_agent(request):
from agents.utils import get_agent_url
from core.utils import token_is_valid

if getattr(settings, "TRMM_INSECURE", False) and request.data["installMethod"] in {
"exe",
"powershell",
}:
insecure = getattr(settings, "TRMM_INSECURE", False)

if insecure and request.data["installMethod"] in {"exe", "powershell"}:
return notify_error(
"Not available in insecure mode. Please use the 'Manual' method."
)
Expand Down Expand Up @@ -680,7 +679,7 @@ def install_agent(request):
if int(request.data["power"]):
cmd.append("--power")

if getattr(settings, "TRMM_INSECURE", False):
if insecure:
cmd.append("--insecure")

resp["cmd"] = " ".join(str(i) for i in cmd)
Expand All @@ -691,6 +690,8 @@ def install_agent(request):
resp["cmd"] = (
dl + f" && chmod +x {inno} && " + " ".join(str(i) for i in cmd)
)
if insecure:
resp["cmd"] += " --insecure"

resp["url"] = download_url

Expand Down
3 changes: 1 addition & 2 deletions api/tacticalrmm/alerts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,8 +627,7 @@ def parse_script_args(self, args: List[str]) -> List[str]:
pattern = re.compile(".*\\{\\{alert\\.(.*)\\}\\}.*")

for arg in args:
match = pattern.match(arg)
if match:
if match := pattern.match(arg):
name = match.group(1)

# check if attr exists and isn't a function
Expand Down
6 changes: 5 additions & 1 deletion api/tacticalrmm/autotasks/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,11 @@ def get_task_actions(self, obj):
"shell": script.shell,
"timeout": action["timeout"],
"run_as_user": script.run_as_user,
"env_vars": env_vars,
"env_vars": Script.parse_script_env_vars(
agent=agent,
shell=script.shell,
env_vars=env_vars,
),
}
)
if actions_to_remove:
Expand Down
Empty file.
Empty file.
37 changes: 37 additions & 0 deletions api/tacticalrmm/beta/v1/agent/filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import django_filters
from agents.models import Agent


class AgentFilter(django_filters.FilterSet):
last_seen_range = django_filters.DateTimeFromToRangeFilter(field_name="last_seen")
total_ram_range = django_filters.NumericRangeFilter(field_name="total_ram")
patches_last_installed_range = django_filters.DateTimeFromToRangeFilter(
field_name="patches_last_installed"
)

client_id = django_filters.NumberFilter(method="client_id_filter")

class Meta:
model = Agent
fields = [
"id",
"hostname",
"agent_id",
"operating_system",
"plat",
"monitoring_type",
"needs_reboot",
"logged_in_username",
"last_logged_in_user",
"alert_template",
"site",
"policy",
"last_seen_range",
"total_ram_range",
"patches_last_installed_range",
]

def client_id_filter(self, queryset, name, value):
if value:
return queryset.filter(site__client__id=value)
return queryset
40 changes: 40 additions & 0 deletions api/tacticalrmm/beta/v1/agent/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
from rest_framework.request import Request
from rest_framework.serializers import BaseSerializer

from agents.models import Agent
from agents.permissions import AgentPerms
from beta.v1.agent.filter import AgentFilter
from beta.v1.pagination import StandardResultsSetPagination
from ..serializers import DetailAgentSerializer, ListAgentSerializer


class AgentViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, AgentPerms]
queryset = Agent.objects.all()
pagination_class = StandardResultsSetPagination
http_method_names = ["get", "put"]
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_class = AgentFilter
search_fields = ["hostname", "services"]
ordering_fields = ["id"]
ordering = ["id"]

def check_permissions(self, request: Request) -> None:
if "agent_id" in request.query_params:
self.kwargs["agent_id"] = request.query_params["agent_id"]
super().check_permissions(request)

def get_permissions(self):
if self.request.method == "POST":
self.permission_classes = [IsAuthenticated]
return super().get_permissions()

def get_serializer_class(self) -> type[BaseSerializer]:
if self.kwargs:
if self.kwargs["pk"]:
return DetailAgentSerializer
return ListAgentSerializer
Empty file.
13 changes: 13 additions & 0 deletions api/tacticalrmm/beta/v1/client/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated

from clients.models import Client
from clients.permissions import ClientsPerms
from ..serializers import ClientSerializer


class ClientViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, ClientsPerms]
queryset = Client.objects.all()
serializer_class = ClientSerializer
http_method_names = ["get", "put"]
7 changes: 7 additions & 0 deletions api/tacticalrmm/beta/v1/pagination.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from rest_framework.pagination import PageNumberPagination


class StandardResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = "page_size"
max_page_size = 1000
73 changes: 73 additions & 0 deletions api/tacticalrmm/beta/v1/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from rest_framework import serializers

from agents.models import Agent
from clients.models import Client, Site


class ListAgentSerializer(serializers.ModelSerializer[Agent]):
class Meta:
model = Agent
fields = "__all__"


class DetailAgentSerializer(serializers.ModelSerializer[Agent]):
status = serializers.ReadOnlyField()

class Meta:
model = Agent
fields = (
"version",
"operating_system",
"plat",
"goarch",
"hostname",
"agent_id",
"last_seen",
"services",
"public_ip",
"total_ram",
"disks",
"boot_time",
"logged_in_username",
"last_logged_in_user",
"monitoring_type",
"description",
"mesh_node_id",
"overdue_email_alert",
"overdue_text_alert",
"overdue_dashboard_alert",
"offline_time",
"overdue_time",
"check_interval",
"needs_reboot",
"choco_installed",
"wmi_detail",
"patches_last_installed",
"time_zone",
"maintenance_mode",
"block_policy_inheritance",
"alert_template",
"site",
"policy",
"status",
"checks",
"pending_actions_count",
"cpu_model",
"graphics",
"local_ips",
"make_model",
"physical_disks",
"serial_number",
)


class ClientSerializer(serializers.ModelSerializer[Client]):
class Meta:
model = Client
fields = "__all__"


class SiteSerializer(serializers.ModelSerializer[Site]):
class Meta:
model = Site
fields = "__all__"
21 changes: 21 additions & 0 deletions api/tacticalrmm/beta/v1/site/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter

from clients.models import Site
from clients.permissions import SitesPerms
from beta.v1.pagination import StandardResultsSetPagination
from ..serializers import SiteSerializer


class SiteViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, SitesPerms]
queryset = Site.objects.all()
serializer_class = SiteSerializer
pagination_class = StandardResultsSetPagination
http_method_names = ["get", "put"]
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
search_fields = ["name"]
ordering_fields = ["id"]
ordering = ["id"]
12 changes: 12 additions & 0 deletions api/tacticalrmm/beta/v1/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from rest_framework import routers
from .agent import views as agent
from .client import views as client
from .site import views as site

router = routers.DefaultRouter()

router.register("agent", agent.AgentViewSet, basename="agent")
router.register("client", client.ClientViewSet, basename="client")
router.register("site", site.SiteViewSet, basename="site")

urlpatterns = router.urls
10 changes: 8 additions & 2 deletions api/tacticalrmm/checks/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,14 @@ def get_env_vars(self, obj):
if obj.check_type != CheckType.SCRIPT:
return []

# check's env_vars override the script's env vars
return obj.env_vars or obj.script.env_vars
agent = self.context["agent"] if "agent" in self.context.keys() else obj.agent

return Script.parse_script_env_vars(
agent=agent,
shell=obj.script.shell,
env_vars=obj.env_vars
or obj.script.env_vars, # check's env_vars override the script's env vars
)

class Meta:
model = Check
Expand Down
7 changes: 7 additions & 0 deletions api/tacticalrmm/clients/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import uuid
from contextlib import suppress

from django.conf import settings
from django.db.models import Count, Exists, OuterRef, Prefetch, prefetch_related_objects
from django.shortcuts import get_object_or_404
from django.utils import timezone as djangotime
Expand Down Expand Up @@ -288,6 +289,9 @@ def get(self, request):
return Response(DeploymentSerializer(deps, many=True).data)

def post(self, request):
if getattr(settings, "TRMM_INSECURE", False):
return notify_error("Not available in insecure mode")

from accounts.models import User

site = get_object_or_404(Site, pk=request.data["site"])
Expand Down Expand Up @@ -343,6 +347,9 @@ class GenerateAgent(APIView):
permission_classes = (AllowAny,)

def get(self, request, uid):
if getattr(settings, "TRMM_INSECURE", False):
return notify_error("Not available in insecure mode")

from tacticalrmm.utils import generate_winagent_exe

try:
Expand Down
3 changes: 3 additions & 0 deletions api/tacticalrmm/core/agent_linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ fi
if [[ $DISPLAY ]]; then
echo "ERROR: Display detected. Installer only supports running headless, i.e from ssh."
echo "If you cannot ssh in then please run 'sudo systemctl isolate multi-user.target' to switch to a non-graphical user session and run the installer again."
echo "If you are already running headless, then you are probably running with X forwarding which is setting DISPLAY, if so then simply run"
echo "unset DISPLAY"
echo "to unset the variable and then try running the installer again"
exit 1
fi

Expand Down
5 changes: 4 additions & 1 deletion api/tacticalrmm/core/management/commands/pre_update_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ def handle(self, *args, **kwargs):
self.stdout.write(self.style.WARNING("Cleaning the cache"))
clear_entire_cache()
self.stdout.write(self.style.SUCCESS("Cache was cleared!"))
call_command("fix_dupe_agent_customfields")
try:
call_command("fix_dupe_agent_customfields")
except:
pass
10 changes: 10 additions & 0 deletions api/tacticalrmm/core/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import re
from contextlib import suppress
from pathlib import Path
from zoneinfo import ZoneInfo

Expand All @@ -11,6 +12,7 @@
from django.shortcuts import get_object_or_404
from django.utils import timezone as djangotime
from django.views.decorators.csrf import csrf_exempt
from redis import from_url
from rest_framework.decorators import api_view, permission_classes
from rest_framework.exceptions import PermissionDenied
from rest_framework.permissions import IsAuthenticated
Expand Down Expand Up @@ -430,6 +432,13 @@ def status(request):
now = djangotime.now()
delta = expires - now

redis_url = f"redis://{settings.REDIS_HOST}"
redis_ping = False
with suppress(Exception):
with from_url(redis_url) as conn:
conn.ping()
redis_ping = True

ret = {
"version": settings.TRMM_VERSION,
"latest_agent_version": settings.LATEST_AGENT_VER,
Expand All @@ -440,6 +449,7 @@ def status(request):
"mem_usage_percent": mem_usage,
"days_until_cert_expires": delta.days,
"cert_expired": delta.days < 0,
"redis_ping": redis_ping,
}

if settings.DOCKER_BUILD:
Expand Down
Loading

0 comments on commit f15ff6e

Please sign in to comment.