Compare commits
	
		
			11 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e413c0264a | ||
| 
						 | 
					f88e7f898c | ||
| 
						 | 
					d07bd4a6db | ||
| 
						 | 
					fb34c099d5 | ||
| 
						 | 
					1d2ee56a15 | ||
| 
						 | 
					86665f7f09 | ||
| 
						 | 
					0d2b4af986 | ||
| 
						 | 
					dc2b2eeb9f | ||
| 
						 | 
					e5dbb66d53 | ||
| 
						 | 
					3474b1c471 | ||
| 
						 | 
					3886de5b7c | 
@@ -164,13 +164,11 @@ class Agent(BaseAuditModel):
 | 
				
			|||||||
                elif i.status == "failing":
 | 
					                elif i.status == "failing":
 | 
				
			||||||
                    failing += 1
 | 
					                    failing += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        has_failing_checks = True if failing > 0 else False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ret = {
 | 
					        ret = {
 | 
				
			||||||
            "total": total,
 | 
					            "total": total,
 | 
				
			||||||
            "passing": passing,
 | 
					            "passing": passing,
 | 
				
			||||||
            "failing": failing,
 | 
					            "failing": failing,
 | 
				
			||||||
            "has_failing_checks": has_failing_checks,
 | 
					            "has_failing_checks": failing > 0,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return ret
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ from time import sleep
 | 
				
			|||||||
import random
 | 
					import random
 | 
				
			||||||
import requests
 | 
					import requests
 | 
				
			||||||
from packaging import version as pyver
 | 
					from packaging import version as pyver
 | 
				
			||||||
 | 
					from typing import List
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,153 +15,92 @@ from logs.models import PendingAction
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
logger.configure(**settings.LOG_CONFIG)
 | 
					logger.configure(**settings.LOG_CONFIG)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OLD_64_PY_AGENT = "https://github.com/wh1te909/winagent/releases/download/v0.11.2/winagent-v0.11.2.exe"
 | 
					
 | 
				
			||||||
OLD_32_PY_AGENT = "https://github.com/wh1te909/winagent/releases/download/v0.11.2/winagent-v0.11.2-x86.exe"
 | 
					def agent_update(pk: int) -> str:
 | 
				
			||||||
 | 
					    agent = Agent.objects.get(pk=pk)
 | 
				
			||||||
 | 
					    # skip if we can't determine the arch
 | 
				
			||||||
 | 
					    if agent.arch is None:
 | 
				
			||||||
 | 
					        logger.warning(f"Unable to determine arch on {agent.hostname}. Skipping.")
 | 
				
			||||||
 | 
					        return "noarch"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # force an update to 1.1.5 since 1.1.6 needs agent to be on 1.1.5 first
 | 
				
			||||||
 | 
					    if pyver.parse(agent.version) < pyver.parse("1.1.5"):
 | 
				
			||||||
 | 
					        version = "1.1.5"
 | 
				
			||||||
 | 
					        if agent.arch == "64":
 | 
				
			||||||
 | 
					            url = "https://github.com/wh1te909/rmmagent/releases/download/v1.1.5/winagent-v1.1.5.exe"
 | 
				
			||||||
 | 
					            inno = "winagent-v1.1.5.exe"
 | 
				
			||||||
 | 
					        elif agent.arch == "32":
 | 
				
			||||||
 | 
					            url = "https://github.com/wh1te909/rmmagent/releases/download/v1.1.5/winagent-v1.1.5-x86.exe"
 | 
				
			||||||
 | 
					            inno = "winagent-v1.1.5-x86.exe"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return "nover"
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        version = settings.LATEST_AGENT_VER
 | 
				
			||||||
 | 
					        url = agent.winagent_dl
 | 
				
			||||||
 | 
					        inno = agent.win_inno_exe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if agent.has_nats:
 | 
				
			||||||
 | 
					        if agent.pendingactions.filter(
 | 
				
			||||||
 | 
					            action_type="agentupdate", status="pending"
 | 
				
			||||||
 | 
					        ).exists():
 | 
				
			||||||
 | 
					            action = agent.pendingactions.filter(
 | 
				
			||||||
 | 
					                action_type="agentupdate", status="pending"
 | 
				
			||||||
 | 
					            ).last()
 | 
				
			||||||
 | 
					            if pyver.parse(action.details["version"]) < pyver.parse(version):
 | 
				
			||||||
 | 
					                action.delete()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return "pending"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PendingAction.objects.create(
 | 
				
			||||||
 | 
					            agent=agent,
 | 
				
			||||||
 | 
					            action_type="agentupdate",
 | 
				
			||||||
 | 
					            details={
 | 
				
			||||||
 | 
					                "url": url,
 | 
				
			||||||
 | 
					                "version": version,
 | 
				
			||||||
 | 
					                "inno": inno,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return "created"
 | 
				
			||||||
 | 
					    # TODO
 | 
				
			||||||
 | 
					    # Salt is deprecated, remove this once salt is gone
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        agent.salt_api_async(
 | 
				
			||||||
 | 
					            func="win_agent.do_agent_update_v2",
 | 
				
			||||||
 | 
					            kwargs={
 | 
				
			||||||
 | 
					                "inno": inno,
 | 
				
			||||||
 | 
					                "url": url,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return "salt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.task
 | 
					@app.task
 | 
				
			||||||
def send_agent_update_task(pks, version):
 | 
					def send_agent_update_task(pks: List[int], version: str) -> None:
 | 
				
			||||||
    assert isinstance(pks, list)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q = Agent.objects.filter(pk__in=pks)
 | 
					    q = Agent.objects.filter(pk__in=pks)
 | 
				
			||||||
    agents = [i.pk for i in q if pyver.parse(i.version) < pyver.parse(version)]
 | 
					    agents: List[int] = [
 | 
				
			||||||
 | 
					        i.pk for i in q if pyver.parse(i.version) < pyver.parse(version)
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chunks = (agents[i : i + 30] for i in range(0, len(agents), 30))
 | 
					    for pk in agents:
 | 
				
			||||||
 | 
					        agent_update(pk)
 | 
				
			||||||
    for chunk in chunks:
 | 
					 | 
				
			||||||
        for pk in chunk:
 | 
					 | 
				
			||||||
            agent = Agent.objects.get(pk=pk)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # skip if we can't determine the arch
 | 
					 | 
				
			||||||
            if agent.arch is None:
 | 
					 | 
				
			||||||
                logger.warning(
 | 
					 | 
				
			||||||
                    f"Unable to determine arch on {agent.salt_id}. Skipping."
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # golang agent only backwards compatible with py agent 0.11.2
 | 
					 | 
				
			||||||
            # force an upgrade to the latest python agent if version < 0.11.2
 | 
					 | 
				
			||||||
            if pyver.parse(agent.version) < pyver.parse("0.11.2"):
 | 
					 | 
				
			||||||
                url = OLD_64_PY_AGENT if agent.arch == "64" else OLD_32_PY_AGENT
 | 
					 | 
				
			||||||
                inno = (
 | 
					 | 
				
			||||||
                    "winagent-v0.11.2.exe"
 | 
					 | 
				
			||||||
                    if agent.arch == "64"
 | 
					 | 
				
			||||||
                    else "winagent-v0.11.2-x86.exe"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                url = agent.winagent_dl
 | 
					 | 
				
			||||||
                inno = agent.win_inno_exe
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if agent.has_nats:
 | 
					 | 
				
			||||||
                if agent.pendingactions.filter(
 | 
					 | 
				
			||||||
                    action_type="agentupdate", status="pending"
 | 
					 | 
				
			||||||
                ).exists():
 | 
					 | 
				
			||||||
                    action = agent.pendingactions.filter(
 | 
					 | 
				
			||||||
                        action_type="agentupdate", status="pending"
 | 
					 | 
				
			||||||
                    ).last()
 | 
					 | 
				
			||||||
                    if pyver.parse(action.details["version"]) < pyver.parse(
 | 
					 | 
				
			||||||
                        settings.LATEST_AGENT_VER
 | 
					 | 
				
			||||||
                    ):
 | 
					 | 
				
			||||||
                        action.delete()
 | 
					 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                PendingAction.objects.create(
 | 
					 | 
				
			||||||
                    agent=agent,
 | 
					 | 
				
			||||||
                    action_type="agentupdate",
 | 
					 | 
				
			||||||
                    details={
 | 
					 | 
				
			||||||
                        "url": agent.winagent_dl,
 | 
					 | 
				
			||||||
                        "version": settings.LATEST_AGENT_VER,
 | 
					 | 
				
			||||||
                        "inno": agent.win_inno_exe,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            # TODO
 | 
					 | 
				
			||||||
            # Salt is deprecated, remove this once salt is gone
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                r = agent.salt_api_async(
 | 
					 | 
				
			||||||
                    func="win_agent.do_agent_update_v2",
 | 
					 | 
				
			||||||
                    kwargs={
 | 
					 | 
				
			||||||
                        "inno": inno,
 | 
					 | 
				
			||||||
                        "url": url,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
        sleep(5)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.task
 | 
					@app.task
 | 
				
			||||||
def auto_self_agent_update_task():
 | 
					def auto_self_agent_update_task() -> None:
 | 
				
			||||||
    core = CoreSettings.objects.first()
 | 
					    core = CoreSettings.objects.first()
 | 
				
			||||||
    if not core.agent_auto_update:
 | 
					    if not core.agent_auto_update:
 | 
				
			||||||
        logger.info("Agent auto update is disabled. Skipping.")
 | 
					        logger.info("Agent auto update is disabled. Skipping.")
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    q = Agent.objects.only("pk", "version")
 | 
					    q = Agent.objects.only("pk", "version")
 | 
				
			||||||
    agents = [
 | 
					    pks: List[int] = [
 | 
				
			||||||
        i.pk
 | 
					        i.pk
 | 
				
			||||||
        for i in q
 | 
					        for i in q
 | 
				
			||||||
        if pyver.parse(i.version) < pyver.parse(settings.LATEST_AGENT_VER)
 | 
					        if pyver.parse(i.version) < pyver.parse(settings.LATEST_AGENT_VER)
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chunks = (agents[i : i + 30] for i in range(0, len(agents), 30))
 | 
					    for pk in pks:
 | 
				
			||||||
 | 
					        agent_update(pk)
 | 
				
			||||||
    for chunk in chunks:
 | 
					 | 
				
			||||||
        for pk in chunk:
 | 
					 | 
				
			||||||
            agent = Agent.objects.get(pk=pk)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # skip if we can't determine the arch
 | 
					 | 
				
			||||||
            if agent.arch is None:
 | 
					 | 
				
			||||||
                logger.warning(
 | 
					 | 
				
			||||||
                    f"Unable to determine arch on {agent.salt_id}. Skipping."
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # golang agent only backwards compatible with py agent 0.11.2
 | 
					 | 
				
			||||||
            # force an upgrade to the latest python agent if version < 0.11.2
 | 
					 | 
				
			||||||
            if pyver.parse(agent.version) < pyver.parse("0.11.2"):
 | 
					 | 
				
			||||||
                url = OLD_64_PY_AGENT if agent.arch == "64" else OLD_32_PY_AGENT
 | 
					 | 
				
			||||||
                inno = (
 | 
					 | 
				
			||||||
                    "winagent-v0.11.2.exe"
 | 
					 | 
				
			||||||
                    if agent.arch == "64"
 | 
					 | 
				
			||||||
                    else "winagent-v0.11.2-x86.exe"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                url = agent.winagent_dl
 | 
					 | 
				
			||||||
                inno = agent.win_inno_exe
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if agent.has_nats:
 | 
					 | 
				
			||||||
                if agent.pendingactions.filter(
 | 
					 | 
				
			||||||
                    action_type="agentupdate", status="pending"
 | 
					 | 
				
			||||||
                ).exists():
 | 
					 | 
				
			||||||
                    action = agent.pendingactions.filter(
 | 
					 | 
				
			||||||
                        action_type="agentupdate", status="pending"
 | 
					 | 
				
			||||||
                    ).last()
 | 
					 | 
				
			||||||
                    if pyver.parse(action.details["version"]) < pyver.parse(
 | 
					 | 
				
			||||||
                        settings.LATEST_AGENT_VER
 | 
					 | 
				
			||||||
                    ):
 | 
					 | 
				
			||||||
                        action.delete()
 | 
					 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                PendingAction.objects.create(
 | 
					 | 
				
			||||||
                    agent=agent,
 | 
					 | 
				
			||||||
                    action_type="agentupdate",
 | 
					 | 
				
			||||||
                    details={
 | 
					 | 
				
			||||||
                        "url": agent.winagent_dl,
 | 
					 | 
				
			||||||
                        "version": settings.LATEST_AGENT_VER,
 | 
					 | 
				
			||||||
                        "inno": agent.win_inno_exe,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            # TODO
 | 
					 | 
				
			||||||
            # Salt is deprecated, remove this once salt is gone
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                r = agent.salt_api_async(
 | 
					 | 
				
			||||||
                    func="win_agent.do_agent_update_v2",
 | 
					 | 
				
			||||||
                    kwargs={
 | 
					 | 
				
			||||||
                        "inno": inno,
 | 
					 | 
				
			||||||
                        "url": url,
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
        sleep(5)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.task
 | 
					@app.task
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,19 +5,20 @@ from unittest.mock import patch
 | 
				
			|||||||
from model_bakery import baker
 | 
					from model_bakery import baker
 | 
				
			||||||
from itertools import cycle
 | 
					from itertools import cycle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.test import TestCase, override_settings
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.utils import timezone as djangotime
 | 
					from django.utils import timezone as djangotime
 | 
				
			||||||
 | 
					from logs.models import PendingAction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from tacticalrmm.test import TacticalTestCase
 | 
					from tacticalrmm.test import TacticalTestCase
 | 
				
			||||||
from .serializers import AgentSerializer
 | 
					from .serializers import AgentSerializer
 | 
				
			||||||
from winupdate.serializers import WinUpdatePolicySerializer
 | 
					from winupdate.serializers import WinUpdatePolicySerializer
 | 
				
			||||||
from .models import Agent
 | 
					from .models import Agent
 | 
				
			||||||
from .tasks import (
 | 
					from .tasks import (
 | 
				
			||||||
 | 
					    agent_recovery_sms_task,
 | 
				
			||||||
    auto_self_agent_update_task,
 | 
					    auto_self_agent_update_task,
 | 
				
			||||||
    sync_salt_modules_task,
 | 
					    sync_salt_modules_task,
 | 
				
			||||||
    batch_sync_modules_task,
 | 
					    batch_sync_modules_task,
 | 
				
			||||||
    OLD_64_PY_AGENT,
 | 
					 | 
				
			||||||
    OLD_32_PY_AGENT,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from winupdate.models import WinUpdatePolicy
 | 
					from winupdate.models import WinUpdatePolicy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -786,6 +787,70 @@ class TestAgentTasks(TacticalTestCase):
 | 
				
			|||||||
        self.assertEqual(ret.status, "SUCCESS")
 | 
					        self.assertEqual(ret.status, "SUCCESS")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @patch("agents.models.Agent.salt_api_async")
 | 
					    @patch("agents.models.Agent.salt_api_async")
 | 
				
			||||||
 | 
					    def test_agent_update(self, salt_api_async):
 | 
				
			||||||
 | 
					        from agents.tasks import agent_update
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        agent_noarch = baker.make_recipe(
 | 
				
			||||||
 | 
					            "agents.agent",
 | 
				
			||||||
 | 
					            operating_system="Error getting OS",
 | 
				
			||||||
 | 
					            version="1.1.0",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        r = agent_update(agent_noarch.pk)
 | 
				
			||||||
 | 
					        self.assertEqual(r, "noarch")
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            PendingAction.objects.filter(
 | 
				
			||||||
 | 
					                agent=agent_noarch, action_type="agentupdate"
 | 
				
			||||||
 | 
					            ).count(),
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        agent64_nats = baker.make_recipe(
 | 
				
			||||||
 | 
					            "agents.agent",
 | 
				
			||||||
 | 
					            operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
 | 
				
			||||||
 | 
					            version="1.1.0",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r = agent_update(agent64_nats.pk)
 | 
				
			||||||
 | 
					        self.assertEqual(r, "created")
 | 
				
			||||||
 | 
					        action = PendingAction.objects.get(agent__pk=agent64_nats.pk)
 | 
				
			||||||
 | 
					        self.assertEqual(action.action_type, "agentupdate")
 | 
				
			||||||
 | 
					        self.assertEqual(action.status, "pending")
 | 
				
			||||||
 | 
					        self.assertEqual(action.details["url"], settings.DL_64)
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            action.details["inno"], f"winagent-v{settings.LATEST_AGENT_VER}.exe"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(action.details["version"], settings.LATEST_AGENT_VER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        agent64_salt = baker.make_recipe(
 | 
				
			||||||
 | 
					            "agents.agent",
 | 
				
			||||||
 | 
					            operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
 | 
				
			||||||
 | 
					            version="1.0.0",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        salt_api_async.return_value = True
 | 
				
			||||||
 | 
					        r = agent_update(agent64_salt.pk)
 | 
				
			||||||
 | 
					        self.assertEqual(r, "salt")
 | 
				
			||||||
 | 
					        salt_api_async.assert_called_with(
 | 
				
			||||||
 | 
					            func="win_agent.do_agent_update_v2",
 | 
				
			||||||
 | 
					            kwargs={
 | 
				
			||||||
 | 
					                "inno": f"winagent-v{settings.LATEST_AGENT_VER}.exe",
 | 
				
			||||||
 | 
					                "url": settings.DL_64,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        salt_api_async.reset_mock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        agent32_nats = baker.make_recipe(
 | 
				
			||||||
 | 
					            "agents.agent",
 | 
				
			||||||
 | 
					            operating_system="Windows 7 Professional, 32 bit (build 7601.23964)",
 | 
				
			||||||
 | 
					            version="1.1.0",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        agent32_salt = baker.make_recipe(
 | 
				
			||||||
 | 
					            "agents.agent",
 | 
				
			||||||
 | 
					            operating_system="Windows 7 Professional, 32 bit (build 7601.23964)",
 | 
				
			||||||
 | 
					            version="1.0.0",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """ @patch("agents.models.Agent.salt_api_async")
 | 
				
			||||||
    @patch("agents.tasks.sleep", return_value=None)
 | 
					    @patch("agents.tasks.sleep", return_value=None)
 | 
				
			||||||
    def test_auto_self_agent_update_task(self, mock_sleep, salt_api_async):
 | 
					    def test_auto_self_agent_update_task(self, mock_sleep, salt_api_async):
 | 
				
			||||||
        # test 64bit golang agent
 | 
					        # test 64bit golang agent
 | 
				
			||||||
@@ -888,4 +953,4 @@ class TestAgentTasks(TacticalTestCase):
 | 
				
			|||||||
                "url": OLD_32_PY_AGENT,
 | 
					                "url": OLD_32_PY_AGENT,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertEqual(ret.status, "SUCCESS")
 | 
					        self.assertEqual(ret.status, "SUCCESS") """
 | 
				
			||||||
@@ -38,7 +38,6 @@ class Client(BaseAuditModel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def has_failing_checks(self):
 | 
					    def has_failing_checks(self):
 | 
				
			||||||
 | 
					 | 
				
			||||||
        agents = (
 | 
					        agents = (
 | 
				
			||||||
            Agent.objects.only(
 | 
					            Agent.objects.only(
 | 
				
			||||||
                "pk",
 | 
					                "pk",
 | 
				
			||||||
@@ -50,14 +49,17 @@ class Client(BaseAuditModel):
 | 
				
			|||||||
            .filter(site__client=self)
 | 
					            .filter(site__client=self)
 | 
				
			||||||
            .prefetch_related("agentchecks")
 | 
					            .prefetch_related("agentchecks")
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        failing = 0
 | 
				
			||||||
        for agent in agents:
 | 
					        for agent in agents:
 | 
				
			||||||
            if agent.checks["has_failing_checks"]:
 | 
					            if agent.checks["has_failing_checks"]:
 | 
				
			||||||
                return True
 | 
					                failing += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if agent.overdue_email_alert or agent.overdue_text_alert:
 | 
					            if agent.overdue_email_alert or agent.overdue_text_alert:
 | 
				
			||||||
                return agent.status == "overdue"
 | 
					                if agent.status == "overdue":
 | 
				
			||||||
 | 
					                    failing += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return False
 | 
					        return failing > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def serialize(client):
 | 
					    def serialize(client):
 | 
				
			||||||
@@ -98,7 +100,6 @@ class Site(BaseAuditModel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def has_failing_checks(self):
 | 
					    def has_failing_checks(self):
 | 
				
			||||||
 | 
					 | 
				
			||||||
        agents = (
 | 
					        agents = (
 | 
				
			||||||
            Agent.objects.only(
 | 
					            Agent.objects.only(
 | 
				
			||||||
                "pk",
 | 
					                "pk",
 | 
				
			||||||
@@ -110,14 +111,17 @@ class Site(BaseAuditModel):
 | 
				
			|||||||
            .filter(site=self)
 | 
					            .filter(site=self)
 | 
				
			||||||
            .prefetch_related("agentchecks")
 | 
					            .prefetch_related("agentchecks")
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        failing = 0
 | 
				
			||||||
        for agent in agents:
 | 
					        for agent in agents:
 | 
				
			||||||
            if agent.checks["has_failing_checks"]:
 | 
					            if agent.checks["has_failing_checks"]:
 | 
				
			||||||
                return True
 | 
					                failing += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if agent.overdue_email_alert or agent.overdue_text_alert:
 | 
					            if agent.overdue_email_alert or agent.overdue_text_alert:
 | 
				
			||||||
                return agent.status == "overdue"
 | 
					                if agent.status == "overdue":
 | 
				
			||||||
 | 
					                    failing += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return False
 | 
					        return failing > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def serialize(site):
 | 
					    def serialize(site):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,6 +58,7 @@ func main() {
 | 
				
			|||||||
	debugLog := flag.String("log", "", "Verbose output")
 | 
						debugLog := flag.String("log", "", "Verbose output")
 | 
				
			||||||
	localMesh := flag.String("local-mesh", "", "Use local mesh agent")
 | 
						localMesh := flag.String("local-mesh", "", "Use local mesh agent")
 | 
				
			||||||
	noSalt := flag.Bool("nosalt", false, "Does not install salt")
 | 
						noSalt := flag.Bool("nosalt", false, "Does not install salt")
 | 
				
			||||||
 | 
						silent := flag.Bool("silent", false, "Do not popup any message boxes during installation")
 | 
				
			||||||
	cert := flag.String("cert", "", "Path to ca.pem")
 | 
						cert := flag.String("cert", "", "Path to ca.pem")
 | 
				
			||||||
	timeout := flag.String("timeout", "", "Timeout for subprocess calls")
 | 
						timeout := flag.String("timeout", "", "Timeout for subprocess calls")
 | 
				
			||||||
	flag.Parse()
 | 
						flag.Parse()
 | 
				
			||||||
@@ -78,7 +79,11 @@ func main() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if debug {
 | 
						if debug {
 | 
				
			||||||
		cmdArgs = append(cmdArgs, "--log", "DEBUG")
 | 
							cmdArgs = append(cmdArgs, "-log", "debug")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if *silent {
 | 
				
			||||||
 | 
							cmdArgs = append(cmdArgs, "-silent")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if *noSalt {
 | 
						if *noSalt {
 | 
				
			||||||
@@ -86,27 +91,27 @@ func main() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(strings.TrimSpace(*localMesh)) != 0 {
 | 
						if len(strings.TrimSpace(*localMesh)) != 0 {
 | 
				
			||||||
		cmdArgs = append(cmdArgs, "--local-mesh", *localMesh)
 | 
							cmdArgs = append(cmdArgs, "-local-mesh", *localMesh)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(strings.TrimSpace(*cert)) != 0 {
 | 
						if len(strings.TrimSpace(*cert)) != 0 {
 | 
				
			||||||
		cmdArgs = append(cmdArgs, "--cert", *cert)
 | 
							cmdArgs = append(cmdArgs, "-cert", *cert)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(strings.TrimSpace(*timeout)) != 0 {
 | 
						if len(strings.TrimSpace(*timeout)) != 0 {
 | 
				
			||||||
		cmdArgs = append(cmdArgs, "--timeout", *timeout)
 | 
							cmdArgs = append(cmdArgs, "-timeout", *timeout)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if Rdp == "1" {
 | 
						if Rdp == "1" {
 | 
				
			||||||
		cmdArgs = append(cmdArgs, "--rdp")
 | 
							cmdArgs = append(cmdArgs, "-rdp")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if Ping == "1" {
 | 
						if Ping == "1" {
 | 
				
			||||||
		cmdArgs = append(cmdArgs, "--ping")
 | 
							cmdArgs = append(cmdArgs, "-ping")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if Power == "1" {
 | 
						if Power == "1" {
 | 
				
			||||||
		cmdArgs = append(cmdArgs, "--power")
 | 
							cmdArgs = append(cmdArgs, "-power")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if debug {
 | 
						if debug {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,17 +15,17 @@ EXE_DIR = os.path.join(BASE_DIR, "tacticalrmm/private/exe")
 | 
				
			|||||||
AUTH_USER_MODEL = "accounts.User"
 | 
					AUTH_USER_MODEL = "accounts.User"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# latest release
 | 
					# latest release
 | 
				
			||||||
TRMM_VERSION = "0.2.9"
 | 
					TRMM_VERSION = "0.2.12"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# bump this version everytime vue code is changed
 | 
					# bump this version everytime vue code is changed
 | 
				
			||||||
# to alert user they need to manually refresh their browser
 | 
					# to alert user they need to manually refresh their browser
 | 
				
			||||||
APP_VER = "0.0.98"
 | 
					APP_VER = "0.0.99"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# https://github.com/wh1te909/salt
 | 
					# https://github.com/wh1te909/salt
 | 
				
			||||||
LATEST_SALT_VER = "1.1.0"
 | 
					LATEST_SALT_VER = "1.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# https://github.com/wh1te909/rmmagent
 | 
					# https://github.com/wh1te909/rmmagent
 | 
				
			||||||
LATEST_AGENT_VER = "1.1.4"
 | 
					LATEST_AGENT_VER = "1.1.7"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MESH_VER = "0.7.14"
 | 
					MESH_VER = "0.7.14"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SCRIPT_VERSION="4"
 | 
					SCRIPT_VERSION="5"
 | 
				
			||||||
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/backup.sh'
 | 
					SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/backup.sh'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GREEN='\033[0;32m'
 | 
					GREEN='\033[0;32m'
 | 
				
			||||||
@@ -50,6 +50,11 @@ if [ -d /meshcentral/meshcentral-coredumps ]; then
 | 
				
			|||||||
    rm -f /meshcentral/meshcentral-coredumps/*
 | 
					    rm -f /meshcentral/meshcentral-coredumps/*
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					printf >&2 "${GREEN}Running postgres vacuum${NC}\n"
 | 
				
			||||||
 | 
					sudo -u postgres psql -d tacticalrmm -c "vacuum full logs_auditlog"
 | 
				
			||||||
 | 
					sudo -u postgres psql -d tacticalrmm -c "vacuum full logs_pendingaction"
 | 
				
			||||||
 | 
					sudo -u postgres psql -d tacticalrmm -c "vacuum full agents_agentoutage"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dt_now=$(date '+%Y_%m_%d__%H_%M_%S')
 | 
					dt_now=$(date '+%Y_%m_%d__%H_%M_%S')
 | 
				
			||||||
tmp_dir=$(mktemp -d -t tacticalrmm-XXXXXXXXXXXXXXXXXXXXX)
 | 
					tmp_dir=$(mktemp -d -t tacticalrmm-XXXXXXXXXXXXXXXXXXXXX)
 | 
				
			||||||
sysd="/etc/systemd/system"
 | 
					sysd="/etc/systemd/system"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SCRIPT_VERSION="99"
 | 
					SCRIPT_VERSION="100"
 | 
				
			||||||
SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/update.sh'
 | 
					SCRIPT_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/update.sh'
 | 
				
			||||||
LATEST_SETTINGS_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/api/tacticalrmm/tacticalrmm/settings.py'
 | 
					LATEST_SETTINGS_URL='https://raw.githubusercontent.com/wh1te909/tacticalrmm/master/api/tacticalrmm/tacticalrmm/settings.py'
 | 
				
			||||||
YELLOW='\033[1;33m'
 | 
					YELLOW='\033[1;33m'
 | 
				
			||||||
@@ -177,6 +177,11 @@ sudo cp /rmm/api/tacticalrmm/core/goinstaller/bin/goversioninfo /usr/local/bin/
 | 
				
			|||||||
sudo chown ${USER}:${USER} /usr/local/bin/goversioninfo
 | 
					sudo chown ${USER}:${USER} /usr/local/bin/goversioninfo
 | 
				
			||||||
sudo chmod +x /usr/local/bin/goversioninfo
 | 
					sudo chmod +x /usr/local/bin/goversioninfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					printf >&2 "${GREEN}Running postgres vacuum${NC}\n"
 | 
				
			||||||
 | 
					sudo -u postgres psql -d tacticalrmm -c "vacuum full logs_auditlog"
 | 
				
			||||||
 | 
					sudo -u postgres psql -d tacticalrmm -c "vacuum full logs_pendingaction"
 | 
				
			||||||
 | 
					sudo -u postgres psql -d tacticalrmm -c "vacuum full agents_agentoutage"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [[ "${CURRENT_PIP_VER}" != "${LATEST_PIP_VER}" ]]; then
 | 
					if [[ "${CURRENT_PIP_VER}" != "${LATEST_PIP_VER}" ]]; then
 | 
				
			||||||
  rm -rf /rmm/api/env
 | 
					  rm -rf /rmm/api/env
 | 
				
			||||||
  cd /rmm/api
 | 
					  cd /rmm/api
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,19 +26,25 @@
 | 
				
			|||||||
      >
 | 
					      >
 | 
				
			||||||
        <div class="q-pa-xs q-gutter-xs">
 | 
					        <div class="q-pa-xs q-gutter-xs">
 | 
				
			||||||
          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
					          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
				
			||||||
            <code>--log DEBUG</code>
 | 
					            <code>-log debug</code>
 | 
				
			||||||
          </q-badge>
 | 
					          </q-badge>
 | 
				
			||||||
          <span>To enable verbose output during the install</span>
 | 
					          <span>To enable verbose output during the install</span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="q-pa-xs q-gutter-xs">
 | 
					        <div class="q-pa-xs q-gutter-xs">
 | 
				
			||||||
          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
					          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
				
			||||||
            <code>--nosalt</code>
 | 
					            <code>-silent</code>
 | 
				
			||||||
 | 
					          </q-badge>
 | 
				
			||||||
 | 
					          <span>Do not popup any message boxes during install</span>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="q-pa-xs q-gutter-xs">
 | 
				
			||||||
 | 
					          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
				
			||||||
 | 
					            <code>-nosalt</code>
 | 
				
			||||||
          </q-badge>
 | 
					          </q-badge>
 | 
				
			||||||
          <span> Do not install salt during agent install. </span>
 | 
					          <span> Do not install salt during agent install. </span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="q-pa-xs q-gutter-xs">
 | 
					        <div class="q-pa-xs q-gutter-xs">
 | 
				
			||||||
          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
					          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
				
			||||||
            <code>--local-mesh "C:\\<some folder or path>\\meshagent.exe"</code>
 | 
					            <code>-local-mesh "C:\\<some folder or path>\\meshagent.exe"</code>
 | 
				
			||||||
          </q-badge>
 | 
					          </q-badge>
 | 
				
			||||||
          <span>
 | 
					          <span>
 | 
				
			||||||
            To skip downloading the Mesh Agent during the install. Download it
 | 
					            To skip downloading the Mesh Agent during the install. Download it
 | 
				
			||||||
@@ -49,7 +55,7 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="q-pa-xs q-gutter-xs">
 | 
					        <div class="q-pa-xs q-gutter-xs">
 | 
				
			||||||
          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
					          <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
 | 
				
			||||||
            <code>--cert "C:\\<some folder or path>\\ca.pem"</code>
 | 
					            <code>-cert "C:\\<some folder or path>\\ca.pem"</code>
 | 
				
			||||||
          </q-badge>
 | 
					          </q-badge>
 | 
				
			||||||
          <span> To use a domain CA </span>
 | 
					          <span> To use a domain CA </span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user