Release 0.4.5
This commit is contained in:
@@ -75,13 +75,8 @@ def agent_update(pk: int) -> str:
|
|||||||
|
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def send_agent_update_task(pks: List[int], version: str) -> None:
|
def send_agent_update_task(pks: List[int]) -> None:
|
||||||
q = Agent.objects.filter(pk__in=pks)
|
chunks = (pks[i : i + 30] for i in range(0, len(pks), 30))
|
||||||
agents = [i.pk for i in q]
|
|
||||||
""" 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 chunk in chunks:
|
for chunk in chunks:
|
||||||
for pk in chunk:
|
for pk in chunk:
|
||||||
agent_update(pk)
|
agent_update(pk)
|
||||||
|
|||||||
@@ -4,16 +4,19 @@ from unittest.mock import patch
|
|||||||
|
|
||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
from itertools import cycle
|
from itertools import cycle
|
||||||
|
from typing import List
|
||||||
|
from packaging import version as pyver
|
||||||
|
|
||||||
|
|
||||||
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 logs.models import PendingAction
|
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 auto_self_agent_update_task
|
||||||
from winupdate.models import WinUpdatePolicy
|
from winupdate.models import WinUpdatePolicy
|
||||||
|
|
||||||
|
|
||||||
@@ -64,12 +67,34 @@ class TestAgentViews(TacticalTestCase):
|
|||||||
@patch("agents.tasks.send_agent_update_task.delay")
|
@patch("agents.tasks.send_agent_update_task.delay")
|
||||||
def test_update_agents(self, mock_task):
|
def test_update_agents(self, mock_task):
|
||||||
url = "/agents/updateagents/"
|
url = "/agents/updateagents/"
|
||||||
data = {"pks": [1, 2, 3, 5, 10], "version": "0.11.1"}
|
baker.make_recipe(
|
||||||
|
"agents.agent",
|
||||||
|
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||||
|
version=settings.LATEST_AGENT_VER,
|
||||||
|
_quantity=15,
|
||||||
|
)
|
||||||
|
baker.make_recipe(
|
||||||
|
"agents.agent",
|
||||||
|
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||||
|
version="1.3.0",
|
||||||
|
_quantity=15,
|
||||||
|
)
|
||||||
|
|
||||||
|
pks: List[int] = list(
|
||||||
|
Agent.objects.only("pk", "version").values_list("pk", flat=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
data = {"pks": pks}
|
||||||
|
expected: List[int] = [
|
||||||
|
i.pk
|
||||||
|
for i in Agent.objects.only("pk", "version")
|
||||||
|
if pyver.parse(i.version) < pyver.parse(settings.LATEST_AGENT_VER)
|
||||||
|
]
|
||||||
|
|
||||||
r = self.client.post(url, data, format="json")
|
r = self.client.post(url, data, format="json")
|
||||||
self.assertEqual(r.status_code, 200)
|
self.assertEqual(r.status_code, 200)
|
||||||
|
|
||||||
mock_task.assert_called_with(pks=data["pks"], version=data["version"])
|
mock_task.assert_called_with(pks=expected)
|
||||||
|
|
||||||
self.check_not_authenticated("post", url)
|
self.check_not_authenticated("post", url)
|
||||||
|
|
||||||
@@ -827,107 +852,30 @@ class TestAgentTasks(TacticalTestCase):
|
|||||||
self.assertEqual(action.action_type, "agentupdate")
|
self.assertEqual(action.action_type, "agentupdate")
|
||||||
self.assertEqual(action.status, "pending")
|
self.assertEqual(action.status, "pending")
|
||||||
|
|
||||||
""" @patch("agents.models.Agent.salt_api_async")
|
@patch("agents.tasks.agent_update")
|
||||||
@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, agent_update):
|
||||||
# test 64bit golang agent
|
baker.make_recipe(
|
||||||
self.agent64 = baker.make_recipe(
|
|
||||||
"agents.agent",
|
"agents.agent",
|
||||||
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||||
version="1.0.0",
|
version=settings.LATEST_AGENT_VER,
|
||||||
|
_quantity=23,
|
||||||
)
|
)
|
||||||
salt_api_async.return_value = True
|
baker.make_recipe(
|
||||||
ret = auto_self_agent_update_task.s().apply()
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(ret.status, "SUCCESS")
|
|
||||||
self.agent64.delete()
|
|
||||||
salt_api_async.reset_mock()
|
|
||||||
|
|
||||||
# test 32bit golang agent
|
|
||||||
self.agent32 = baker.make_recipe(
|
|
||||||
"agents.agent",
|
|
||||||
operating_system="Windows 7 Professional, 32 bit (build 7601.24544)",
|
|
||||||
version="1.0.0",
|
|
||||||
)
|
|
||||||
salt_api_async.return_value = True
|
|
||||||
ret = auto_self_agent_update_task.s().apply()
|
|
||||||
salt_api_async.assert_called_with(
|
|
||||||
func="win_agent.do_agent_update_v2",
|
|
||||||
kwargs={
|
|
||||||
"inno": f"winagent-v{settings.LATEST_AGENT_VER}-x86.exe",
|
|
||||||
"url": settings.DL_32,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(ret.status, "SUCCESS")
|
|
||||||
self.agent32.delete()
|
|
||||||
salt_api_async.reset_mock()
|
|
||||||
|
|
||||||
# test agent that has a null os field
|
|
||||||
self.agentNone = baker.make_recipe(
|
|
||||||
"agents.agent",
|
|
||||||
operating_system=None,
|
|
||||||
version="1.0.0",
|
|
||||||
)
|
|
||||||
ret = auto_self_agent_update_task.s().apply()
|
|
||||||
salt_api_async.assert_not_called()
|
|
||||||
self.agentNone.delete()
|
|
||||||
salt_api_async.reset_mock()
|
|
||||||
|
|
||||||
# test auto update disabled in global settings
|
|
||||||
self.agent64 = baker.make_recipe(
|
|
||||||
"agents.agent",
|
"agents.agent",
|
||||||
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||||
version="1.0.0",
|
version="1.3.0",
|
||||||
|
_quantity=33,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.coresettings.agent_auto_update = False
|
self.coresettings.agent_auto_update = False
|
||||||
self.coresettings.save(update_fields=["agent_auto_update"])
|
self.coresettings.save(update_fields=["agent_auto_update"])
|
||||||
ret = auto_self_agent_update_task.s().apply()
|
|
||||||
salt_api_async.assert_not_called()
|
|
||||||
|
|
||||||
# reset core settings
|
r = auto_self_agent_update_task.s().apply()
|
||||||
self.agent64.delete()
|
self.assertEqual(agent_update.call_count, 0)
|
||||||
salt_api_async.reset_mock()
|
|
||||||
self.coresettings.agent_auto_update = True
|
self.coresettings.agent_auto_update = True
|
||||||
self.coresettings.save(update_fields=["agent_auto_update"])
|
self.coresettings.save(update_fields=["agent_auto_update"])
|
||||||
|
|
||||||
# test 64bit python agent
|
r = auto_self_agent_update_task.s().apply()
|
||||||
self.agent64py = baker.make_recipe(
|
self.assertEqual(agent_update.call_count, 33)
|
||||||
"agents.agent",
|
|
||||||
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
|
||||||
version="0.11.1",
|
|
||||||
)
|
|
||||||
salt_api_async.return_value = True
|
|
||||||
ret = auto_self_agent_update_task.s().apply()
|
|
||||||
salt_api_async.assert_called_with(
|
|
||||||
func="win_agent.do_agent_update_v2",
|
|
||||||
kwargs={
|
|
||||||
"inno": "winagent-v0.11.2.exe",
|
|
||||||
"url": OLD_64_PY_AGENT,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(ret.status, "SUCCESS")
|
|
||||||
self.agent64py.delete()
|
|
||||||
salt_api_async.reset_mock()
|
|
||||||
|
|
||||||
# test 32bit python agent
|
|
||||||
self.agent32py = baker.make_recipe(
|
|
||||||
"agents.agent",
|
|
||||||
operating_system="Windows 7 Professional, 32 bit (build 7601.24544)",
|
|
||||||
version="0.11.1",
|
|
||||||
)
|
|
||||||
salt_api_async.return_value = True
|
|
||||||
ret = auto_self_agent_update_task.s().apply()
|
|
||||||
salt_api_async.assert_called_with(
|
|
||||||
func="win_agent.do_agent_update_v2",
|
|
||||||
kwargs={
|
|
||||||
"inno": "winagent-v0.11.2-x86.exe",
|
|
||||||
"url": OLD_32_PY_AGENT,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(ret.status, "SUCCESS") """
|
|
||||||
|
|||||||
@@ -59,9 +59,13 @@ def get_agent_versions(request):
|
|||||||
|
|
||||||
@api_view(["POST"])
|
@api_view(["POST"])
|
||||||
def update_agents(request):
|
def update_agents(request):
|
||||||
pks = request.data["pks"]
|
q = Agent.objects.filter(pk__in=request.data["pks"]).only("pk", "version")
|
||||||
version = request.data["version"]
|
pks: List[int] = [
|
||||||
send_agent_update_task.delay(pks=pks, version=version)
|
i.pk
|
||||||
|
for i in q
|
||||||
|
if pyver.parse(i.version) < pyver.parse(settings.LATEST_AGENT_VER)
|
||||||
|
]
|
||||||
|
send_agent_update_task.delay(pks=pks)
|
||||||
return Response("ok")
|
return Response("ok")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ 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.4.4"
|
TRMM_VERSION = "0.4.5"
|
||||||
|
|
||||||
# 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.109"
|
APP_VER = "0.0.110"
|
||||||
|
|
||||||
# https://github.com/wh1te909/rmmagent
|
# https://github.com/wh1te909/rmmagent
|
||||||
LATEST_AGENT_VER = "1.4.2"
|
LATEST_AGENT_VER = "1.4.2"
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from "axios";
|
|
||||||
import mixins from "@/mixins/mixins";
|
import mixins from "@/mixins/mixins";
|
||||||
export default {
|
export default {
|
||||||
name: "UpdateAgents",
|
name: "UpdateAgents",
|
||||||
@@ -58,7 +57,7 @@ export default {
|
|||||||
},
|
},
|
||||||
getVersions() {
|
getVersions() {
|
||||||
this.$q.loading.show();
|
this.$q.loading.show();
|
||||||
axios
|
this.$axios
|
||||||
.get("/agents/getagentversions/")
|
.get("/agents/getagentversions/")
|
||||||
.then(r => {
|
.then(r => {
|
||||||
this.versions = r.data.versions;
|
this.versions = r.data.versions;
|
||||||
@@ -72,8 +71,8 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
update() {
|
update() {
|
||||||
const data = { version: this.version, pks: this.group };
|
const data = { pks: this.group };
|
||||||
axios
|
this.$axios
|
||||||
.post("/agents/updateagents/", data)
|
.post("/agents/updateagents/", data)
|
||||||
.then(r => {
|
.then(r => {
|
||||||
this.$emit("close");
|
this.$emit("close");
|
||||||
|
|||||||
Reference in New Issue
Block a user