Merge branch 'improve-session-lock' into 'dev'

Improve session.lock checking. Add option to disable language files. Add option to compress backups

See merge request crafty-controller/crafty-commander!178
This commit is contained in:
Andrew 2022-03-02 16:37:30 +00:00
commit fec877db7b
11 changed files with 93 additions and 20 deletions

View File

@ -104,8 +104,8 @@ class Management_Controller:
return management_helper.get_backup_config(server_id) return management_helper.get_backup_config(server_id)
@staticmethod @staticmethod
def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None, excluded_dirs: list = None): def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None, excluded_dirs: list = None, compress: bool = False,):
return management_helper.set_backup_config(server_id, backup_path, max_backups, excluded_dirs) return management_helper.set_backup_config(server_id, backup_path, max_backups, excluded_dirs, compress)
@staticmethod @staticmethod
def get_excluded_backup_dirs(server_id: int): def get_excluded_backup_dirs(server_id: int):

View File

@ -1,4 +1,3 @@
import os
import json import json
import logging import logging
import datetime import datetime
@ -114,7 +113,7 @@ class Stats:
def get_world_size(server_path): def get_world_size(server_path):
total_size = 0 total_size = 0
total_size = helper.get_dir_size(server_path) total_size = helper.get_dir_size(server_path)
level_total_size = helper.human_readable_file_size(total_size) level_total_size = helper.human_readable_file_size(total_size)

View File

@ -128,6 +128,7 @@ class Backups(Model):
excluded_dirs = CharField(null=True) excluded_dirs = CharField(null=True)
max_backups = IntegerField() max_backups = IntegerField()
server_id = ForeignKeyField(Servers, backref='backups_server') server_id = ForeignKeyField(Servers, backref='backups_server')
compress = BooleanField(default=False)
class Meta: class Meta:
table_name = 'backups' table_name = 'backups'
database = database database = database
@ -313,19 +314,21 @@ class helpers_management:
"backup_path": row.server_id.backup_path, "backup_path": row.server_id.backup_path,
"excluded_dirs": row.excluded_dirs, "excluded_dirs": row.excluded_dirs,
"max_backups": row.max_backups, "max_backups": row.max_backups,
"server_id": row.server_id.server_id "server_id": row.server_id.server_id,
"compress": row.compress
} }
except IndexError: except IndexError:
conf = { conf = {
"backup_path": None, "backup_path": None,
"excluded_dirs": None, "excluded_dirs": None,
"max_backups": 0, "max_backups": 0,
"server_id": server_id "server_id": server_id,
"compress": False,
} }
return conf return conf
@staticmethod @staticmethod
def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None, excluded_dirs: list = None): 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()}") logger.debug(f"Updating server {server_id} backup config with {locals()}")
if Backups.select().where(Backups.server_id == server_id).count() != 0: if Backups.select().where(Backups.server_id == server_id).count() != 0:
new_row = False new_row = False
@ -334,7 +337,8 @@ class helpers_management:
conf = { conf = {
"excluded_dirs": None, "excluded_dirs": None,
"max_backups": 0, "max_backups": 0,
"server_id": server_id "server_id": server_id,
"compress": False
} }
new_row = True new_row = True
if max_backups is not None: if max_backups is not None:
@ -342,6 +346,7 @@ class helpers_management:
if excluded_dirs is not None: if excluded_dirs is not None:
dirs_to_exclude = ",".join(excluded_dirs) dirs_to_exclude = ",".join(excluded_dirs)
conf['excluded_dirs'] = dirs_to_exclude conf['excluded_dirs'] = dirs_to_exclude
conf['compress'] = compress
if not new_row: if not new_row:
with database.atomic(): with database.atomic():
if backup_path is not None: if backup_path is not None:

View File

@ -9,7 +9,7 @@ from app.classes.shared.console import console
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
try: try:
from zipfile import ZipFile from zipfile import ZipFile, ZIP_DEFLATED
except ModuleNotFoundError as err: except ModuleNotFoundError as err:
logger.critical(f"Import Error: Unable to load {err.name} module", exc_info=True) logger.critical(f"Import Error: Unable to load {err.name} module", exc_info=True)
@ -87,4 +87,25 @@ class FileHelpers:
return True return True
@staticmethod
def make_compressed_archive(path_to_destination, path_to_zip):
# create a ZipFile object
path_to_destination += '.zip'
with ZipFile(path_to_destination, 'w', ZIP_DEFLATED) as z:
for root, _dirs, files in os.walk(path_to_zip, topdown=True):
ziproot = path_to_zip
for file in files:
try:
logger.info(f"backing up: {os.path.join(root, file)}")
if os.name == "nt":
z.write(os.path.join(root, file), os.path.join(root.replace(ziproot, ""), file))
else:
z.write(os.path.join(root, file), os.path.join(root.replace(ziproot, "/"), file))
except Exception as e:
logger.warning(f"Error backing up: {os.path.join(root, file)}! - Error was: {e}")
return True
file_helper = FileHelpers() file_helper = FileHelpers()

View File

@ -17,6 +17,7 @@ import ctypes
from datetime import datetime from datetime import datetime
from socket import gethostname from socket import gethostname
from contextlib import suppress from contextlib import suppress
import psutil
from requests import get from requests import get
from app.classes.web.websocket_helper import websocket_helper from app.classes.web.websocket_helper import websocket_helper
@ -481,11 +482,18 @@ class Helpers:
pid = data.get('pid') pid = data.get('pid')
started = data.get('started') started = data.get('started')
console.critical(f"Another Crafty Controller agent seems to be running...\npid: {pid} \nstarted on: {started}") console.critical(f"Another Crafty Controller agent seems to be running...\npid: {pid} \nstarted on: {started}")
if psutil.pid_exists(pid):
logger.critical("Found running crafty process. Exiting.")
sys.exit(1)
else:
logger.info("No process found for pid. Assuming crafty crashed. Deleting stale session.lock")
os.remove(self.session_file)
except Exception as e: except Exception as e:
logger.error(f"Failed to locate existing session.lock with error: {e} ") logger.error(f"Failed to locate existing session.lock with error: {e} ")
console.error(f"Failed to locate existing session.lock with error: {e} ") console.error(f"Failed to locate existing session.lock with error: {e} ")
sys.exit(1) sys.exit(1)
pid = os.getpid() pid = os.getpid()
now = datetime.now() now = datetime.now()

View File

@ -604,7 +604,12 @@ class Server:
else: else:
# If not, just remove the file # If not, just remove the file
os.remove(excluded_dir) os.remove(excluded_dir)
file_helper.make_archive(helper.get_os_understandable_path(backup_filename), tempDir) if conf['compress']:
logger.debug("Found compress backup to be true. Calling compressed archive")
file_helper.make_compressed_archive(helper.get_os_understandable_path(backup_filename), tempDir)
else:
logger.debug("Found compress backup to be false. Calling NON-compressed archive")
file_helper.make_archive(helper.get_os_understandable_path(backup_filename), tempDir)
while len(self.list_backups()) > conf["max_backups"] and conf["max_backups"] > 0: while len(self.list_backups()) > conf["max_backups"] and conf["max_backups"] > 0:
backup_list = self.list_backups() backup_list = self.list_backups()

View File

@ -606,10 +606,11 @@ class PanelHandler(BaseHandler):
page_data['super-disabled'] = '' page_data['super-disabled'] = ''
else: else:
page_data['super-disabled'] = 'disabled' page_data['super-disabled'] = 'disabled'
for file in os.listdir(os.path.join(helper.root_dir, 'app', 'translations')): for file in sorted(os.listdir(os.path.join(helper.root_dir, 'app', 'translations'))):
if file.endswith('.json'): if file.endswith('.json'):
if file != str(page_data['languages'][0] + '.json'): if file not in helper.get_setting('disabled_language_files'):
page_data['languages'].append(file.split('.')[0]) if file != str(page_data['languages'][0] + '.json'):
page_data['languages'].append(file.split('.')[0])
template = "panel/panel_edit_user.html" template = "panel/panel_edit_user.html"
@ -738,8 +739,9 @@ class PanelHandler(BaseHandler):
for file in sorted(os.listdir(os.path.join(helper.root_dir, 'app', 'translations'))): for file in sorted(os.listdir(os.path.join(helper.root_dir, 'app', 'translations'))):
if file.endswith('.json'): if file.endswith('.json'):
if file != str(page_data['languages'][0] + '.json'): if file not in helper.get_setting('disabled_language_files'):
page_data['languages'].append(file.split('.')[0]) if file != str(page_data['languages'][0] + '.json'):
page_data['languages'].append(file.split('.')[0])
if user_id is None: if user_id is None:
self.redirect("/panel/error?error=Invalid User ID") self.redirect("/panel/error?error=Invalid User ID")
@ -1059,6 +1061,7 @@ class PanelHandler(BaseHandler):
logger.debug(self.request.arguments) logger.debug(self.request.arguments)
server_id = self.get_argument('id', None) server_id = self.get_argument('id', None)
server_obj = self.controller.servers.get_server_obj(server_id) server_obj = self.controller.servers.get_server_obj(server_id)
compress = self.get_argument('compress', False)
check_changed = self.get_argument('changed') check_changed = self.get_argument('changed')
if str(check_changed) == str(1): if str(check_changed) == str(1):
checked = self.get_body_arguments('root_path') checked = self.get_body_arguments('root_path')
@ -1089,7 +1092,7 @@ class PanelHandler(BaseHandler):
server_obj = self.controller.servers.get_server_obj(server_id) server_obj = self.controller.servers.get_server_obj(server_id)
server_obj.backup_path = backup_path server_obj.backup_path = backup_path
self.controller.servers.update_server(server_obj) self.controller.servers.update_server(server_obj)
self.controller.management.set_backup_config(server_id, max_backups=max_backups, excluded_dirs=checked) self.controller.management.set_backup_config(server_id, max_backups=max_backups, excluded_dirs=checked, compress=bool(compress))
self.controller.management.add_to_audit_log(exec_user['user_id'], self.controller.management.add_to_audit_log(exec_user['user_id'],
f"Edited server {server_id}: updated backups", f"Edited server {server_id}: updated backups",
@ -1189,7 +1192,9 @@ class PanelHandler(BaseHandler):
"start_time": sch_time, "start_time": sch_time,
"enabled": enabled, "enabled": enabled,
"one_time": one_time, "one_time": one_time,
"cron_string": '' "cron_string": '',
"parent": None,
"delay": 0
} }
elif difficulty == "reaction": elif difficulty == "reaction":
job_data = { job_data = {
@ -1337,7 +1342,9 @@ class PanelHandler(BaseHandler):
"start_time": sch_time, "start_time": sch_time,
"enabled": enabled, "enabled": enabled,
"one_time": one_time, "one_time": one_time,
"cron_string": '' "cron_string": '',
"parent": None,
"delay": 0
} }
elif difficulty == "advanced": elif difficulty == "advanced":
job_data = { job_data = {

View File

@ -14,6 +14,7 @@
"virtual_terminal_lines": 70, "virtual_terminal_lines": 70,
"max_log_lines": 700, "max_log_lines": 700,
"max_audit_entries": 300, "max_audit_entries": 300,
"disabled_language_files": ["lol_EN.json", ""],
"keywords": ["help", "chunk"], "keywords": ["help", "chunk"],
"allow_nsfw_profile_pictures": false "allow_nsfw_profile_pictures": false
} }

View File

@ -55,6 +55,16 @@
<div class="form-group"> <div class="form-group">
<label for="server_path">{{ translate('serverBackups', 'maxBackups', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverBackups', 'maxBackupsDesc', data['lang']) }}</small> </label> <label for="server_path">{{ translate('serverBackups', 'maxBackups', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverBackups', 'maxBackupsDesc', data['lang']) }}</small> </label>
<input type="text" class="form-control" name="max_backups" id="max_backups" value="{{ data['backup_config']['max_backups'] }}" placeholder="{{ translate('serverBackups', 'maxBackups', data['lang']) }}" > <input type="text" class="form-control" name="max_backups" id="max_backups" value="{{ data['backup_config']['max_backups'] }}" placeholder="{{ translate('serverBackups', 'maxBackups', data['lang']) }}" >
</div>
<div class="form-group">
<label for="compress" class="form-check-label ml-4 mb-4"></label>
{% if data['backup_config']['compress'] %}
<input type="checkbox" class="form-check-input" id="compress" name="compress"
checked="" value="True">{{ translate('serverBackups', 'compress', data['lang']) }}
{% else %}
<input type="checkbox" class="form-check-input" id="compress" name="compress"
value="True">{{ translate('serverBackups', 'compress', data['lang']) }}
{% end %}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="server">{{ translate('serverBackups', 'exclusionsTitle', data['lang']) }} <small> - {{ translate('serverBackups', 'excludedChoose', data['lang']) }}</small></label> <label for="server">{{ translate('serverBackups', 'exclusionsTitle', data['lang']) }} <small> - {{ translate('serverBackups', 'excludedChoose', data['lang']) }}</small></label>

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns('backups', compress=peewee.BooleanField(default=False))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns('backups', ['compress'])
"""
Write your rollback migrations here.
"""

View File

@ -243,7 +243,8 @@
"excludedBackups": "Excluded Paths: ", "excludedBackups": "Excluded Paths: ",
"excludedChoose": "Choose the paths you wish to exclude from your backups", "excludedChoose": "Choose the paths you wish to exclude from your backups",
"clickExclude": "Click to select Exclusions", "clickExclude": "Click to select Exclusions",
"exclusionsTitle": "Backup Exclusions" "exclusionsTitle": "Backup Exclusions",
"compress": "Compress Backup"
}, },
"serverFiles": { "serverFiles": {
"noscript": "The file manager does not work without JavaScript", "noscript": "The file manager does not work without JavaScript",