Skip to content

Commit

Permalink
monitoring view v2
Browse files Browse the repository at this point in the history
  • Loading branch information
wh1te909 committed Jan 24, 2025
1 parent 83b4d8c commit eb80f07
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 4 deletions.
24 changes: 24 additions & 0 deletions api/tacticalrmm/core/decorators.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import json
from functools import wraps

from django.conf import settings
from django.http import HttpResponse


# TODO deprecated
def monitoring_view(function):
def wrap(request, *args, **kwargs):
if request.method != "POST":
Expand All @@ -29,3 +31,25 @@ def wrap(request, *args, **kwargs):
wrap.__doc__ = function.__doc__
wrap.__name__ = function.__name__
return wrap


def monitoring_view_v2(function):
@wraps(function)
def wrap(request, *args, **kwargs):
if request.method != "GET":
return HttpResponse("Invalid request type\n", status=400)

http_token = request.META.get("HTTP_X_MON_TOKEN")
if not http_token:
return HttpResponse("Missing X-Mon-Token header\n", status=401)

mon_token = getattr(settings, "MON_TOKEN", "")
if not mon_token:
return HttpResponse("Missing mon token\n", status=401)

if http_token != mon_token:
return HttpResponse("Not authenticated\n", status=401)

return function(request, *args, **kwargs)

return wrap
3 changes: 2 additions & 1 deletion api/tacticalrmm/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
path("urlaction/run/test/", views.RunTestURLAction.as_view()),
path("smstest/", views.TwilioSMSTest.as_view()),
path("clearcache/", views.clear_cache),
path("status/", views.status),
path("status/", views.status), # TODO deprecated
path("v2/status/", views.status_v2),
path("openai/generate/", views.OpenAICodeCompletion.as_view()),
path("webtermperms/", views.webterm_perms),
]
Expand Down
69 changes: 68 additions & 1 deletion api/tacticalrmm/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from rest_framework.response import Response
from rest_framework.views import APIView

from core.decorators import monitoring_view
from core.decorators import monitoring_view, monitoring_view_v2
from core.tasks import sync_mesh_perms_task
from core.utils import (
get_core_settings,
Expand All @@ -32,6 +32,7 @@
from logs.models import AuditLog
from tacticalrmm.constants import AuditActionType, PAStatus
from tacticalrmm.helpers import get_certs, notify_error
from tacticalrmm.logger import logger
from tacticalrmm.permissions import (
_has_perm_on_agent,
_has_perm_on_client,
Expand Down Expand Up @@ -557,6 +558,72 @@ def post(self, request):
return Response(msg)


@csrf_exempt
@monitoring_view_v2
def status_v2(request):
from agents.models import Agent
from clients.models import Client, Site
from tacticalrmm.helpers import get_nats_ports
from tacticalrmm.utils import get_celery_queue_len, localhost_port_is_open

disk_usage: int = round(psutil.disk_usage("/").percent)
mem_usage: int = round(psutil.virtual_memory().percent)

cert_file, _ = get_certs()
cert_bytes = Path(cert_file).read_bytes()

cert = x509.load_pem_x509_certificate(cert_bytes)
delta = cert.not_valid_after_utc - djangotime.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

celery_queue_health = "healthy"
try:
queue_len = get_celery_queue_len()
except RuntimeError as e:
queue_len = -1
celery_queue_health = "unhealthy"
logger.error(f"Error getting celery queue length: {e}")

nats_std_port, nats_ws_port = get_nats_ports()
mesh_port = getattr(settings, "MESH_PORT", 4430)

ret = {
"version": settings.TRMM_VERSION,
"latest_agent_version": settings.LATEST_AGENT_VER,
"agent_count": Agent.objects.count(),
"client_count": Client.objects.count(),
"site_count": Site.objects.count(),
"disk_usage_percent": disk_usage,
"mem_usage_percent": mem_usage,
"days_until_cert_expires": delta.days,
"cert_expired": delta.days < 0,
"redis_ping": redis_ping,
"celery_queue_len": queue_len,
"celery_queue_health": celery_queue_health,
"nats_std_ping": localhost_port_is_open(nats_std_port),
"nats_ws_ping": localhost_port_is_open(nats_ws_port),
"mesh_ping": localhost_port_is_open(mesh_port),
"services_running": {
"mesh": sysd_svc_is_running("meshcentral.service"),
"daphne": sysd_svc_is_running("daphne.service"),
"celery": sysd_svc_is_running("celery.service"),
"celerybeat": sysd_svc_is_running("celerybeat.service"),
"redis": sysd_svc_is_running("redis-server.service"),
"nats": sysd_svc_is_running("nats.service"),
"nats-api": sysd_svc_is_running("nats-api.service"),
}
}

return JsonResponse(ret, json_dumps_params={"indent": 2})


## TODO deprecated
@csrf_exempt
@monitoring_view
def status(request):
Expand Down
24 changes: 22 additions & 2 deletions api/tacticalrmm/tacticalrmm/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import json
import os
import re
import socket
import subprocess
import tempfile
import time
import re
from contextlib import contextmanager
from typing import TYPE_CHECKING, List, Literal, Optional, Union
from zoneinfo import ZoneInfo
Expand All @@ -21,6 +22,7 @@
from agents.models import Agent
from core.utils import get_core_settings, token_is_valid
from logs.models import DebugLog
from tacticalrmm.celery import app as celery_app
from tacticalrmm.constants import (
MONTH_DAYS,
MONTHS,
Expand All @@ -41,8 +43,8 @@
)

if TYPE_CHECKING:
from clients.models import Client, Site
from alerts.models import Alert
from clients.models import Client, Site


def generate_winagent_exe(
Expand Down Expand Up @@ -468,3 +470,21 @@ def runcmd_placeholder_text() -> dict[str, str]:
),
}
return ret


def get_celery_queue_len():
try:
with celery_app.pool.acquire(block=True) as conn:
return conn.default_channel.client.llen("celery")
except Exception as e:
raise RuntimeError(f"Error getting celery queue length: {e}")


def localhost_port_is_open(port):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(1)
s.connect(("127.0.0.1", port))
return True
except (socket.timeout, ConnectionRefusedError):
return False

0 comments on commit eb80f07

Please sign in to comment.