Release 0.19.4
This commit is contained in:
commit
59c880dc36
|
@ -39,7 +39,7 @@ Demo database resets every hour. A lot of features are disabled for obvious reas
|
|||
|
||||
## Mac agent versions supported
|
||||
|
||||
- 64 bit Intel and Apple Silicon (M1, M2)
|
||||
- 64 bit Intel and Apple Silicon (M-Series)
|
||||
|
||||
## Installation / Backup / Restore / Usage
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.2.16 on 2024-10-06 05:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("accounts", "0037_role_can_run_server_scripts_role_can_use_webterm"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="role",
|
||||
name="can_edit_global_keystore",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="role",
|
||||
name="can_view_global_keystore",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
|
@ -131,6 +131,8 @@ class Role(BaseAuditModel):
|
|||
can_manage_customfields = models.BooleanField(default=False)
|
||||
can_run_server_scripts = models.BooleanField(default=False)
|
||||
can_use_webterm = models.BooleanField(default=False)
|
||||
can_view_global_keystore = models.BooleanField(default=False)
|
||||
can_edit_global_keystore = models.BooleanField(default=False)
|
||||
|
||||
# checks
|
||||
can_list_checks = models.BooleanField(default=False)
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# Generated by Django 4.2.16 on 2024-10-05 20:39
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0047_alter_coresettings_notify_on_warning_alerts"),
|
||||
("agents", "0059_alter_agenthistory_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="agenthistory",
|
||||
name="collector_all_output",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="agenthistory",
|
||||
name="custom_field",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="history",
|
||||
to="core.customfield",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="agenthistory",
|
||||
name="save_to_agent_note",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
|
@ -1122,6 +1122,15 @@ class AgentHistory(models.Model):
|
|||
on_delete=models.SET_NULL,
|
||||
)
|
||||
script_results = models.JSONField(null=True, blank=True)
|
||||
custom_field = models.ForeignKey(
|
||||
"core.CustomField",
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="history",
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
collector_all_output = models.BooleanField(default=False)
|
||||
save_to_agent_note = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.agent.hostname} - {self.type}"
|
||||
|
|
|
@ -2,7 +2,7 @@ import json
|
|||
import os
|
||||
from itertools import cycle
|
||||
from typing import TYPE_CHECKING
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import PropertyMock, patch
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from django.conf import settings
|
||||
|
@ -768,6 +768,67 @@ class TestAgentViews(TacticalTestCase):
|
|||
|
||||
self.assertEqual(Note.objects.get(agent=self.agent).note, "ok")
|
||||
|
||||
# test run on server
|
||||
with patch("core.utils.run_server_script") as mock_run_server_script:
|
||||
mock_run_server_script.return_value = ("output", "error", 1.23456789, 0)
|
||||
data = {
|
||||
"script": script.pk,
|
||||
"output": "wait",
|
||||
"args": ["arg1", "arg2"],
|
||||
"timeout": 15,
|
||||
"run_as_user": False,
|
||||
"env_vars": ["key1=val1", "key2=val2"],
|
||||
"run_on_server": True,
|
||||
}
|
||||
|
||||
r = self.client.post(url, data, format="json")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
hist = AgentHistory.objects.filter(agent=self.agent, script=script).last()
|
||||
if not hist:
|
||||
raise AgentHistory.DoesNotExist
|
||||
|
||||
mock_run_server_script.assert_called_with(
|
||||
body=script.script_body,
|
||||
args=script.parse_script_args(self.agent, script.shell, data["args"]),
|
||||
env_vars=script.parse_script_env_vars(
|
||||
self.agent, script.shell, data["env_vars"]
|
||||
),
|
||||
shell=script.shell,
|
||||
timeout=18,
|
||||
)
|
||||
|
||||
expected_ret = {
|
||||
"stdout": "output",
|
||||
"stderr": "error",
|
||||
"execution_time": "1.2346",
|
||||
"retcode": 0,
|
||||
}
|
||||
|
||||
self.assertEqual(r.data, expected_ret)
|
||||
|
||||
hist.refresh_from_db()
|
||||
expected_script_results = {**expected_ret, "id": hist.pk}
|
||||
self.assertEqual(hist.script_results, expected_script_results)
|
||||
|
||||
# test run on server with server scripts disabled
|
||||
with patch(
|
||||
"core.models.CoreSettings.server_scripts_enabled",
|
||||
new_callable=PropertyMock,
|
||||
) as server_scripts_enabled:
|
||||
server_scripts_enabled.return_value = False
|
||||
|
||||
data = {
|
||||
"script": script.pk,
|
||||
"output": "wait",
|
||||
"args": ["arg1", "arg2"],
|
||||
"timeout": 15,
|
||||
"run_as_user": False,
|
||||
"env_vars": ["key1=val1", "key2=val2"],
|
||||
"run_on_server": True,
|
||||
}
|
||||
r = self.client.post(url, data, format="json")
|
||||
self.assertEqual(r.status_code, 400)
|
||||
|
||||
def test_get_notes(self):
|
||||
url = f"{base_url}/notes/"
|
||||
|
||||
|
|
|
@ -768,6 +768,10 @@ def run_script(request, agent_id):
|
|||
run_as_user: bool = request.data["run_as_user"]
|
||||
env_vars: list[str] = request.data["env_vars"]
|
||||
req_timeout = int(request.data["timeout"]) + 3
|
||||
run_on_server: bool | None = request.data.get("run_on_server")
|
||||
|
||||
if run_on_server and not get_core_settings().server_scripts_enabled:
|
||||
return notify_error("This feature is disabled.")
|
||||
|
||||
AuditLog.audit_script_run(
|
||||
username=request.user.username,
|
||||
|
@ -784,6 +788,29 @@ def run_script(request, agent_id):
|
|||
)
|
||||
history_pk = hist.pk
|
||||
|
||||
if run_on_server:
|
||||
from core.utils import run_server_script
|
||||
|
||||
r = run_server_script(
|
||||
body=script.script_body,
|
||||
args=script.parse_script_args(agent, script.shell, args),
|
||||
env_vars=script.parse_script_env_vars(agent, script.shell, env_vars),
|
||||
shell=script.shell,
|
||||
timeout=req_timeout,
|
||||
)
|
||||
|
||||
ret = {
|
||||
"stdout": r[0],
|
||||
"stderr": r[1],
|
||||
"execution_time": "{:.4f}".format(r[2]),
|
||||
"retcode": r[3],
|
||||
}
|
||||
|
||||
hist.script_results = {**ret, "id": history_pk}
|
||||
hist.save(update_fields=["script_results"])
|
||||
|
||||
return Response(ret)
|
||||
|
||||
if output == "wait":
|
||||
r = agent.run_script(
|
||||
scriptpk=script.pk,
|
||||
|
@ -1008,6 +1035,16 @@ def bulk(request):
|
|||
elif request.data["mode"] == "script":
|
||||
script = get_object_or_404(Script, pk=request.data["script"])
|
||||
|
||||
# prevent API from breaking for those who haven't updated payload
|
||||
try:
|
||||
custom_field_pk = request.data["custom_field"]
|
||||
collector_all_output = request.data["collector_all_output"]
|
||||
save_to_agent_note = request.data["save_to_agent_note"]
|
||||
except KeyError:
|
||||
custom_field_pk = None
|
||||
collector_all_output = False
|
||||
save_to_agent_note = False
|
||||
|
||||
bulk_script_task.delay(
|
||||
script_pk=script.pk,
|
||||
agent_pks=agents,
|
||||
|
@ -1016,6 +1053,9 @@ def bulk(request):
|
|||
username=request.user.username[:50],
|
||||
run_as_user=request.data["run_as_user"],
|
||||
env_vars=request.data["env_vars"],
|
||||
custom_field_pk=custom_field_pk,
|
||||
collector_all_output=collector_all_output,
|
||||
save_to_agent_note=save_to_agent_note,
|
||||
)
|
||||
|
||||
return Response(f"{script.name} will now be run on {len(agents)} agents. {ht}")
|
||||
|
|
|
@ -12,7 +12,7 @@ from rest_framework.response import Response
|
|||
from rest_framework.views import APIView
|
||||
|
||||
from accounts.models import User
|
||||
from agents.models import Agent, AgentHistory
|
||||
from agents.models import Agent, AgentHistory, Note
|
||||
from agents.serializers import AgentHistorySerializer
|
||||
from alerts.tasks import cache_agents_alert_template
|
||||
from apiv3.utils import get_agent_config
|
||||
|
@ -40,6 +40,7 @@ from tacticalrmm.constants import (
|
|||
AuditActionType,
|
||||
AuditObjType,
|
||||
CheckStatus,
|
||||
CustomFieldModel,
|
||||
DebugLogType,
|
||||
GoArch,
|
||||
MeshAgentIdent,
|
||||
|
@ -581,11 +582,39 @@ class AgentHistoryResult(APIView):
|
|||
request.data["script_results"]["retcode"] = 1
|
||||
|
||||
hist = get_object_or_404(
|
||||
AgentHistory.objects.filter(agent__agent_id=agentid), pk=pk
|
||||
AgentHistory.objects.select_related("custom_field").filter(
|
||||
agent__agent_id=agentid
|
||||
),
|
||||
pk=pk,
|
||||
)
|
||||
s = AgentHistorySerializer(instance=hist, data=request.data, partial=True)
|
||||
s.is_valid(raise_exception=True)
|
||||
s.save()
|
||||
|
||||
if hist.custom_field:
|
||||
if hist.custom_field.model == CustomFieldModel.AGENT:
|
||||
field = hist.custom_field.get_or_create_field_value(hist.agent)
|
||||
elif hist.custom_field.model == CustomFieldModel.CLIENT:
|
||||
field = hist.custom_field.get_or_create_field_value(hist.agent.client)
|
||||
elif hist.custom_field.model == CustomFieldModel.SITE:
|
||||
field = hist.custom_field.get_or_create_field_value(hist.agent.site)
|
||||
|
||||
r = request.data["script_results"]["stdout"]
|
||||
value = (
|
||||
r.strip()
|
||||
if hist.collector_all_output
|
||||
else r.strip().split("\n")[-1].strip()
|
||||
)
|
||||
|
||||
field.save_to_field(value)
|
||||
|
||||
if hist.save_to_agent_note:
|
||||
Note.objects.create(
|
||||
agent=hist.agent,
|
||||
user=request.user,
|
||||
note=request.data["script_results"]["stdout"],
|
||||
)
|
||||
|
||||
return Response("ok")
|
||||
|
||||
|
||||
|
|
|
@ -365,9 +365,11 @@ class CheckResult(models.Model):
|
|||
if len(self.history) > 15:
|
||||
self.history = self.history[-15:]
|
||||
|
||||
update_fields.extend(["history"])
|
||||
update_fields.extend(["history", "more_info"])
|
||||
|
||||
avg = int(mean(self.history))
|
||||
txt = "Memory Usage" if check.check_type == CheckType.MEMORY else "CPU Load"
|
||||
self.more_info = f"Average {txt}: {avg}%"
|
||||
|
||||
if check.error_threshold and avg > check.error_threshold:
|
||||
self.status = CheckStatus.FAILING
|
||||
|
|
|
@ -133,6 +133,7 @@ class Site(BaseAuditModel):
|
|||
old_site.alert_template != self.alert_template
|
||||
or old_site.workstation_policy != self.workstation_policy
|
||||
or old_site.server_policy != self.server_policy
|
||||
or old_site.client != self.client
|
||||
):
|
||||
cache_agents_alert_template.delay()
|
||||
|
||||
|
|
|
@ -11,6 +11,14 @@ class CoreSettingsPerms(permissions.BasePermission):
|
|||
return _has_perm(r, "can_edit_core_settings")
|
||||
|
||||
|
||||
class GlobalKeyStorePerms(permissions.BasePermission):
|
||||
def has_permission(self, r, view) -> bool:
|
||||
if r.method == "GET":
|
||||
return _has_perm(r, "can_view_global_keystore")
|
||||
|
||||
return _has_perm(r, "can_edit_global_keystore")
|
||||
|
||||
|
||||
class URLActionPerms(permissions.BasePermission):
|
||||
def has_permission(self, r, view) -> bool:
|
||||
if r.method in {"GET", "PATCH"}:
|
||||
|
|
|
@ -43,6 +43,7 @@ from .permissions import (
|
|||
CodeSignPerms,
|
||||
CoreSettingsPerms,
|
||||
CustomFieldPerms,
|
||||
GlobalKeyStorePerms,
|
||||
RunServerScriptPerms,
|
||||
ServerMaintPerms,
|
||||
URLActionPerms,
|
||||
|
@ -310,7 +311,7 @@ class CodeSign(APIView):
|
|||
|
||||
|
||||
class GetAddKeyStore(APIView):
|
||||
permission_classes = [IsAuthenticated, CoreSettingsPerms]
|
||||
permission_classes = [IsAuthenticated, GlobalKeyStorePerms]
|
||||
|
||||
def get(self, request):
|
||||
keys = GlobalKVStore.objects.all()
|
||||
|
@ -325,7 +326,7 @@ class GetAddKeyStore(APIView):
|
|||
|
||||
|
||||
class UpdateDeleteKeyStore(APIView):
|
||||
permission_classes = [IsAuthenticated, CoreSettingsPerms]
|
||||
permission_classes = [IsAuthenticated, GlobalKeyStorePerms]
|
||||
|
||||
def put(self, request, pk):
|
||||
key = get_object_or_404(GlobalKVStore, pk=pk)
|
||||
|
|
|
@ -1,47 +1,46 @@
|
|||
adrf==0.1.6
|
||||
asgiref==3.8.1
|
||||
celery==5.4.0
|
||||
certifi==2024.7.4
|
||||
cffi==1.16.0
|
||||
certifi==2024.8.30
|
||||
cffi==1.17.1
|
||||
channels==4.1.0
|
||||
channels_redis==4.2.0
|
||||
cryptography==42.0.8
|
||||
Django==4.2.14
|
||||
django-cors-headers==4.4.0
|
||||
django-filter==24.2
|
||||
cryptography==43.0.3
|
||||
Django==4.2.16
|
||||
django-cors-headers==4.5.0
|
||||
django-filter==24.3
|
||||
django-rest-knox==4.2.0
|
||||
djangorestframework==3.15.2
|
||||
drf-spectacular==0.27.2
|
||||
hiredis==2.3.2
|
||||
kombu==5.3.7
|
||||
meshctrl==0.1.15
|
||||
msgpack==1.0.8
|
||||
nats-py==2.8.0
|
||||
msgpack==1.1.0
|
||||
nats-py==2.9.0
|
||||
packaging==24.1
|
||||
psutil==5.9.8
|
||||
psycopg[binary]==3.1.19
|
||||
psutil==6.0.0
|
||||
psycopg[binary]==3.2.3
|
||||
pycparser==2.22
|
||||
pycryptodome==3.20.0
|
||||
pycryptodome==3.21.0
|
||||
pyotp==2.9.0
|
||||
pyparsing==3.1.2
|
||||
pyparsing==3.1.4
|
||||
python-ipware==2.0.2
|
||||
qrcode==7.4.2
|
||||
redis==5.0.7
|
||||
qrcode==8.0
|
||||
redis==5.0.8
|
||||
requests==2.32.3
|
||||
six==1.16.0
|
||||
sqlparse==0.5.0
|
||||
sqlparse==0.5.1
|
||||
twilio==8.13.0
|
||||
urllib3==2.2.2
|
||||
uvicorn[standard]==0.30.1
|
||||
uWSGI==2.0.26
|
||||
urllib3==2.2.3
|
||||
uvicorn[standard]==0.31.1
|
||||
uWSGI==2.0.27
|
||||
validators==0.24.0
|
||||
vine==5.1.0
|
||||
websockets==12.0
|
||||
zipp==3.19.2
|
||||
pandas==2.2.2
|
||||
websockets==13.1
|
||||
zipp==3.20.2
|
||||
pandas==2.2.3
|
||||
kaleido==0.2.1
|
||||
jinja2==3.1.4
|
||||
markdown==3.6
|
||||
plotly==5.22.0
|
||||
markdown==3.7
|
||||
plotly==5.24.1
|
||||
weasyprint==62.3
|
||||
ocxsect==0.1.5
|
|
@ -118,8 +118,14 @@ class Script(BaseAuditModel):
|
|||
|
||||
args = script["args"] if "args" in script.keys() else []
|
||||
|
||||
env = script["env"] if "env" in script.keys() else []
|
||||
|
||||
syntax = script["syntax"] if "syntax" in script.keys() else ""
|
||||
|
||||
run_as_user = (
|
||||
script["run_as_user"] if "run_as_user" in script.keys() else False
|
||||
)
|
||||
|
||||
supported_platforms = (
|
||||
script["supported_platforms"]
|
||||
if "supported_platforms" in script.keys()
|
||||
|
@ -135,7 +141,9 @@ class Script(BaseAuditModel):
|
|||
i.shell = script["shell"]
|
||||
i.default_timeout = default_timeout
|
||||
i.args = args
|
||||
i.env_vars = env
|
||||
i.syntax = syntax
|
||||
i.run_as_user = run_as_user
|
||||
i.filename = script["filename"]
|
||||
i.supported_platforms = supported_platforms
|
||||
|
||||
|
@ -163,8 +171,10 @@ class Script(BaseAuditModel):
|
|||
category=category,
|
||||
default_timeout=default_timeout,
|
||||
args=args,
|
||||
env_vars=env,
|
||||
filename=script["filename"],
|
||||
syntax=syntax,
|
||||
run_as_user=run_as_user,
|
||||
supported_platforms=supported_platforms,
|
||||
)
|
||||
# new_script.hash_script_body() # also saves script
|
||||
|
|
|
@ -48,6 +48,7 @@ class ScriptSerializer(ModelSerializer):
|
|||
"run_as_user",
|
||||
"env_vars",
|
||||
]
|
||||
extra_kwargs = {"script_body": {"trim_whitespace": False}}
|
||||
|
||||
|
||||
class ScriptCheckSerializer(ModelSerializer):
|
||||
|
@ -63,3 +64,4 @@ class ScriptSnippetSerializer(ModelSerializer):
|
|||
class Meta:
|
||||
model = ScriptSnippet
|
||||
fields = "__all__"
|
||||
extra_kwargs = {"code": {"trim_whitespace": False}}
|
||||
|
|
|
@ -54,12 +54,21 @@ def bulk_script_task(
|
|||
username: str,
|
||||
run_as_user: bool = False,
|
||||
env_vars: list[str] = [],
|
||||
custom_field_pk: int | None,
|
||||
collector_all_output: bool = False,
|
||||
save_to_agent_note: bool = False,
|
||||
) -> None:
|
||||
script = Script.objects.get(pk=script_pk)
|
||||
# always override if set on script model
|
||||
if script.run_as_user:
|
||||
run_as_user = True
|
||||
|
||||
custom_field = None
|
||||
if custom_field_pk:
|
||||
from core.models import CustomField
|
||||
|
||||
custom_field = CustomField.objects.get(pk=custom_field_pk)
|
||||
|
||||
items = []
|
||||
agent: "Agent"
|
||||
for agent in Agent.objects.filter(pk__in=agent_pks):
|
||||
|
@ -68,6 +77,9 @@ def bulk_script_task(
|
|||
type=AgentHistoryType.SCRIPT_RUN,
|
||||
script=script,
|
||||
username=username,
|
||||
custom_field=custom_field,
|
||||
collector_all_output=collector_all_output,
|
||||
save_to_agent_note=save_to_agent_note,
|
||||
)
|
||||
data = {
|
||||
"func": "runscriptfull",
|
||||
|
|
|
@ -21,21 +21,21 @@ MAC_UNINSTALL = BASE_DIR / "core" / "mac_uninstall.sh"
|
|||
AUTH_USER_MODEL = "accounts.User"
|
||||
|
||||
# latest release
|
||||
TRMM_VERSION = "0.19.3"
|
||||
TRMM_VERSION = "0.19.4"
|
||||
|
||||
# https://github.com/amidaware/tacticalrmm-web
|
||||
WEB_VERSION = "0.101.48"
|
||||
WEB_VERSION = "0.101.49"
|
||||
|
||||
# bump this version everytime vue code is changed
|
||||
# to alert user they need to manually refresh their browser
|
||||
APP_VER = "0.0.194"
|
||||
APP_VER = "0.0.195"
|
||||
|
||||
# https://github.com/amidaware/rmmagent
|
||||
LATEST_AGENT_VER = "2.8.0"
|
||||
|
||||
MESH_VER = "1.1.21"
|
||||
MESH_VER = "1.1.32"
|
||||
|
||||
NATS_SERVER_VER = "2.10.17"
|
||||
NATS_SERVER_VER = "2.10.22"
|
||||
|
||||
# Install Nushell on the agent
|
||||
# https://github.com/nushell/nushell
|
||||
|
@ -81,10 +81,10 @@ INSTALL_DENO_URL = ""
|
|||
DENO_DEFAULT_PERMISSIONS = "--allow-all"
|
||||
|
||||
# for the update script, bump when need to recreate venv
|
||||
PIP_VER = "44"
|
||||
PIP_VER = "45"
|
||||
|
||||
SETUPTOOLS_VER = "70.2.0"
|
||||
WHEEL_VER = "0.43.0"
|
||||
SETUPTOOLS_VER = "75.1.0"
|
||||
WHEEL_VER = "0.44.0"
|
||||
|
||||
AGENT_BASE_URL = "https://agents.tacticalrmm.com"
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ RUN MESH_VER=$(grep -o 'MESH_VER.*' /tmp/settings.py | cut -d'"' -f 2) && \
|
|||
cat > package.json <<EOF
|
||||
{
|
||||
"dependencies": {
|
||||
"archiver": "5.3.1",
|
||||
"archiver": "7.0.1",
|
||||
"meshcentral": "$MESH_VER",
|
||||
"mongodb": "4.13.0",
|
||||
"otplib": "10.2.3",
|
||||
|
|
|
@ -25,7 +25,8 @@ if [ ! -f "/home/node/app/meshcentral-data/config.json" ] || [[ "${MESH_PERSISTE
|
|||
|
||||
encoded_uri=$(node -p "encodeURI('mongodb://${MONGODB_USER}:${MONGODB_PASSWORD}@${MONGODB_HOST}:${MONGODB_PORT}')")
|
||||
|
||||
mesh_config="$(cat << EOF
|
||||
mesh_config="$(
|
||||
cat <<EOF
|
||||
{
|
||||
"settings": {
|
||||
"mongodb": "${encoded_uri}",
|
||||
|
@ -39,8 +40,7 @@ if [ ! -f "/home/node/app/meshcentral-data/config.json" ] || [[ "${MESH_PERSISTE
|
|||
"aliasPort": 443,
|
||||
"allowLoginToken": true,
|
||||
"allowFraming": true,
|
||||
"_agentPing": 60,
|
||||
"agentPong": 300,
|
||||
"agentPing": 35,
|
||||
"allowHighQualityDesktop": true,
|
||||
"agentCoreDump": false,
|
||||
"compression": ${MESH_COMPRESSION_ENABLED},
|
||||
|
@ -74,26 +74,26 @@ if [ ! -f "/home/node/app/meshcentral-data/config.json" ] || [[ "${MESH_PERSISTE
|
|||
}
|
||||
}
|
||||
EOF
|
||||
)"
|
||||
)"
|
||||
|
||||
echo "${mesh_config}" > /home/node/app/meshcentral-data/config.json
|
||||
echo "${mesh_config}" >/home/node/app/meshcentral-data/config.json
|
||||
fi
|
||||
|
||||
node node_modules/meshcentral --createaccount ${MESH_USER} --pass ${MESH_PASS} --email example@example.com
|
||||
node node_modules/meshcentral --adminaccount ${MESH_USER}
|
||||
|
||||
if [ ! -f "${TACTICAL_DIR}/tmp/mesh_token" ]; then
|
||||
mesh_token=$(node node_modules/meshcentral --logintokenkey)
|
||||
mesh_token=$(node node_modules/meshcentral --logintokenkey)
|
||||
|
||||
if [[ ${#mesh_token} -eq 160 ]]; then
|
||||
echo ${mesh_token} > /opt/tactical/tmp/mesh_token
|
||||
else
|
||||
echo "Failed to generate mesh token. Fix the error and restart the mesh container"
|
||||
fi
|
||||
if [[ ${#mesh_token} -eq 160 ]]; then
|
||||
echo ${mesh_token} >/opt/tactical/tmp/mesh_token
|
||||
else
|
||||
echo "Failed to generate mesh token. Fix the error and restart the mesh container"
|
||||
fi
|
||||
fi
|
||||
|
||||
# wait for nginx container
|
||||
until (echo > /dev/tcp/"${NGINX_HOST_IP}"/${NGINX_HOST_PORT}) &> /dev/null; do
|
||||
until (echo >/dev/tcp/"${NGINX_HOST_IP}"/${NGINX_HOST_PORT}) &>/dev/null; do
|
||||
echo "waiting for nginx to start..."
|
||||
sleep 5
|
||||
done
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM nats:2.10.17-alpine
|
||||
FROM nats:2.10.22-alpine
|
||||
|
||||
ENV TACTICAL_DIR /opt/tactical
|
||||
ENV TACTICAL_READY_FILE ${TACTICAL_DIR}/tmp/tactical.ready
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_VERSION="85"
|
||||
SCRIPT_VERSION="86"
|
||||
SCRIPT_URL="https://raw.githubusercontent.com/amidaware/tacticalrmm/master/install.sh"
|
||||
|
||||
sudo apt install -y curl wget dirmngr gnupg lsb-release ca-certificates
|
||||
|
@ -420,7 +420,7 @@ mesh_pkg="$(
|
|||
cat <<EOF
|
||||
{
|
||||
"dependencies": {
|
||||
"archiver": "5.3.1",
|
||||
"archiver": "7.0.1",
|
||||
"meshcentral": "${MESH_VER}",
|
||||
"otplib": "10.2.3",
|
||||
"pg": "8.7.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_VERSION="59"
|
||||
SCRIPT_VERSION="60"
|
||||
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/restore.sh'
|
||||
|
||||
sudo apt update
|
||||
|
@ -413,7 +413,7 @@ mesh_pkg="$(
|
|||
cat <<EOF
|
||||
{
|
||||
"dependencies": {
|
||||
"archiver": "5.3.1",
|
||||
"archiver": "7.0.1",
|
||||
"meshcentral": "${MESH_VER}",
|
||||
"otplib": "10.2.3",
|
||||
"pg": "8.7.1",
|
||||
|
@ -494,7 +494,6 @@ echo "Running management commands...please wait..."
|
|||
API=$(python manage.py get_config api)
|
||||
WEB_VERSION=$(python manage.py get_config webversion)
|
||||
FRONTEND=$(python manage.py get_config webdomain)
|
||||
webdomain=$(python manage.py get_config webdomain)
|
||||
meshdomain=$(python manage.py get_config meshdomain)
|
||||
WEBTAR_URL=$(python manage.py get_webtar_url)
|
||||
CERT_PUB_KEY=$(python manage.py get_config certfile)
|
||||
|
@ -620,9 +619,9 @@ sudo ln -s /etc/nginx/sites-available/rmm.conf /etc/nginx/sites-enabled/rmm.conf
|
|||
|
||||
HAS_11=$(grep 127.0.1.1 /etc/hosts)
|
||||
if [[ $HAS_11 ]]; then
|
||||
sudo sed -i "/127.0.1.1/s/$/ ${API} ${webdomain} ${meshdomain}/" /etc/hosts
|
||||
sudo sed -i "/127.0.1.1/s/$/ ${API} ${FRONTEND} ${meshdomain}/" /etc/hosts
|
||||
else
|
||||
echo "127.0.1.1 ${API} ${webdomain} ${meshdomain}" | sudo tee --append /etc/hosts >/dev/null
|
||||
echo "127.0.1.1 ${API} ${FRONTEND} ${meshdomain}" | sudo tee --append /etc/hosts >/dev/null
|
||||
fi
|
||||
|
||||
sudo systemctl enable nats.service
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_VERSION="153"
|
||||
SCRIPT_VERSION="154"
|
||||
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/update.sh'
|
||||
LATEST_SETTINGS_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/api/tacticalrmm/tacticalrmm/settings.py'
|
||||
YELLOW='\033[1;33m'
|
||||
|
@ -319,7 +319,7 @@ if [[ "${CURRENT_MESH_VER}" != "${LATEST_MESH_VER}" ]] || [[ "$force" = true ]];
|
|||
cat <<EOF
|
||||
{
|
||||
"dependencies": {
|
||||
"archiver": "5.3.1",
|
||||
"archiver": "7.0.1",
|
||||
"meshcentral": "${LATEST_MESH_VER}",
|
||||
"otplib": "10.2.3",
|
||||
"pg": "8.7.1",
|
||||
|
|
Loading…
Reference in New Issue