Put support logs into a thread.

This commit is contained in:
Andrew 2022-01-13 20:42:53 -05:00
parent 4a78f3c4bd
commit 8424fc3149
6 changed files with 124 additions and 53 deletions

View File

@ -47,6 +47,10 @@ class Users_Controller:
def user_query(user_id): def user_query(user_id):
return users_helper.user_query(user_id) return users_helper.user_query(user_id)
@staticmethod
def set_support_path(user_id, support_path):
users_helper.set_support_path(user_id, support_path)
@staticmethod @staticmethod
def update_user(user_id, user_data={}, user_crafty_data={}): def update_user(user_id, user_data={}, user_crafty_data={}):
base_data = users_helper.get_user(user_id) base_data = users_helper.get_user(user_id)

View File

@ -43,6 +43,7 @@ class Users(Model):
superuser = BooleanField(default=False) superuser = BooleanField(default=False)
api_token = CharField(default="", unique=True, index=True) # we may need to revisit this api_token = CharField(default="", unique=True, index=True) # we may need to revisit this
lang = CharField(default="en_EN") lang = CharField(default="en_EN")
support_logs = CharField(default = '')
class Meta: class Meta:
table_name = "users" table_name = "users"
@ -119,6 +120,7 @@ class helper_users:
'api_token': None, 'api_token': None,
'roles': [], 'roles': [],
'servers': [], 'servers': [],
'support_logs': '',
} }
user = model_to_dict(Users.get(Users.user_id == user_id)) user = model_to_dict(Users.get(Users.user_id == user_id))
@ -171,6 +173,10 @@ class helper_users:
user = Users.get(Users.user_id == user_id) user = Users.get(Users.user_id == user_id)
return user.delete_instance() return user.delete_instance()
@staticmethod
def set_support_path(user_id, support_path):
Users.update(support_logs = support_path).where(Users.user_id == user_id).execute()
@staticmethod @staticmethod
def user_id_exists(user_id): def user_id_exists(user_id):
if not users_helper.get_user(user_id): if not users_helper.get_user(user_id):

View File

@ -3,6 +3,7 @@ import pathlib
import time import time
import logging import logging
import sys import sys
from app.classes.models.server_permissions import Enum_Permissions_Server
from app.classes.models.users import helper_users from app.classes.models.users import helper_users
from peewee import DoesNotExist from peewee import DoesNotExist
import schedule import schedule
@ -13,6 +14,7 @@ import tempfile
import zipfile import zipfile
from distutils import dir_util from distutils import dir_util
from app.classes.models.management import helpers_management from app.classes.models.management import helpers_management
from app.classes.web.websocket_helper import websocket_helper
from app.classes.shared.helpers import helper from app.classes.shared.helpers import helper
from app.classes.shared.console import console from app.classes.shared.console import console
@ -128,6 +130,43 @@ class Controller:
else: else:
return False return False
def package_support_logs(self, exec_user):
websocket_helper.broadcast_user(exec_user['user_id'], 'notification', 'Preparing your support logs')
tempDir = tempfile.mkdtemp()
tempZipStorage = tempfile.mkdtemp()
full_temp = os.path.join(tempDir, 'support_logs')
os.mkdir(full_temp)
tempZipStorage = os.path.join(tempZipStorage, "support_logs")
crafty_path = os.path.join(full_temp, "crafty")
os.mkdir(crafty_path)
server_path = os.path.join(full_temp, "server")
os.mkdir(server_path)
if exec_user['superuser']:
auth_servers = self.servers.get_all_defined_servers()
else:
user_servers = self.servers.get_authorized_servers(int(exec_user['user_id']))
auth_servers = []
for server in user_servers:
if Enum_Permissions_Server.Logs in self.server_perms.get_user_permissions_list(exec_user['user_id'], server["server_id"]):
auth_servers.append(server)
else:
logger.info("Logs permission not available for server {}. Skipping.".format(server["server_name"]))
#we'll iterate through our list of log paths from auth servers.
for server in auth_servers:
final_path = os.path.join(server_path, str(server['server_name']))
os.mkdir(final_path)
shutil.copy(server['log_path'], final_path)
#Copy crafty logs to archive dir
full_log_name = os.path.join(crafty_path, 'logs')
shutil.copytree("logs", full_log_name)
shutil.make_archive(tempZipStorage, "zip", tempDir)
tempZipStorage += '.zip'
websocket_helper.broadcast_user(exec_user['user_id'], 'send_logs_bootbox', {
})
self.users.set_support_path(exec_user['user_id'], tempZipStorage)
@staticmethod @staticmethod
def add_system_user(): def add_system_user():
helper_users.add_user("system", helper.random_string_generator(64), "default@example.com", helper_users.new_api_token(), False, False) helper_users.add_user("system", helper.random_string_generator(64), "default@example.com", helper_users.new_api_token(), False, False)

View File

@ -26,6 +26,7 @@ from app.classes.models.crafty_permissions import Enum_Permissions_Crafty, Permi
from app.classes.models.management import management_helper from app.classes.models.management import management_helper
from app.classes.shared.helpers import helper from app.classes.shared.helpers import helper
from app.classes.web.websocket_helper import WebSocketHelper
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -769,63 +770,44 @@ class PanelHandler(BaseHandler):
del chunk del chunk
self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id)) self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id))
elif page == "support_logs": elif page == 'download_support_package':
logger.info("Support logs requested. Packinging logs for user with ID: {}".format(exec_user_id)) tempZipStorage = exec_user['support_logs']
tempDir = tempfile.mkdtemp() #We'll reset the support path for this user now.
tempZipStorage = tempfile.mkdtemp() self.controller.users.set_support_path(exec_user_id, "")
full_temp = os.path.join(tempDir, 'support_logs')
os.mkdir(full_temp)
tempZipStorage = os.path.join(tempZipStorage, "support_logs")
crafty_path = os.path.join(full_temp, "crafty")
os.mkdir(crafty_path)
server_path = os.path.join(full_temp, "server")
os.mkdir(server_path)
if exec_user['superuser']:
auth_servers = self.controller.servers.get_all_defined_servers()
else:
user_servers = self.controller.servers.get_authorized_servers(int(exec_user_id))
auth_servers = []
for server in user_servers:
if Enum_Permissions_Server.Logs in self.controller.server_perms.get_user_permissions_list(exec_user['user_id'], server["server_id"]):
auth_servers.append(server)
else:
logger.info("Logs permission not available for server {}. Skipping.".format(server["server_name"]))
#we'll iterate through our list of log paths from auth servers.
for server in auth_servers:
final_path = os.path.join(server_path, str(server['server_name']))
os.mkdir(final_path)
shutil.copy(server['log_path'], final_path)
#Copy crafty logs to archive dir
full_log_name = os.path.join(crafty_path, 'logs')
shutil.copytree("logs", full_log_name)
shutil.make_archive(tempZipStorage, "zip", tempDir)
tempZipStorage += '.zip'
self.set_header('Content-Type', 'application/octet-stream') self.set_header('Content-Type', 'application/octet-stream')
self.set_header('Content-Disposition', 'attachment; filename=' + "support_logs.zip") self.set_header('Content-Disposition', 'attachment; filename=' + "support_logs.zip")
chunk_size = 1024 * 1024 * 4 # 4 MiB chunk_size = 1024 * 1024 * 4 # 4 MiB
if tempZipStorage != '':
with open(tempZipStorage, 'rb') as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
try:
self.write(chunk) # write the chunk to response
self.flush() # send the chunk to client
except iostream.StreamClosedError:
# this means the client has closed the connection
# so break the loop
break
finally:
# deleting the chunk is very important because
# if many clients are downloading files at the
# same time, the chunks in memory will keep
# increasing and will eat up the RAM
del chunk
self.redirect('/panel/dashboard')
else:
self.redirect('/panel/error?error=No path found for support logs')
return
with open(tempZipStorage, 'rb') as f: elif page == "support_logs":
while True: logger.info("Support logs requested. Packinging logs for user with ID: {}".format(exec_user_id))
chunk = f.read(chunk_size) logs_thread = threading.Thread(target=self.controller.package_support_logs, daemon=True, args=(exec_user,), name='{}_logs_thread'.format(exec_user['user_id']))
if not chunk: logs_thread.start()
break self.redirect('/panel/dashboard')
try: return
self.write(chunk) # write the chunk to response
self.flush() # send the chunk to client
except iostream.StreamClosedError:
# this means the client has closed the connection
# so break the loop
break
finally:
# deleting the chunk is very important because
# if many clients are downloading files at the
# same time, the chunks in memory will keep
# increasing and will eat up the RAM
del chunk

View File

@ -237,6 +237,30 @@ if (webSocket) {
}) })
}); });
} }
if (webSocket) {
webSocket.on('send_logs_bootbox', function (server_id) {
var x = document.querySelector('.bootbox');
if(x){
x.remove()}
var x = document.querySelector('.modal-backdrop');
if(x){
x.remove()}
bootbox.alert({
title: 'Download Support Logs?',
message: "We've finished preparing your support logs. Please click download to download",
buttons: {
ok: {
label: 'Download',
className: 'btn-info'
}
},
callback: function(){
console.log("in callback")
location.href="/panel/download_support_package";
}
});
});
}
if (webSocket) { if (webSocket) {
webSocket.on('send_eula_bootbox', function (server_id) { webSocket.on('send_eula_bootbox', function (server_id) {

View File

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