crafty-4/app/classes/models/management.py

447 lines
16 KiB
Python
Raw Normal View History

2021-09-08 22:01:10 +00:00
import logging
import datetime
from app.classes.models.users import Users, users_helper
from app.classes.models.servers import Servers
from app.classes.models.server_permissions import server_permissions
2022-03-08 04:40:44 +00:00
from app.classes.shared.helpers import helper
from app.classes.shared.main_models import db_helper
from app.classes.web.websocket_helper import websocket_helper
2021-09-08 22:01:10 +00:00
try:
from peewee import (
SqliteDatabase,
Model,
ForeignKeyField,
CharField,
IntegerField,
DateTimeField,
FloatField,
TextField,
AutoField,
BooleanField,
)
2021-09-08 22:01:10 +00:00
from playhouse.shortcuts import model_to_dict
except ModuleNotFoundError as e:
2022-03-08 04:40:44 +00:00
helper.auto_installer_fix(e)
2021-09-08 22:01:10 +00:00
2022-03-08 04:40:44 +00:00
logger = logging.getLogger(__name__)
peewee_logger = logging.getLogger("peewee")
2022-03-08 04:40:44 +00:00
peewee_logger.setLevel(logging.INFO)
database = SqliteDatabase(
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
)
2021-09-08 22:01:10 +00:00
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Audit_Log Class
# **********************************************************************************
2021-09-08 22:01:10 +00:00
class Audit_Log(Model):
audit_id = AutoField()
created = DateTimeField(default=datetime.datetime.now)
user_name = CharField(default="")
user_id = IntegerField(default=0, index=True)
source_ip = CharField(default="127.0.0.1")
server_id = IntegerField(
default=None, index=True
) # When auditing global events, use server ID 0
log_msg = TextField(default="")
2021-09-08 22:01:10 +00:00
class Meta:
database = database
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Host_Stats Class
# **********************************************************************************
2021-09-08 22:01:10 +00:00
class Host_Stats(Model):
time = DateTimeField(default=datetime.datetime.now, index=True)
boot_time = CharField(default="")
cpu_usage = FloatField(default=0)
cpu_cores = IntegerField(default=0)
cpu_cur_freq = FloatField(default=0)
cpu_max_freq = FloatField(default=0)
mem_percent = FloatField(default=0)
mem_usage = CharField(default="")
mem_total = CharField(default="")
disk_json = TextField(default="")
class Meta:
table_name = "host_stats"
database = database
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Commands Class
# **********************************************************************************
2021-09-08 22:01:10 +00:00
class Commands(Model):
command_id = AutoField()
created = DateTimeField(default=datetime.datetime.now)
server_id = ForeignKeyField(Servers, backref="server", index=True)
user = ForeignKeyField(Users, backref="user", index=True)
source_ip = CharField(default="127.0.0.1")
command = CharField(default="")
2021-09-08 22:01:10 +00:00
executed = BooleanField(default=False)
class Meta:
table_name = "commands"
database = database
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Webhooks Class
# **********************************************************************************
2021-09-08 22:01:10 +00:00
class Webhooks(Model):
id = AutoField()
name = CharField(max_length=64, unique=True, index=True)
method = CharField(default="POST")
url = CharField(unique=True)
event = CharField(default="")
send_data = BooleanField(default=True)
class Meta:
table_name = "webhooks"
database = database
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Schedules Class
# **********************************************************************************
2021-09-08 22:01:10 +00:00
class Schedules(Model):
schedule_id = IntegerField(unique=True, primary_key=True)
server_id = ForeignKeyField(Servers, backref="schedule_server")
2021-09-08 22:01:10 +00:00
enabled = BooleanField()
action = CharField()
interval = IntegerField()
interval_type = CharField()
start_time = CharField(null=True)
command = CharField(null=True)
comment = CharField()
one_time = BooleanField(default=False)
cron_string = CharField(default="")
2022-02-24 03:58:48 +00:00
parent = IntegerField(null=True)
delay = IntegerField(default=0)
2021-09-08 22:01:10 +00:00
class Meta:
table_name = "schedules"
2021-09-08 22:01:10 +00:00
database = database
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Backups Class
# **********************************************************************************
2021-09-08 22:01:10 +00:00
class Backups(Model):
excluded_dirs = CharField(null=True)
2021-09-08 22:01:10 +00:00
max_backups = IntegerField()
server_id = ForeignKeyField(Servers, backref="backups_server")
2022-03-02 16:34:26 +00:00
compress = BooleanField(default=False)
2021-09-08 22:01:10 +00:00
class Meta:
table_name = "backups"
2021-09-08 22:01:10 +00:00
database = database
2021-09-08 22:01:10 +00:00
class helpers_management:
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Host_Stats Methods
# **********************************************************************************
2021-09-08 22:01:10 +00:00
@staticmethod
def get_latest_hosts_stats():
# pylint: disable=no-member
query = Host_Stats.select().order_by(Host_Stats.id.desc()).get()
2021-09-08 22:01:10 +00:00
return model_to_dict(query)
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Commands Methods
# **********************************************************************************
2021-09-08 22:01:10 +00:00
@staticmethod
def add_command(server_id, user_id, remote_ip, command):
Commands.insert(
{
Commands.server_id: server_id,
Commands.user: user_id,
Commands.source_ip: remote_ip,
Commands.command: command,
}
).execute()
2021-09-08 22:01:10 +00:00
@staticmethod
def get_unactioned_commands():
query = Commands.select().where(Commands.executed == 0)
return query
2021-09-08 22:01:10 +00:00
@staticmethod
def mark_command_complete(command_id=None):
if command_id is not None:
logger.debug(f"Marking Command {command_id} completed")
Commands.update({Commands.executed: True}).where(
Commands.command_id == command_id
).execute()
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Audit_Log Methods
# **********************************************************************************
2021-09-08 22:01:10 +00:00
@staticmethod
def get_actity_log():
q = Audit_Log.select()
return db_helper.return_db_rows(q)
2021-09-08 22:01:10 +00:00
@staticmethod
def add_to_audit_log(user_id, log_msg, server_id=None, source_ip=None):
logger.debug(f"Adding to audit log User:{user_id} - Message: {log_msg} ")
2021-09-08 22:01:10 +00:00
user_data = users_helper.get_user(user_id)
audit_msg = f"{str(user_data['username']).capitalize()} {log_msg}"
2021-09-08 22:01:10 +00:00
server_users = server_permissions.get_server_user_list(server_id)
for user in server_users:
websocket_helper.broadcast_user(user, "notification", audit_msg)
Audit_Log.insert(
{
Audit_Log.user_name: user_data["username"],
Audit_Log.user_id: user_id,
Audit_Log.server_id: server_id,
Audit_Log.log_msg: audit_msg,
Audit_Log.source_ip: source_ip,
}
).execute()
# deletes records when they're more than 100
ordered = Audit_Log.select().order_by(+Audit_Log.created)
for item in ordered:
if not helper.get_setting("max_audit_entries"):
2022-01-31 23:09:23 +00:00
max_entries = 300
else:
max_entries = helper.get_setting("max_audit_entries")
2022-01-31 23:09:23 +00:00
if Audit_Log.select().count() > max_entries:
Audit_Log.delete().where(Audit_Log.audit_id == item.audit_id).execute()
else:
return
2021-09-08 22:01:10 +00:00
@staticmethod
def add_to_audit_log_raw(user_name, user_id, server_id, log_msg, source_ip):
Audit_Log.insert(
{
Audit_Log.user_name: user_name,
Audit_Log.user_id: user_id,
Audit_Log.server_id: server_id,
Audit_Log.log_msg: log_msg,
Audit_Log.source_ip: source_ip,
}
).execute()
# deletes records when they're more than 100
ordered = Audit_Log.select().order_by(+Audit_Log.created)
for item in ordered:
# configurable through app/config/config.json
if not helper.get_setting("max_audit_entries"):
2022-01-31 23:09:23 +00:00
max_entries = 300
else:
max_entries = helper.get_setting("max_audit_entries")
2022-01-31 23:09:23 +00:00
if Audit_Log.select().count() > max_entries:
Audit_Log.delete().where(Audit_Log.audit_id == item.audit_id).execute()
else:
return
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Schedules Methods
# **********************************************************************************
2021-09-08 22:01:10 +00:00
@staticmethod
def create_scheduled_task(
server_id,
action,
interval,
interval_type,
start_time,
command,
comment=None,
enabled=True,
one_time=False,
cron_string="* * * * *",
2022-02-24 05:19:54 +00:00
parent=None,
delay=0,
):
sch_id = Schedules.insert(
{
Schedules.server_id: server_id,
Schedules.action: action,
Schedules.enabled: enabled,
Schedules.interval: interval,
Schedules.interval_type: interval_type,
Schedules.start_time: start_time,
Schedules.command: command,
Schedules.comment: comment,
Schedules.one_time: one_time,
Schedules.cron_string: cron_string,
Schedules.parent: parent,
Schedules.delay: delay,
}
).execute()
2021-09-08 22:01:10 +00:00
return sch_id
@staticmethod
def delete_scheduled_task(schedule_id):
sch = Schedules.get(Schedules.schedule_id == schedule_id)
return Schedules.delete_instance(sch)
@staticmethod
def update_scheduled_task(schedule_id, updates):
Schedules.update(updates).where(Schedules.schedule_id == schedule_id).execute()
2021-11-29 21:22:46 +00:00
@staticmethod
def delete_scheduled_task_by_server(server_id):
Schedules.delete().where(Schedules.server_id == int(server_id)).execute()
2021-11-29 21:22:46 +00:00
2021-09-08 22:01:10 +00:00
@staticmethod
def get_scheduled_task(schedule_id):
return model_to_dict(Schedules.get(Schedules.schedule_id == schedule_id))
2021-09-08 22:01:10 +00:00
@staticmethod
def get_scheduled_task_model(schedule_id):
return Schedules.select().where(Schedules.schedule_id == schedule_id).get()
2021-09-08 22:01:10 +00:00
@staticmethod
def get_schedules_by_server(server_id):
return Schedules.select().where(Schedules.server_id == server_id).execute()
2022-02-24 03:58:48 +00:00
@staticmethod
def get_child_schedules_by_server(schedule_id, server_id):
return (
Schedules.select()
.where(Schedules.server_id == server_id, Schedules.parent == schedule_id)
.execute()
)
2022-02-24 03:58:48 +00:00
2022-02-24 05:19:54 +00:00
@staticmethod
def get_child_schedules(schedule_id):
return Schedules.select().where(Schedules.parent == schedule_id)
2021-09-08 22:01:10 +00:00
@staticmethod
def get_schedules_all():
return Schedules.select().execute()
@staticmethod
def get_schedules_enabled():
# pylint: disable=singleton-comparison
2022-01-29 05:08:55 +00:00
return Schedules.select().where(Schedules.enabled == True).execute()
2021-09-08 22:01:10 +00:00
# **********************************************************************************
2021-09-08 22:01:10 +00:00
# Backups Methods
# **********************************************************************************
2021-09-08 22:01:10 +00:00
@staticmethod
def get_backup_config(server_id):
try:
row = (
Backups.select().where(Backups.server_id == server_id).join(Servers)[0]
)
2021-09-08 22:01:10 +00:00
conf = {
"backup_path": row.server_id.backup_path,
"excluded_dirs": row.excluded_dirs,
2021-09-08 22:01:10 +00:00
"max_backups": row.max_backups,
2022-03-02 16:34:26 +00:00
"server_id": row.server_id.server_id,
"compress": row.compress,
2021-09-08 22:01:10 +00:00
}
except IndexError:
conf = {
"backup_path": None,
"excluded_dirs": None,
2021-09-08 22:01:10 +00:00
"max_backups": 0,
2022-03-02 16:34:26 +00:00
"server_id": server_id,
"compress": False,
2021-09-08 22:01:10 +00:00
}
return conf
@staticmethod
def set_backup_config(
server_id: int,
backup_path: str = None,
max_backups: int = None,
excluded_dirs: list = None,
compress: bool = False,
):
logger.debug(f"Updating server {server_id} backup config with {locals()}")
2022-01-29 21:37:00 +00:00
if Backups.select().where(Backups.server_id == server_id).count() != 0:
2021-09-08 22:01:10 +00:00
new_row = False
conf = {}
2022-01-29 21:37:00 +00:00
else:
2021-09-08 22:01:10 +00:00
conf = {
"excluded_dirs": None,
2021-09-08 22:01:10 +00:00
"max_backups": 0,
"server_id": server_id,
"compress": False,
2021-09-08 22:01:10 +00:00
}
new_row = True
if max_backups is not None:
conf["max_backups"] = max_backups
if excluded_dirs is not None:
dirs_to_exclude = ",".join(excluded_dirs)
conf["excluded_dirs"] = dirs_to_exclude
conf["compress"] = compress
2021-09-08 22:01:10 +00:00
if not new_row:
with database.atomic():
if backup_path is not None:
u1 = (
Servers.update(backup_path=backup_path)
.where(Servers.server_id == server_id)
.execute()
)
2021-09-08 22:01:10 +00:00
else:
u1 = 0
u2 = (
Backups.update(conf).where(Backups.server_id == server_id).execute()
)
logger.debug(f"Updating existing backup record. {u1}+{u2} rows affected")
2021-09-08 22:01:10 +00:00
else:
with database.atomic():
conf["server_id"] = server_id
if backup_path is not None:
Servers.update(backup_path=backup_path).where(
Servers.server_id == server_id
)
Backups.create(**conf)
2021-09-08 22:01:10 +00:00
logger.debug("Creating new backup record.")
def get_excluded_backup_dirs(self, server_id: int):
excluded_dirs = self.get_backup_config(server_id)["excluded_dirs"]
if excluded_dirs is not None and excluded_dirs != "":
dir_list = excluded_dirs.split(",")
else:
dir_list = []
return dir_list
def add_excluded_backup_dir(self, server_id: int, dir_to_add: str):
dir_list = self.get_excluded_backup_dirs()
if dir_to_add not in dir_list:
dir_list.append(dir_to_add)
excluded_dirs = ",".join(dir_list)
self.set_backup_config(server_id=server_id, excluded_dirs=excluded_dirs)
else:
logger.debug(
f"Not adding {dir_to_add} to excluded directories - "
f"already in the excluded directory list for server ID {server_id}"
)
def del_excluded_backup_dir(self, server_id: int, dir_to_del: str):
dir_list = self.get_excluded_backup_dirs()
if dir_to_del in dir_list:
dir_list.remove(dir_to_del)
excluded_dirs = ",".join(dir_list)
self.set_backup_config(server_id=server_id, excluded_dirs=excluded_dirs)
else:
logger.debug(
f"Not removing {dir_to_del} from excluded directories - "
f"not in the excluded directory list for server ID {server_id}"
)
2022-03-02 18:07:00 +00:00
@staticmethod
def clear_unexecuted_commands():
Commands.update(
{
Commands.executed: True
# pylint: disable=singleton-comparison
}
).where(Commands.executed == False).execute()
2021-09-08 22:01:10 +00:00
management_helper = helpers_management()