Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1e3ee91cef | ||
|
74721b6d61 | ||
|
2190943faf | ||
|
eb80f07b7d |
2
.github/workflows/ci-tests.yml
vendored
2
.github/workflows/ci-tests.yml
vendored
@@ -52,7 +52,7 @@ jobs:
|
||||
- name: Codestyle black
|
||||
working-directory: api
|
||||
run: |
|
||||
black --exclude migrations/ --check tacticalrmm
|
||||
black --exclude migrations/ --check --diff tacticalrmm
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
@@ -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":
|
||||
@@ -29,3 +31,25 @@ def monitoring_view(function):
|
||||
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
|
||||
|
@@ -20,7 +20,8 @@ urlpatterns = [
|
||||
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),
|
||||
]
|
||||
|
@@ -20,7 +20,7 @@ from rest_framework.request import Request
|
||||
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,
|
||||
@@ -32,6 +32,7 @@ from core.utils import (
|
||||
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,
|
||||
@@ -557,6 +558,72 @@ class TwilioSMSTest(APIView):
|
||||
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):
|
||||
|
@@ -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
|
||||
@@ -21,6 +22,7 @@ from rest_framework.response import Response
|
||||
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,
|
||||
@@ -41,8 +43,8 @@ from tacticalrmm.helpers import (
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from clients.models import Client, Site
|
||||
from alerts.models import Alert
|
||||
from clients.models import Client, Site
|
||||
|
||||
|
||||
def generate_winagent_exe(
|
||||
@@ -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
|
||||
|
Reference in New Issue
Block a user