Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b3cec06b3 | ||
|
|
8536754d14 | ||
|
|
1f36235801 | ||
|
|
a4194b14f9 | ||
|
|
2dcc629d9d | ||
|
|
98ddadc6bc | ||
|
|
f6e47b7383 | ||
|
|
f073ddc906 | ||
|
|
3e00631925 |
@@ -1,3 +1,4 @@
|
|||||||
|
import asyncio
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from time import sleep
|
from time import sleep
|
||||||
import random
|
import random
|
||||||
@@ -54,6 +55,14 @@ def send_agent_update_task(pks, version):
|
|||||||
if agent.pendingactions.filter(
|
if agent.pendingactions.filter(
|
||||||
action_type="agentupdate", status="pending"
|
action_type="agentupdate", status="pending"
|
||||||
).exists():
|
).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
|
continue
|
||||||
|
|
||||||
PendingAction.objects.create(
|
PendingAction.objects.create(
|
||||||
@@ -122,6 +131,14 @@ def auto_self_agent_update_task():
|
|||||||
if agent.pendingactions.filter(
|
if agent.pendingactions.filter(
|
||||||
action_type="agentupdate", status="pending"
|
action_type="agentupdate", status="pending"
|
||||||
).exists():
|
).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
|
continue
|
||||||
|
|
||||||
PendingAction.objects.create(
|
PendingAction.objects.create(
|
||||||
@@ -146,6 +163,18 @@ def auto_self_agent_update_task():
|
|||||||
sleep(5)
|
sleep(5)
|
||||||
|
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def sync_sysinfo_task():
|
||||||
|
agents = Agent.objects.all()
|
||||||
|
online = [
|
||||||
|
i
|
||||||
|
for i in agents
|
||||||
|
if pyver.parse(i.version) >= pyver.parse("1.1.3") and i.status == "online"
|
||||||
|
]
|
||||||
|
for agent in online:
|
||||||
|
asyncio.run(agent.nats_cmd({"func": "sync"}, wait=False))
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def sync_salt_modules_task(pk):
|
def sync_salt_modules_task(pk):
|
||||||
agent = Agent.objects.get(pk=pk)
|
agent = Agent.objects.get(pk=pk)
|
||||||
|
|||||||
@@ -9,21 +9,6 @@ class TestServiceViews(TacticalTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.authenticate()
|
self.authenticate()
|
||||||
|
|
||||||
def test_get_services(self):
|
|
||||||
|
|
||||||
# test a call where agent doesn't exist
|
|
||||||
resp = self.client.get("/services/500/services/", format="json")
|
|
||||||
self.assertEqual(resp.status_code, 404)
|
|
||||||
|
|
||||||
agent = baker.make_recipe("agents.agent_with_services")
|
|
||||||
url = f"/services/{agent.pk}/services/"
|
|
||||||
serializer = ServicesSerializer(agent)
|
|
||||||
resp = self.client.get(url, format="json")
|
|
||||||
self.assertEqual(resp.status_code, 200)
|
|
||||||
self.assertEqual(serializer.data, resp.data)
|
|
||||||
|
|
||||||
self.check_not_authenticated("get", url)
|
|
||||||
|
|
||||||
def test_default_services(self):
|
def test_default_services(self):
|
||||||
url = "/services/defaultservices/"
|
url = "/services/defaultservices/"
|
||||||
resp = self.client.get(url, format="json")
|
resp = self.client.get(url, format="json")
|
||||||
@@ -33,13 +18,13 @@ class TestServiceViews(TacticalTestCase):
|
|||||||
self.check_not_authenticated("get", url)
|
self.check_not_authenticated("get", url)
|
||||||
|
|
||||||
@patch("agents.models.Agent.nats_cmd")
|
@patch("agents.models.Agent.nats_cmd")
|
||||||
def test_get_refreshed_services(self, nats_cmd):
|
def test_get_services(self, nats_cmd):
|
||||||
# test a call where agent doesn't exist
|
# test a call where agent doesn't exist
|
||||||
resp = self.client.get("/services/500/refreshedservices/", format="json")
|
resp = self.client.get("/services/500/services/", format="json")
|
||||||
self.assertEqual(resp.status_code, 404)
|
self.assertEqual(resp.status_code, 404)
|
||||||
|
|
||||||
agent = baker.make_recipe("agents.agent_with_services")
|
agent = baker.make_recipe("agents.agent_with_services")
|
||||||
url = f"/services/{agent.pk}/refreshedservices/"
|
url = f"/services/{agent.pk}/services/"
|
||||||
|
|
||||||
nats_return = [
|
nats_return = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ from . import views
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("<int:pk>/services/", views.get_services),
|
path("<int:pk>/services/", views.get_services),
|
||||||
path("defaultservices/", views.default_services),
|
path("defaultservices/", views.default_services),
|
||||||
path("<int:pk>/refreshedservices/", views.get_refreshed_services),
|
|
||||||
path("serviceaction/", views.service_action),
|
path("serviceaction/", views.service_action),
|
||||||
path("<int:pk>/<svcname>/servicedetail/", views.service_detail),
|
path("<int:pk>/<svcname>/servicedetail/", views.service_detail),
|
||||||
path("editservice/", views.edit_service),
|
path("editservice/", views.edit_service),
|
||||||
|
|||||||
@@ -19,17 +19,6 @@ logger.configure(**settings.LOG_CONFIG)
|
|||||||
|
|
||||||
@api_view()
|
@api_view()
|
||||||
def get_services(request, pk):
|
def get_services(request, pk):
|
||||||
agent = get_object_or_404(Agent, pk=pk)
|
|
||||||
return Response(ServicesSerializer(agent).data)
|
|
||||||
|
|
||||||
|
|
||||||
@api_view()
|
|
||||||
def default_services(request):
|
|
||||||
return Response(Check.load_default_services())
|
|
||||||
|
|
||||||
|
|
||||||
@api_view()
|
|
||||||
def get_refreshed_services(request, pk):
|
|
||||||
agent = get_object_or_404(Agent, pk=pk)
|
agent = get_object_or_404(Agent, pk=pk)
|
||||||
if not agent.has_nats:
|
if not agent.has_nats:
|
||||||
return notify_error("Requires agent version 1.1.0 or greater")
|
return notify_error("Requires agent version 1.1.0 or greater")
|
||||||
@@ -43,6 +32,11 @@ def get_refreshed_services(request, pk):
|
|||||||
return Response(ServicesSerializer(agent).data)
|
return Response(ServicesSerializer(agent).data)
|
||||||
|
|
||||||
|
|
||||||
|
@api_view()
|
||||||
|
def default_services(request):
|
||||||
|
return Response(Check.load_default_services())
|
||||||
|
|
||||||
|
|
||||||
@api_view(["POST"])
|
@api_view(["POST"])
|
||||||
def service_action(request):
|
def service_action(request):
|
||||||
agent = get_object_or_404(Agent, pk=request.data["pk"])
|
agent = get_object_or_404(Agent, pk=request.data["pk"])
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ app.conf.beat_schedule = {
|
|||||||
"task": "agents.tasks.auto_self_agent_update_task",
|
"task": "agents.tasks.auto_self_agent_update_task",
|
||||||
"schedule": crontab(minute=35, hour="*"),
|
"schedule": crontab(minute=35, hour="*"),
|
||||||
},
|
},
|
||||||
|
"agents-sync": {
|
||||||
|
"task": "agents.tasks.sync_sysinfo_task",
|
||||||
|
"schedule": crontab(minute=55, hour="*"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ EXCLUDE_PATHS = (
|
|||||||
"/logs/downloadlog",
|
"/logs/downloadlog",
|
||||||
)
|
)
|
||||||
|
|
||||||
ENDS_WITH = "/refreshedservices/"
|
ENDS_WITH = "/services/"
|
||||||
|
|
||||||
|
|
||||||
class AuditMiddleware:
|
class AuditMiddleware:
|
||||||
|
|||||||
@@ -15,19 +15,19 @@ 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.6"
|
TRMM_VERSION = "0.2.9"
|
||||||
|
|
||||||
# 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.96"
|
APP_VER = "0.0.98"
|
||||||
|
|
||||||
# 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.2"
|
LATEST_AGENT_VER = "1.1.4"
|
||||||
|
|
||||||
MESH_VER = "0.7.10"
|
MESH_VER = "0.7.14"
|
||||||
|
|
||||||
SALT_MASTER_VER = "3002.2"
|
SALT_MASTER_VER = "3002.2"
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
hide-bottom
|
hide-bottom
|
||||||
>
|
>
|
||||||
<template v-slot:top>
|
<template v-slot:top>
|
||||||
<q-btn dense flat push @click="refreshServices" icon="refresh" />
|
<q-btn dense flat push @click="getServices" icon="refresh" />
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-input v-model="filter" outlined label="Search" dense clearable>
|
<q-input v-model="filter" outlined label="Search" dense clearable>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
@@ -242,7 +242,7 @@ export default {
|
|||||||
.then(r => {
|
.then(r => {
|
||||||
this.serviceDetailVisible = false;
|
this.serviceDetailVisible = false;
|
||||||
this.serviceDetailsModal = false;
|
this.serviceDetailsModal = false;
|
||||||
this.refreshServices();
|
this.getServices();
|
||||||
this.notifySuccess(`Service ${name} was edited!`);
|
this.notifySuccess(`Service ${name} was edited!`);
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
@@ -303,7 +303,7 @@ export default {
|
|||||||
this.$axios
|
this.$axios
|
||||||
.post("/services/serviceaction/", data)
|
.post("/services/serviceaction/", data)
|
||||||
.then(r => {
|
.then(r => {
|
||||||
this.refreshServices();
|
this.getServices();
|
||||||
this.serviceDetailsModal = false;
|
this.serviceDetailsModal = false;
|
||||||
this.notifySuccess(`Service ${fullname} was ${status}!`);
|
this.notifySuccess(`Service ${fullname} was ${status}!`);
|
||||||
})
|
})
|
||||||
@@ -313,19 +313,9 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
getServices() {
|
getServices() {
|
||||||
|
this.$q.loading.show({ message: "Loading services..." });
|
||||||
this.$axios
|
this.$axios
|
||||||
.get(`/services/${this.pk}/services/`)
|
.get(`/services/${this.pk}/services/`)
|
||||||
.then(r => {
|
|
||||||
this.servicesData = [r.data][0].services;
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
this.notifyError(e.response.data);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
refreshServices() {
|
|
||||||
this.$q.loading.show({ message: "Reloading services..." });
|
|
||||||
this.$axios
|
|
||||||
.get(`/services/${this.pk}/refreshedservices/`)
|
|
||||||
.then(r => {
|
.then(r => {
|
||||||
this.servicesData = [r.data][0].services;
|
this.servicesData = [r.data][0].services;
|
||||||
this.$q.loading.hide();
|
this.$q.loading.hide();
|
||||||
|
|||||||
@@ -27,10 +27,13 @@
|
|||||||
<p>Fix issues with the Tactical Checkrunner windows service which handles running all checks.</p>
|
<p>Fix issues with the Tactical Checkrunner windows service which handles running all checks.</p>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section v-show="mode === 'salt'">
|
<q-card-section v-show="mode === 'salt'">
|
||||||
<p>Fix issues with the salt-minion which handles windows updates, chocolatey and scheduled tasks.</p>
|
<p>Fix issues with the salt-minion which handles windows updates and chocolatey.</p>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section v-show="mode === 'rpc'">
|
<q-card-section v-show="mode === 'rpc'">
|
||||||
<p>Fix issues with the Tactical RPC service which handles most of the agent's realtime functions.</p>
|
<p>
|
||||||
|
Fix issues with the Tactical RPC service which handles most of the agent's realtime functions and scheduled
|
||||||
|
tasks.
|
||||||
|
</p>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section v-show="mode === 'command'">
|
<q-card-section v-show="mode === 'command'">
|
||||||
<p>Run a shell command on the agent.</p>
|
<p>Run a shell command on the agent.</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user