Skip to content

Commit

Permalink
Release 0.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
wh1te909 committed Jan 17, 2021
2 parents 9ab915a + bf91d60 commit 8046a3c
Show file tree
Hide file tree
Showing 47 changed files with 1,017 additions and 417 deletions.
5 changes: 3 additions & 2 deletions .devcontainer/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ POSTGRES_USER=postgres
POSTGRES_PASS=postgrespass

# DEV SETTINGS
APP_PORT=8080
API_PORT=8000
APP_PORT=8000
API_PORT=8080
HTTP_PROTOCOL=https
21 changes: 15 additions & 6 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ services:
context: .
dockerfile: ./api.dockerfile
command: ["tactical-api"]
environment:
API_PORT: ${API_PORT}
ports:
- 8000:8000
- "8000:${API_PORT}"
volumes:
- tactical-data-dev:/opt/tactical
- ..:/workspace:cached
Expand All @@ -19,12 +21,12 @@ services:

app-dev:
image: node:12-alpine
ports:
- 8080:8080
command: /bin/sh -c "npm install && npm run serve -- --host 0.0.0.0 --port 8080"
command: /bin/sh -c "npm install && npm run serve -- --host 0.0.0.0 --port ${APP_PORT}"
working_dir: /workspace/web
volumes:
- ..:/workspace:cached
ports:
- "8080:${APP_PORT}"
networks:
dev:
aliases:
Expand All @@ -49,10 +51,15 @@ services:
nats-dev:
image: ${IMAGE_REPO}tactical-nats:${VERSION}
restart: always
environment:
API_HOST: ${API_HOST}
API_PORT: ${API_PORT}
DEV: 1
ports:
- "4222:4222"
volumes:
- tactical-data-dev:/opt/tactical
- ..:/workspace:cached
networks:
dev:
aliases:
Expand Down Expand Up @@ -136,6 +143,8 @@ services:
MESH_USER: ${MESH_USER}
TRMM_USER: ${TRMM_USER}
TRMM_PASS: ${TRMM_PASS}
HTTP_PROTOCOL: ${HTTP_PROTOCOL}
APP_PORT: ${APP_PORT}
depends_on:
- postgres-dev
- meshcentral-dev
Expand Down Expand Up @@ -206,8 +215,8 @@ services:
MESH_HOST: ${MESH_HOST}
CERT_PUB_KEY: ${CERT_PUB_KEY}
CERT_PRIV_KEY: ${CERT_PRIV_KEY}
APP_PORT: 8080
API_PORT: 8000
APP_PORT: ${APP_PORT}
API_PORT: ${API_PORT}
networks:
dev:
ipv4_address: 172.21.0.20
Expand Down
23 changes: 14 additions & 9 deletions .devcontainer/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ set -e
: "${API_HOST:=tactical-backend}"
: "${APP_HOST:=tactical-frontend}"
: "${REDIS_HOST:=tactical-redis}"
: "${HTTP_PROTOCOL:=http}"
: "${APP_PORT:=8080}"
: "${API_PORT:=8000}"

# Add python venv to path
export PATH="${VIRTUAL_ENV}/bin:$PATH"
Expand Down Expand Up @@ -68,7 +71,7 @@ KEY_FILE = '/opt/tactical/certs/privkey.pem'
SCRIPTS_DIR = '${WORKSPACE_DIR}/scripts'
ALLOWED_HOSTS = ['${API_HOST}', 'localhost', '127.0.0.1']
ALLOWED_HOSTS = ['${API_HOST}', '*']
ADMIN_URL = 'admin/'
Expand Down Expand Up @@ -144,10 +147,9 @@ if [ "$1" = 'tactical-init-dev' ]; then

# create .env file for frontend
webenv="$(cat << EOF
PROD_URL = "http://${API_HOST}:8000"
DEV_URL = "http://${API_HOST}:8000"
DEV_HOST = 0.0.0.0
DEV_PORT = 8080
PROD_URL = "${HTTP_PROTOCOL}://${API_HOST}"
DEV_URL = "${HTTP_PROTOCOL}://${API_HOST}"
APP_URL = https://${APP_HOST}
EOF
)"
echo "${webenv}" | tee ${WORKSPACE_DIR}/web/.env > /dev/null
Expand All @@ -161,22 +163,25 @@ EOF
fi

if [ "$1" = 'tactical-api' ]; then
cp ${WORKSPACE_DIR}/api/tacticalrmm/core/goinstaller/bin/goversioninfo /usr/local/bin/goversioninfo
chmod +x /usr/local/bin/goversioninfo

check_tactical_ready
python manage.py runserver 0.0.0.0:8000
python manage.py runserver 0.0.0.0:${API_PORT}
fi

if [ "$1" = 'tactical-celery-dev' ]; then
check_tactical_ready
celery -A tacticalrmm worker -l debug
env/bin/celery -A tacticalrmm worker -l debug
fi

if [ "$1" = 'tactical-celerybeat-dev' ]; then
check_tactical_ready
test -f "${WORKSPACE_DIR}/api/tacticalrmm/celerybeat.pid" && rm "${WORKSPACE_DIR}/api/tacticalrmm/celerybeat.pid"
celery -A tacticalrmm beat -l debug
env/bin/celery -A tacticalrmm beat -l debug
fi

if [ "$1" = 'tactical-celerywinupdate-dev' ]; then
check_tactical_ready
celery -A tacticalrmm worker -Q wupdate -l debug
env/bin/celery -A tacticalrmm worker -Q wupdate -l debug
fi
25 changes: 9 additions & 16 deletions api/tacticalrmm/agents/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,32 +382,18 @@ def get_patch_policy(self):

return patch_policy

# clear is used to delete managed policy checks from agent
# parent_checks specifies a list of checks to delete from agent with matching parent_check field
def generate_checks_from_policies(self, clear=False):
def generate_checks_from_policies(self):
from automation.models import Policy

# Clear agent checks managed by policy
if clear:
self.agentchecks.filter(managed_by_policy=True).delete()

# Clear agent checks that have overriden_by_policy set
self.agentchecks.update(overriden_by_policy=False)

# Generate checks based on policies
Policy.generate_policy_checks(self)

# clear is used to delete managed policy tasks from agent
# parent_tasks specifies a list of tasks to delete from agent with matching parent_task field
def generate_tasks_from_policies(self, clear=False):
from autotasks.tasks import delete_win_task_schedule
def generate_tasks_from_policies(self):
from automation.models import Policy

# Clear agent tasks managed by policy
if clear:
for task in self.autotasks.filter(managed_by_policy=True):
delete_win_task_schedule.delay(task.pk)

# Generate tasks based on policies
Policy.generate_policy_tasks(self)

Expand Down Expand Up @@ -625,6 +611,13 @@ def handle_pending_actions(self):
elif action.details["action"] == "taskdelete":
delete_win_task_schedule.delay(task_id, pending_action=action.id)

# for clearing duplicate pending actions on agent
def remove_matching_pending_task_actions(self, task_id):
# remove any other pending actions on agent with same task_id
for action in self.pendingactions.exclude(status="completed"):
if action.details["task_id"] == task_id:
action.delete()


class AgentOutage(models.Model):
agent = models.ForeignKey(
Expand Down
37 changes: 35 additions & 2 deletions api/tacticalrmm/agents/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _check_in_full(pk: int) -> None:
def check_in_task() -> None:
q = Agent.objects.only("pk", "version")
agents: List[int] = [
i.pk for i in q if pyver.parse(i.version) >= pyver.parse("1.1.12")
i.pk for i in q if pyver.parse(i.version) == pyver.parse("1.1.12")
]
chunks = (agents[i : i + 50] for i in range(0, len(agents), 50))
for chunk in chunks:
Expand Down Expand Up @@ -133,13 +133,32 @@ def auto_self_agent_update_task() -> None:
agent_update(pk)


@app.task
def get_wmi_task():
agents = Agent.objects.all()
online = [
i
for i in agents
if pyver.parse(i.version) >= pyver.parse("1.2.0") and i.status == "online"
]
chunks = (online[i : i + 50] for i in range(0, len(online), 50))
for chunk in chunks:
for agent in chunk:
asyncio.run(agent.nats_cmd({"func": "wmi"}, wait=False))
sleep(0.1)
rand = random.randint(3, 7)
sleep(rand)


@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"
if pyver.parse(i.version) >= pyver.parse("1.1.3")
and pyver.parse(i.version) <= pyver.parse("1.1.12")
and i.status == "online"
]

chunks = (online[i : i + 50] for i in range(0, len(online), 50))
Expand Down Expand Up @@ -309,6 +328,20 @@ def install_salt_task(pk: int) -> None:
asyncio.run(agent.nats_cmd({"func": "installsalt"}, wait=False))


@app.task
def handle_agent_recovery_task(pk: int) -> None:
sleep(10)
from agents.models import RecoveryAction

action = RecoveryAction.objects.get(pk=pk)
if action.mode == "command":
data = {"func": "recoverycmd", "recoverycommand": action.command}
else:
data = {"func": "recover", "payload": {"mode": action.mode}}

asyncio.run(action.agent.nats_cmd(data, wait=False))


@app.task
def run_script_email_results_task(
agentpk: int, scriptpk: int, nats_timeout: int, nats_data: dict, emails: List[str]
Expand Down
12 changes: 8 additions & 4 deletions api/tacticalrmm/agents/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,13 @@ def test_uninstall(self, reload_nats, mock_task, nats_cmd):

@patch("agents.models.Agent.nats_cmd")
def test_get_processes(self, mock_ret):
url = f"/agents/{self.agent.pk}/getprocs/"
agent_old = baker.make_recipe("agents.online_agent", version="1.1.12")
url_old = f"/agents/{agent_old.pk}/getprocs/"
r = self.client.get(url_old)
self.assertEqual(r.status_code, 400)

agent = baker.make_recipe("agents.online_agent", version="1.2.0")
url = f"/agents/{agent.pk}/getprocs/"

with open(
os.path.join(settings.BASE_DIR, "tacticalrmm/test_data/procs.json")
Expand All @@ -137,9 +143,7 @@ def test_get_processes(self, mock_ret):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
assert any(i["name"] == "Registry" for i in mock_ret.return_value)
assert any(
i["memory_percent"] == 0.004843281375620747 for i in mock_ret.return_value
)
assert any(i["membytes"] == 434655234324 for i in mock_ret.return_value)

mock_ret.return_value = "timeout"
r = self.client.get(url)
Expand Down
10 changes: 5 additions & 5 deletions api/tacticalrmm/agents/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ def edit_agent(request):

# check if site changed and initiate generating correct policies
if old_site != request.data["site"]:
agent.generate_checks_from_policies(clear=True)
agent.generate_tasks_from_policies(clear=True)
agent.generate_checks_from_policies()
agent.generate_tasks_from_policies()

return Response("ok")

Expand Down Expand Up @@ -159,12 +159,12 @@ def agent_detail(request, pk):
@api_view()
def get_processes(request, pk):
agent = get_object_or_404(Agent, pk=pk)
if not agent.has_nats:
return notify_error("Requires agent version 1.1.0 or greater")
if pyver.parse(agent.version) < pyver.parse("1.2.0"):
return notify_error("Requires agent version 1.2.0 or greater")

r = asyncio.run(agent.nats_cmd(data={"func": "procs"}, timeout=5))
if r == "timeout":
return notify_error("Unable to contact the agent")

return Response(r)


Expand Down
2 changes: 0 additions & 2 deletions api/tacticalrmm/apiv3/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,6 @@ def get(self, request, agentid):
return Response(ret)

def patch(self, request):
from logs.models import AuditLog

check = get_object_or_404(Check, pk=request.data["id"])
check.last_run = djangotime.now()
check.save(update_fields=["last_run"])
Expand Down
42 changes: 41 additions & 1 deletion api/tacticalrmm/automation/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django.db import models
from agents.models import Agent
from clients.models import Site, Client
from core.models import CoreSettings
from logs.models import BaseAuditModel

Expand Down Expand Up @@ -58,6 +57,11 @@ def serialize(policy):

@staticmethod
def cascade_policy_tasks(agent):
from autotasks.tasks import delete_win_task_schedule

from autotasks.models import AutomatedTask
from logs.models import PendingAction

# List of all tasks to be applied
tasks = list()
added_task_pks = list()
Expand Down Expand Up @@ -107,6 +111,33 @@ def cascade_policy_tasks(agent):
tasks.append(task)
added_task_pks.append(task.pk)

# remove policy tasks from agent not included in policy
for task in agent.autotasks.filter(
parent_task__in=[
taskpk
for taskpk in agent_tasks_parent_pks
if taskpk not in added_task_pks
]
):
delete_win_task_schedule.delay(task.pk)

# handle matching tasks that haven't synced to agent yet or pending deletion due to agent being offline
for action in agent.pendingactions.exclude(status="completed"):
task = AutomatedTask.objects.get(pk=action.details["task_id"])
if (
task.parent_task in agent_tasks_parent_pks
and task.parent_task in added_task_pks
):
agent.remove_matching_pending_task_actions(task.id)

PendingAction(
agent=agent,
action_type="taskaction",
details={"action": "taskcreate", "task_id": task.id},
).save()
task.sync_status = "notsynced"
task.save(update_fields=["sync_status"])

return [task for task in tasks if task.pk not in agent_tasks_parent_pks]

@staticmethod
Expand Down Expand Up @@ -280,6 +311,15 @@ def cascade_policy_checks(agent):
+ eventlog_checks
)

# remove policy checks from agent that fell out of policy scope
agent.agentchecks.filter(
parent_check__in=[
checkpk
for checkpk in agent_checks_parent_pks
if checkpk not in [check.pk for check in final_list]
]
).delete()

return [
check for check in final_list if check.pk not in agent_checks_parent_pks
]
Expand Down
Loading

0 comments on commit 8046a3c

Please sign in to comment.