254 lines
8.2 KiB
Python
254 lines
8.2 KiB
Python
from loguru import logger
|
|
import subprocess
|
|
|
|
from django.conf import settings
|
|
from django.shortcuts import get_object_or_404
|
|
|
|
|
|
from rest_framework.decorators import (
|
|
api_view,
|
|
authentication_classes,
|
|
permission_classes,
|
|
)
|
|
from rest_framework.response import Response
|
|
from rest_framework import status, generics
|
|
from rest_framework.authentication import BasicAuthentication, TokenAuthentication
|
|
|
|
from .models import Agent
|
|
from winupdate.models import WinUpdatePolicy
|
|
|
|
from .serializers import AgentSerializer
|
|
from .tasks import uninstall_agent_task, update_agent_task
|
|
|
|
logger.configure(**settings.LOG_CONFIG)
|
|
|
|
@api_view()
|
|
@permission_classes([])
|
|
@authentication_classes([])
|
|
def update_agent(request, pk):
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
update_agent_task.delay(agent.pk)
|
|
|
|
return Response(f"updating {agent.hostname}")
|
|
|
|
|
|
@api_view(["DELETE"])
|
|
def uninstall_agent(request):
|
|
pk = request.data["pk"]
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
|
|
try:
|
|
resp = agent.salt_api_cmd(
|
|
hostname=agent.hostname,
|
|
timeout=30,
|
|
func="test.ping"
|
|
)
|
|
except Exception:
|
|
agent.uninstall_pending = True
|
|
agent.save(update_fields=["uninstall_pending"])
|
|
logger.warning(f"{agent.hostname} is offline. It will be removed on next check-in")
|
|
return Response(
|
|
{"error": "Agent offline. It will be removed on next check-in"},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
data = resp.json()
|
|
if not data["return"][0][agent.hostname]:
|
|
agent.uninstall_pending = True
|
|
agent.save(update_fields=["uninstall_pending"])
|
|
return Response(
|
|
{"error": "Agent offline. It will be removed on next check-in"},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
logger.info(f"{agent.hostname} has been marked for removal and will be uninstalled shortly")
|
|
uninstall_agent_task.delay(pk, wait=False)
|
|
agent.uninstall_pending = True
|
|
agent.save(update_fields=["uninstall_pending"])
|
|
return Response("ok")
|
|
|
|
|
|
@api_view(["PATCH"])
|
|
def edit_agent(request):
|
|
agent = get_object_or_404(Agent, pk=request.data["pk"])
|
|
|
|
agent.client = request.data["client"]
|
|
agent.site = request.data["site"]
|
|
agent.monitoring_type = request.data["montype"]
|
|
agent.description = request.data["desc"]
|
|
agent.overdue_time = request.data["overduetime"]
|
|
agent.ping_check_interval = request.data["pinginterval"]
|
|
agent.overdue_email_alert = request.data["emailalert"]
|
|
agent.overdue_text_alert = request.data["textalert"]
|
|
|
|
policy = WinUpdatePolicy.objects.get(agent=agent)
|
|
|
|
policy.critical = request.data["critical"]
|
|
policy.important = request.data["important"]
|
|
policy.moderate = request.data["moderate"]
|
|
policy.low = request.data["low"]
|
|
policy.other = request.data["other"]
|
|
policy.run_time_hour = request.data["scheduledtime"]
|
|
policy.run_time_days = request.data["dayoptions"]
|
|
policy.reboot_after_install = request.data["rebootafterinstall"]
|
|
policy.reprocess_failed = request.data["reprocessfailed"]
|
|
policy.reprocess_failed_times = request.data["reprocessfailedtimes"]
|
|
policy.email_if_fail = request.data["emailiffail"]
|
|
|
|
agent.save(update_fields=[
|
|
"client", "site", "monitoring_type", "description", "ping_check_interval",
|
|
"overdue_time", "overdue_email_alert", "overdue_text_alert"
|
|
])
|
|
|
|
policy.save(update_fields=[
|
|
"critical", "important", "moderate", "low", "other", "run_time_hour",
|
|
"run_time_days", "reboot_after_install", "reprocess_failed",
|
|
"reprocess_failed_times", "email_if_fail"
|
|
])
|
|
return Response("ok")
|
|
|
|
|
|
@api_view()
|
|
def meshcentral_tabs(request, pk):
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
r = subprocess.run([
|
|
"node",
|
|
"/meshcentral/node_modules/meshcentral/meshcentral",
|
|
"--logintoken",
|
|
f"user//{settings.MESH_USERNAME}"],
|
|
capture_output=True
|
|
)
|
|
token = r.stdout.decode().splitlines()[0]
|
|
terminalurl = f"{settings.MESH_SITE}/?viewmode=12&hide=31&login={token}&node={agent.mesh_node_id}"
|
|
fileurl = f"{settings.MESH_SITE}/?viewmode=13&hide=31&login={token}&node={agent.mesh_node_id}"
|
|
return Response({
|
|
"hostname": agent.hostname,
|
|
"terminalurl": terminalurl,
|
|
"fileurl": fileurl
|
|
})
|
|
|
|
|
|
@api_view()
|
|
def take_control(request, pk):
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
r = subprocess.run([
|
|
"node",
|
|
"/meshcentral/node_modules/meshcentral/meshcentral",
|
|
"--logintoken",
|
|
f"user//{settings.MESH_USERNAME}"],
|
|
capture_output=True
|
|
)
|
|
token = r.stdout.decode().splitlines()[0]
|
|
url = f"{settings.MESH_SITE}/?viewmode=11&hide=31&login={token}&node={agent.mesh_node_id}"
|
|
return Response(url)
|
|
|
|
|
|
@api_view()
|
|
def agent_detail(request, pk):
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
return Response(AgentSerializer(agent).data)
|
|
|
|
@api_view()
|
|
def get_event_log(request, pk, logtype, days):
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
try:
|
|
resp = agent.salt_api_cmd(
|
|
hostname=agent.hostname,
|
|
timeout=70,
|
|
func="get_eventlog.get_eventlog",
|
|
arg=[logtype, int(days)]
|
|
)
|
|
data = resp.json()
|
|
except Exception:
|
|
return Response({"error": "unable to contact the agent"}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
return Response(data["return"][0][agent.hostname])
|
|
|
|
|
|
@api_view(["POST"])
|
|
def power_action(request):
|
|
pk = request.data["pk"]
|
|
action = request.data["action"]
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
if action == "rebootnow":
|
|
logger.info(f"{agent.hostname} was scheduled for immediate reboot")
|
|
resp = agent.salt_api_cmd(
|
|
hostname=agent.hostname, timeout=30, func="system.reboot", arg=3, kwargs={"in_seconds": True}
|
|
)
|
|
|
|
data = resp.json()
|
|
if not data["return"][0][agent.hostname]:
|
|
return Response(
|
|
"unable to contact the agent", status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
return Response("ok")
|
|
|
|
@api_view(["POST"])
|
|
def send_raw_cmd(request):
|
|
pk = request.data["pk"]
|
|
cmd = request.data["rawcmd"]
|
|
if not cmd:
|
|
return Response("please enter a command", status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
try:
|
|
resp = agent.salt_api_cmd(
|
|
hostname=agent.hostname, timeout=60, func="cmd.run", arg=cmd
|
|
)
|
|
data = resp.json()
|
|
except Exception:
|
|
return Response(
|
|
"unable to contact the agent", status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
if not data["return"][0][agent.hostname]:
|
|
return Response(
|
|
"unable to contact the agent", status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
logger.info(f"The command {cmd} was sent on agent {agent.hostname}")
|
|
return Response(data["return"][0][agent.hostname])
|
|
|
|
|
|
@api_view()
|
|
def list_agents(request):
|
|
agents = Agent.objects.all()
|
|
return Response(AgentSerializer(agents, many=True).data)
|
|
|
|
|
|
@api_view()
|
|
def by_client(request, client):
|
|
agents = Agent.objects.filter(client=client)
|
|
return Response(AgentSerializer(agents, many=True).data)
|
|
|
|
|
|
@api_view()
|
|
def by_site(request, client, site):
|
|
agents = Agent.objects.filter(client=client).filter(site=site)
|
|
return Response(AgentSerializer(agents, many=True).data)
|
|
|
|
|
|
@api_view(["POST"])
|
|
def overdue_action(request):
|
|
pk = request.data["pk"]
|
|
alert_type = request.data["alertType"]
|
|
action = request.data["action"]
|
|
agent = get_object_or_404(Agent, pk=pk)
|
|
if alert_type == "email" and action == "enabled":
|
|
agent.overdue_email_alert = True
|
|
agent.save(update_fields=["overdue_email_alert"])
|
|
elif alert_type == "email" and action == "disabled":
|
|
agent.overdue_email_alert = False
|
|
agent.save(update_fields=["overdue_email_alert"])
|
|
elif alert_type == "text" and action == "enabled":
|
|
agent.overdue_text_alert = True
|
|
agent.save(update_fields=["overdue_text_alert"])
|
|
elif alert_type == "text" and action == "disabled":
|
|
agent.overdue_text_alert = False
|
|
agent.save(update_fields=["overdue_text_alert"])
|
|
else:
|
|
return Response(
|
|
{"error": "Something went wrong"}, status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
return Response(agent.hostname)
|