# coding: utf-8 # ------------------------------------------------------------------- # 宝塔Linux面板 # ------------------------------------------------------------------- # Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved. # ------------------------------------------------------------------- # Author: miku # ------------------------------------------------------------------- import json import os import sys import time import sys import concurrent.futures import threading import hashlib import datetime import re if "/www/server/panel/class" not in sys.path: sys.path.insert(0, "/www/server/panel/class") if '/www/server/panel' not in sys.path: sys.path.insert(0, '/www/server/panel') import public from mod.project.backup_restore.base_util import BaseUtil from mod.project.backup_restore.data_manager import DataManager from mod.project.backup_restore.config_manager import ConfigManager # from .modules.base_module import BaseModule from mod.project.backup_restore.modules.site_module import SiteModule from mod.project.backup_restore.modules.database_module import DatabaseModule from mod.project.backup_restore.modules.soft_module import SoftModule from mod.project.backup_restore.modules.ftp_module import FtpModule from mod.project.backup_restore.modules.crontab_module import CrontabModule from mod.project.backup_restore.modules.ssh_module import SshModule from mod.project.backup_restore.modules.firewall_module import FirewallModule from mod.project.backup_restore.modules.plugin_module import PluginModule from mod.project.backup_restore.modules.mail_module import MailModule from mod.project.backup_restore.modules.node_module import NodeModule from mod.project.backup_restore.modules.panelconfig_module import PanelConfigModule # from .modules.database_module import DatabaseModule # from .modules.ftp_module import FTPModule # from .modules.terminal_module import TerminalModule # from .modules.firewall_module import FirewallModule # from .utils import print_log, get_file_sha256 class BackupManager(SiteModule,DatabaseModule,FtpModule,DataManager,BaseUtil,ConfigManager): def __init__(self): # self._init_modules() self.base_path = '/www/backup/backup_restore' self.bakcup_task_json = self.base_path + '/backup_task.json' self.backup_log_file = self.base_path + '/backup.log' self.backup_pl_file = self.base_path + '/backup.pl' self.backup_success_file = self.base_path + '/success.pl' self.backup_save_config = self.base_path + '/backup_save_config.json' self.history_log_path = '/www/backup/backup_restore/history/log' self.history_info_path = '/www/backup/backup_restore/history/info' self.migrate_backup_info_path = '/www/backup/backup_restore/migrate_backup_info.json' self.backup_err_log_path = '/www/backup/backup_restore/backup_err.log' # def _init_modules(self): # """初始化所有模块""" # self.modules = { # 'site': SiteModule(self.config_manager), # 'database': DatabaseModule(self.config_manager), # 'ftp': FTPModule(self.config_manager), # 'terminal': TerminalModule(self.config_manager), # 'firewall': FirewallModule(self.config_manager) # } def get_local_backup(self,get=None): backup_list=[] if os.path.exists(self.bakcup_task_json): backup_list=json.loads(public.ReadFile(self.bakcup_task_json)) file_names = os.listdir(self.base_path) pattern = re.compile(r"\d{8}-\d{4}_\d+_backup\.tar\.gz") matched_files = [f for f in file_names if pattern.match(f)] for file in matched_files: if "upload.tmp" in file: continue file_timestamp = file.split('_')[1] matched = any(item["timestamp"] == int(file_timestamp) for item in backup_list) if not matched: done_time=datetime.datetime.fromtimestamp(int(file_timestamp)).strftime('%Y-%m-%d %H:%M:%S') file_size = public.ExecShell("du -sb /www/backup/backup_restore/{}".format(file))[0].split("\t")[0] file_conf={} file_conf['backup_name'] = str(file) file_conf['timestamp']=int(file_timestamp) file_conf['create_time'] = done_time file_conf['backup_time'] = done_time file_conf['backup_file'] = self.base_path + "/" + file file_conf['storage_type'] = "local" file_conf['auto_exit'] = 0 file_conf['restore_status'] = 0 file_conf['backup_status'] = 2 file_conf['backup_path'] = self.base_path + "/" + file file_conf['done_time'] = done_time file_conf['backup_file_size'] = str(self.get_file_size(self.base_path + "/" + file)) file_conf['backup_file_sha256'] = self.get_file_sha256(self.base_path + "/" + file) file_conf['backup_count'] = {} file_conf['backup_count']['success'] = None file_conf['backup_count']['failed'] = None file_conf['total_time']=None backup_list.append(file_conf) if os.path.exists(self.migrate_backup_info_path): migrate_backup_info=json.loads(public.ReadFile(self.migrate_backup_info_path)) backup_list.append(migrate_backup_info) public.ExecShell("rm -f {}".format(self.migrate_backup_info_path)) public.WriteFile(self.bakcup_task_json,json.dumps(backup_list)) return backup_list #public.WriteFile(self.bakcup_task_json,json.dumps(backup_list)) # for file_name in os.listdir(self.base_path): # backup_file_path=self.base_path + "/" + file_name # if backup_file_path.endswith(".tar.gz"): # for backup_task in backup_list: # if backup_task.get('backup_file') == backup_file_path: # continue # else: # print(1) # stat_file = os.stat(backup_file_path) # file_data = { # "name": file_name, # "size": stat_file.st_size, # "timestamp": 123456789, # "backup_file": backup_file_path, # "backup_status": 2, # "backup_type": "local" # } # #backup_list.append(file_data) #print(backup_list) #return backup_list def get_backup_file_msg(self,timestamp): import tarfile backup_file=str(timestamp) + "_backup.tar.gz" print(backup_file) file_names = os.listdir(self.base_path) for file in file_names: if backup_file in file: backup_file=file path=self.base_path + "/" + backup_file path_data={} if not os.path.exists(path): return path_data try: with tarfile.open(path, 'r:gz') as tar: # 提前获取文件列表 members = tar.getnames() # 提取备份 JSON 配置 if '{}_backup/backup.json'.format(timestamp) in members: json_file_name = '{}_backup/backup.json'.format(timestamp) json_file = tar.extractfile(json_file_name) json_content = json_file.read().decode('utf-8') path_data['config'] = json.loads(json_content) # 提取备份日志文件 if '{}_backup/backup.log'.format(timestamp) in members: log_file_name = '{}_backup/backup.log'.format(timestamp) log_file = tar.extractfile(log_file_name) log_content = log_file.read().decode('utf-8') path_data['log'] = log_content + path + "\n打包完成" except: return False # path_data['server_config']=self.get_server_config() # path_data['backup_path_size']=25256044 # path_data['free_size'] = self.get_free_space()['free_space'] self.history_log_path = '/www/backup/backup_restore/history/log' self.history_info_path = '/www/backup/backup_restore/history/info' if not os.path.exists(self.history_log_path): public.ExecShell("mkdir -p {}".format(self.history_log_path)) if not os.path.exists(self.history_info_path): public.ExecShell("mkdir -p {}".format(self.history_info_path)) try: public.WriteFile(self.history_log_path + "{}_backup.log".format(timestamp),path_data['log']) except: pass try: public.WriteFile(self.history_info_path + "/{}_backup.info".format(timestamp),json.dumps(path_data['config'])) except: return False try: backup_task_info=self.get_backup_conf(timestamp) hitory_info=json.loads(public.ReadFile(self.history_info_path + "/{}_backup.info".format(timestamp))) hitory_info['create_time']=backup_task_info['create_time'] hitory_info['backup_time']=backup_task_info['backup_time'] hitory_info['backup_file']=backup_task_info['backup_file'] hitory_info['backup_path']=backup_task_info['backup_path'] hitory_info['done_time']=backup_task_info['done_time'] hitory_info['total_time']=backup_task_info['total_time'] hitory_info['backup_file_size']=backup_task_info['backup_file_size'] hitory_info['backup_file_sha256']=backup_task_info['backup_file_sha256'] public.WriteFile(self.history_info_path + "/{}_backup.info".format(timestamp),json.dumps(hitory_info)) except: pass #return path_data return True def add_backup_task(self,timestamp: int): backup_path=self.base_path + '/{timestamp}_backup/'.format(timestamp=timestamp) if not os.path.exists(backup_path): os.makedirs(backup_path) backup_conf=self.get_backup_conf(timestamp) if not backup_conf: print("备份配置文件不存在") return public.returnMsg(False, "备份配置文件不存在") backup_conf['data_list']={} backup_data_list=backup_conf['backup_data'] if "soft" in backup_data_list: backup_conf['data_list']['soft']=SoftModule().get_soft_data(timestamp) else: backup_conf['data_list']['soft']={} backup_conf['data_list']['site']=self.get_site_backup_conf(timestamp) if "database" in backup_data_list: backup_conf['data_list']['database']=self.get_database_backup_conf(timestamp) else: backup_conf['data_list']['database']={} if "ftp" in backup_data_list: backup_conf['data_list']['ftp']=self.backup_ftp_data(timestamp) else: backup_conf['data_list']['ftp']={} backup_conf['backup_status']=1 public.WriteFile(backup_path + 'backup.json',json.dumps(backup_conf)) def backup_data(self,timestamp: int): if os.path.exists(self.backup_log_file): public.ExecShell("rm -f {}".format(self.backup_log_file)) if os.path.exists(self.backup_pl_file): print("当前已有备份进程再运行!") return public.returnMsg(False, "当前已有备份进程再运行!") public.WriteFile(self.backup_pl_file,timestamp) backup_conf=self.get_backup_conf(timestamp) try: backup_data_list=backup_conf['backup_data'] except: backup_data_list=[] backup_data_list.extend(["soft","site","database","wp_tools","ftp","crontab","vmail","ssh","firewall","node","plugin"]) backup_conf['backup_data'] = backup_data_list backup_conf['database_id'] = '["ALL"]' backup_conf['site_id'] = '["ALL"]' self.save_backup_conf(timestamp,backup_conf) backup_conf['backup_status']=1 self.save_backup_conf(timestamp,backup_conf) start_time=int(time.time()) self.add_backup_task(timestamp) # 注释掉原来的代码 # try: # if "site" in backup_data_list: # self.backup_site_data(timestamp) # except: # pass # try: # if "database" in backup_data_list: # self.backup_database_data(timestamp) # except: # pass # try: # CrontabModule().backup_crontab_data(timestamp) # except: # pass # try: # SshModule().backup_ssh_data(timestamp) # except: # pass # try: # FirewallModule().backup_firewall_data(timestamp) # except: # pass # try: # MailModule().backup_vmail_data(timestamp) # except: # pass # try: # PluginModule().backup_plugin_data(timestamp) # except: # pass # try: # self.write_backup_data(timestamp) # except: # pass # 新的循环实现 for backup_type in backup_data_list: try: if backup_type == 'site': print(1) self.backup_site_data(timestamp) elif backup_type == 'database': self.backup_database_data(timestamp) elif backup_type == 'crontab': CrontabModule().backup_crontab_data(timestamp) elif backup_type == 'ssh': SshModule().backup_ssh_data(timestamp) elif backup_type == 'firewall': FirewallModule().backup_firewall_data(timestamp) elif backup_type == 'vmail': MailModule().backup_vmail_data(timestamp) elif backup_type == 'plugin': PluginModule().backup_plugin_data(timestamp) # elif backup_type == 'soft': # self.backup_soft_data(timestamp) elif backup_type == 'wp_tools': self.backup_wp_tools_data(timestamp) elif backup_type == 'ftp': self.backup_ftp_data(timestamp) elif backup_type == 'node': NodeModule().backup_node_data(timestamp) except Exception as e: public.WriteFile(self.backup_err_log_path,e) try: PanelConfigModule().backup_panel_config_data(timestamp) except: pass try: self.write_backup_data(timestamp) except: public.WriteFile(self.backup_err_log_path,e) end_time=int(time.time()) done_time=datetime.datetime.fromtimestamp(int(end_time)).strftime('%Y-%m-%d %H:%M:%S') total_time=end_time - start_time backup_conf=self.get_backup_conf(timestamp) backup_conf['backup_status']=2 backup_conf['done_time']=done_time backup_conf['total_time']=total_time self.save_backup_conf(timestamp,backup_conf) self.sync_backup_info(timestamp) public.WriteFile(self.backup_success_file,timestamp) public.ExecShell("rm -f {}".format(self.backup_pl_file)) self.create_history_file(timestamp) def create_history_file(self,timestamp): if not os.path.exists(self.history_log_path): public.ExecShell("mkdir -p {}".format(self.history_log_path)) if not os.path.exists(self.history_info_path): public.ExecShell("mkdir -p {}".format(self.history_info_path)) hitory_log_file=self.history_log_path + '/' + str(timestamp) + '_backup.log' history_info_file=self.history_info_path + '/' + str(timestamp) + '_backup.info' public.WriteFile(hitory_log_file,public.ReadFile("/www/backup/backup_restore/backup.log".format(timestamp))) public.WriteFile(history_info_file,public.ReadFile("/www/backup/backup_restore/{}_backup/backup.json".format(timestamp))) def sync_backup_info(self,timestamp): backup_conf=self.get_backup_conf(timestamp) data_list=self.get_backup_data_list(timestamp) data_list['backup_status']=backup_conf['backup_status'] data_list['backup_file']=backup_conf['backup_file'] data_list['backup_file_sha256']=backup_conf['backup_file_sha256'] data_list['backup_file_size']=backup_conf['backup_file_size'] data_list['done_time']=backup_conf['done_time'] data_list['total_time']=backup_conf['total_time'] data_list['backup_count']=backup_conf['backup_count'] self.update_backup_data_list(timestamp, data_list) def count_backup_status(self,data,status_code): return sum( 1 for category in data.values() for item in category if isinstance(item, dict) and item.get('status') == status_code ) def write_backup_data(self,timestamp): self.print_log("====================================================","backup") self.print_log("开始压缩打包所有数据","backup") from datetime import datetime # timestamp=get.timestamp backup_conf=self.get_backup_conf(timestamp) backup_log_path=self.base_path + str(timestamp) + "_backup/" public.ExecShell('\cp -rpa {} {}'.format(self.backup_log_file,backup_log_path)) conf_data=json.loads((public.ReadFile("/www/backup/backup_restore/{}_backup/backup.json".format(timestamp)))) status_2_count = self.count_backup_status(conf_data['data_list'], 2) status_3_count = self.count_backup_status(conf_data['data_list'], 3) dt_object = datetime.fromtimestamp(int(timestamp)) file_time = dt_object.strftime('%Y%m%d-%H%M') tar_file_name = file_time + "_" + str(timestamp) + "_backup.tar.gz" conf_data['backup_status']=1 public.WriteFile("/www/backup/backup_restore/{}_backup/backup.json".format(timestamp),json.dumps(conf_data)) public.ExecShell("cd /www/backup/backup_restore && tar -czvf {} {}_backup".format(tar_file_name,timestamp)) file_size = public.ExecShell("du -sb /www/backup/backup_restore/{}".format(tar_file_name))[0].split("\t")[0] time.sleep(1) #public.ExecShell("rm -rf /www/backup/backup_restore/{}_backup".format(timestamp)) backup_conf["backup_status"] = 2 backup_conf["backup_file"] = "/www/backup/backup_restore/" + tar_file_name backup_conf["backup_file_sha256"] = self.get_file_sha256("/www/backup/backup_restore/" + tar_file_name) backup_conf["backup_file_size"] = file_size backup_conf["backup_count"]={} backup_conf["backup_count"]['success'] = status_2_count backup_conf["backup_count"]['failed'] = status_3_count storage_type=backup_conf['storage_type'] print(backup_conf) backup_size=self.format_size(int(file_size)) self.print_log("压缩打包所有数据完成 数据大小:{}".format(backup_size),'backup') self.print_log("====================================================","backup") tar_file_name= "/www/backup/backup_restore/" + tar_file_name if storage_type != "local" and os.path.exists(tar_file_name): from CloudStoraUpload import CloudStoraUpload _cloud = CloudStoraUpload() self.print_log(f"测试连接云存储{storage_type}...","backup") if not self.test_cloud_connection(storage_type): self.print_log(f"无法连接到云存储:{storage_type}","backup") self.print_log("已经备份保存至本地") else: _cloud.run(storage_type) cloud_name_cn = _cloud.obj._title self.print_log("正在上传备份文件到{}...".format(cloud_name_cn),"backup") try: backup_path = _cloud.obj.backup_path if not backup_path.endswith('/'): backup_path += '/' upload_path = os.path.join(backup_path, "backup_restore", os.path.basename(tar_file_name)) if _cloud.cloud_upload_file(tar_file_name, upload_path): self.print_log(f"已成功上传到{cloud_name_cn}","backup") else: self.print_log(f"上传到{cloud_name_cn}失败","backup") except Exception as e: self.print_log(f"上传到{cloud_name_cn}时发生错误: {str(e)}","backup") self.save_backup_conf(timestamp,backup_conf) def add_backup(self, timestamp: int) -> dict: """添加备份任务""" try: backup_config = self.config_manager.get_backup_config() timestamp = int(time.time()) except: pass def test_get(self,get=None): result = self.get_backup_progress() print(result) def get_backup_progress(self, get=None): """ 获取备份进度信息 @param get: object 包含请求参数 @return: dict 备份进度信息 """ # 设置相关文件路径 backup_pl_file = self.base_path + '/backup.pl' backup_log_file = self.base_path + '/backup.log' backup_success_file = self.base_path + '/success.pl' # 创建处理已完成备份的函数,减少代码重复 def create_completed_result(backup_timestamp): if not backup_timestamp: return public.ReturnMsg(False, "备份完成但无法获取备份时间戳") if not os.path.exists(self.bakcup_task_json): return public.ReturnMsg(False, "备份配置文件不存在") backup_configs = json.loads(public.ReadFile(self.bakcup_task_json)) success_data = next((item for item in backup_configs if str(item.get('timestamp')) == str(backup_timestamp)), {}) err_info =[] # in_err={} # in_err['name']="php" # in_err['type']="环境" # in_err['msg']="缺少gd依赖库" # err_info.append(in_err) return { "task_type": "backup", "task_status": 2, "backup_data": None, "backup_name": None, "data_backup_status": 2, "progress": 100, "msg": None, 'task_msg': None, 'exec_log': public.ReadFile(backup_log_file) if os.path.exists(backup_log_file) else "", 'timestamp': backup_timestamp, 'backup_file_info': success_data, 'err_info': err_info } # 检查备份是否已完成 if os.path.exists(backup_success_file): success_time = int(os.path.getctime(backup_success_file)) local_time = int(time.time()) # 如果success文件创建时间在10秒内,说明备份刚刚完成 if success_time + 10 > local_time: try: backup_timestamp = public.ReadFile(backup_success_file).strip() return public.ReturnMsg(True,create_completed_result(backup_timestamp)) except Exception as e: public.ExecShell("rm -f {}".format(backup_success_file)) return public.ReturnMsg(False, f"获取备份完成信息出错: {str(e)}") else: # 超过10秒,删除success文件 public.ExecShell("rm -f {}".format(backup_success_file)) # 检查是否有备份进程运行 timestamp = "" try: # 检查备份进程锁文件 if os.path.exists(backup_pl_file): timestamp = public.ReadFile(backup_pl_file).strip() if not timestamp: return public.ReturnMsg(False, "备份进程正在运行,但无法获取备份时间戳") else: # 等待2秒,可能是备份刚刚完成 time.sleep(2) if os.path.exists(backup_success_file): success_time = int(os.path.getctime(backup_success_file)) local_time = int(time.time()) if success_time + 10 > local_time: backup_timestamp = public.ReadFile(backup_success_file).strip() return public.ReturnMsg(True,create_completed_result(backup_timestamp)) # 再次检查是否有备份进程 if os.path.exists(backup_pl_file): timestamp = public.ReadFile(backup_pl_file).strip() if not timestamp: return public.ReturnMsg(False, "备份进程正在运行,但无法获取备份时间戳") else: return public.ReturnMsg(False, "当前未找到备份任务,请在备份列表中查看是否备份完成") # 读取备份配置文件 backup_json_path = f"{self.base_path}/{timestamp}_backup/backup.json" if not os.path.exists(backup_json_path): return public.ReturnMsg(False, f"备份配置文件不存在: {backup_json_path}") conf_data = json.loads(public.ReadFile(backup_json_path)) except Exception as e: return public.ReturnMsg(False, f"获取备份进度信息出错: {str(e)}") # 读取备份日志 backup_log_data = public.ReadFile(backup_log_file) if os.path.exists(backup_log_file) else "" # 定义备份类型及其处理逻辑 backup_types = [ { 'type': 'site', 'data_key': 'site', 'display_name': '站点', 'progress': 30 }, { 'type': 'database', 'data_key': 'database', 'display_name': '数据库', 'progress': 60 }, { 'type': 'ftp', 'data_key': 'ftp', 'display_name': 'FTP用户', 'progress': 70 }, { 'type': 'terminal', 'data_key': 'terminal', 'display_name': '终端数据', 'progress': 75 }, { 'type': 'firewall', 'data_key': 'firewall', 'display_name': '防火墙规则', 'progress': 80 } ] # 检查各类型备份进度 for backup_type in backup_types: items = conf_data.get("data_list", {}).get(backup_type['data_key'], []) for item in items: try: if item.get("status") == 2: continue name = item.get("name", f"未知{backup_type['display_name']}") return public.ReturnMsg(True,{ "task_type": "backup", "task_status": 1, "data_type": backup_type['type'], "name": name, "data_backup_status": item.get("status", 0), "progress": backup_type['progress'], "msg": item.get("msg"), 'task_msg': f"当前正在备份{backup_type['display_name']} {name}", 'exec_log': backup_log_data, 'timestamp': timestamp }) except: return public.ReturnMsg(True,{ "task_type": "backup", "task_status": 1, "data_type": "服务器配置", "name": "服务器配置", "data_backup_status": 1, "progress": 80, "msg": "正在备份服务器配置", 'task_msg': f"当前正在备份各项服务器配置", 'exec_log': backup_log_data, 'timestamp': timestamp }) # 检查数据打包进度 try: backup_status = conf_data.get('backup_status') if backup_status == 1: return public.ReturnMsg(True,{ "task_type": "backup", "task_status": 1, "data_type": "tar", "name": "数据打包", "data_backup_status": 1, "progress": 90, 'task_msg': "当前正在压缩数据包", 'exec_log': backup_log_data, 'timestamp': timestamp }) except Exception: # 可能没有backup_status字段,继续处理 pass # 如果没有发现进行中的任务,但有备份进程 if timestamp: return { "backup_data": "unknown", "backup_name": "未知任务", "data_backup_status": 1, "progress": 10, 'backup_msg': "正在准备备份数据", 'backup_log': backup_log_data, 'timestamp': timestamp } return public.ReturnMsg(False, "当前未找到正在进行的备份任务,请在备份列表中查看是否备份完成") def get_backup_details(self, timestamp): history_info_file = self.history_info_path + '/' + str(timestamp) + '_backup.info' if not os.path.exists(history_info_file): get_info=self.get_backup_file_msg(timestamp) if not get_info: return { "status": False, "msg": "获取详情失败", "error_msg": "备份信息文件不存在", "data": {} } # try: backup_info = json.loads(public.ReadFile(history_info_file)) try: disk_use = int(backup_info.get("backup_file_size", 0)) * 2 except: disk_use = backup_info.get("backup_file_size", 0) # 提取基本信息 result = { "status": True, "msg": "获取详情成功", "error_msg": "", "data": { "type": "backup", "done_time": backup_info.get("done_time", ""), "total_time": backup_info.get("total_time", 0), "backup_file": backup_info.get("backup_file", ""), "backup_file_size": backup_info.get("backup_file_size", "0"), "backup_file_sha256": backup_info.get("backup_file_sha256", ""), "disk_use": disk_use, "disk_free": BaseUtil.get_free_space(self)['free_space'], "data_status": { "env_list": [], "site_list": [], "database_list": [], "ftp_list": [], "crontab_list": {}, "ssh_list": {}, "firewall_list": {}, "plugin_list": [], "vmail_list": [], "btnode_list": [], "soft_data": [] } } } # 处理软件列表 if "soft" in backup_info['data_list']: soft_data = backup_info["data_list"]["soft"] soft_list = [] # 处理Web服务器 if "web_server" in soft_data and soft_data["web_server"]: soft_list.append({ "name": soft_data["web_server"].get("name", ""), "version": soft_data["web_server"].get("version", ""), "size": soft_data["web_server"].get("size", 0) }) # 处理PHP版本 if "php_server" in soft_data and soft_data["php_server"]: for php in soft_data["php_server"]: soft_list.append({ "name": php.get("name", ""), "version": php.get("version", ""), "size": php.get("size", 0) }) # 处理MySQL服务器 if "mysql_server" in soft_data and soft_data["mysql_server"]: soft_list.append({ "name": soft_data["mysql_server"].get("type", "mysql"), "version": soft_data["mysql_server"].get("version", ""), "size": soft_data["mysql_server"].get("size", 0) }) # 处理FTP服务器 if "ftp_server" in soft_data and soft_data["ftp_server"]: soft_list.append({ "name": soft_data["ftp_server"].get("name", ""), "version": soft_data["ftp_server"].get("version", ""), "size": soft_data["ftp_server"].get("size", 0) }) # 处理JDK列表 if "jdk_list" in soft_data and soft_data["jdk_list"]: for jdk in soft_data["jdk_list"]: soft_list.append({ "name": jdk.get("name", ""), "version": jdk.get("version", ""), "size": jdk.get("size", 0) }) # 处理Node列表 if "node_list" in soft_data and soft_data["node_list"]: for node in soft_data["node_list"]: soft_list.append({ "name": node.get("name", ""), "version": node.get("version", ""), "size": node.get("size", 0) }) # 处理Tomcat列表 if "tomcat_list" in soft_data and soft_data["tomcat_list"]: for tomcat in soft_data["tomcat_list"]: soft_list.append({ "name": tomcat.get("name", ""), "version": tomcat.get("version", ""), "size": tomcat.get("size", 0) }) # 处理Redis服务器 if "redis_server" in soft_data and soft_data["redis_server"]: soft_list.append({ "name": soft_data["redis_server"].get("name", ""), "version": soft_data["redis_server"].get("version", ""), "size": soft_data["redis_server"].get("size", 0) }) # 处理Memcached服务器 if "memcached_server" in soft_data and soft_data["memcached_server"]: soft_list.append({ "name": soft_data["memcached_server"].get("name", ""), "version": soft_data["memcached_server"].get("version", ""), "size": soft_data["memcached_server"].get("size", 0) }) # 处理MongoDB服务器 if "mongodb_server" in soft_data and soft_data["mongodb_server"]: soft_list.append({ "name": soft_data["mongodb_server"].get("name", ""), "version": soft_data["mongodb_server"].get("version", ""), "size": soft_data["mongodb_server"].get("size", 0) }) # 处理PostgreSQL服务器 if "pgsql_server" in soft_data and soft_data["pgsql_server"]: soft_list.append({ "name": soft_data["pgsql_server"].get("name", ""), "version": soft_data["pgsql_server"].get("version", ""), "size": soft_data["pgsql_server"].get("size", 0) }) # 处理phpMyAdmin if "phpmyadmin_version" in soft_data and soft_data["phpmyadmin_version"]: soft_list.append({ "name": soft_data["phpmyadmin_version"].get("name", ""), "version": soft_data["phpmyadmin_version"].get("version", ""), "size": soft_data["phpmyadmin_version"].get("size", 0) }) # 添加到结果中 result["data"]["data_status"]["soft_data"] = soft_list # 添加软件数据到环境列表 for soft in soft_list: result["data"]["data_status"]["env_list"].append({ "name": soft.get("name", ""), "version": soft.get("version", ""), "size": soft.get("size", 0), "status": 2, "err_msg": None }) # 处理网站列表 if "data_list" in backup_info and "site" in backup_info["data_list"]: for site in backup_info["data_list"]["site"]: result["data"]["data_status"]["site_list"].append({ "name": site.get("name", ""), "type": site.get("project_type", ""), "size": site.get("size", 0), "status": site.get("status", 0), "err_msg": site.get("msg", None) }) # 处理数据库列表 if "data_list" in backup_info and "database" in backup_info["data_list"]: for db in backup_info["data_list"]["database"]: result["data"]["data_status"]["database_list"].append({ "name": db.get("name", ""), "type": db.get("type", ""), "size": db.get("size", 0), "status": db.get("status", 0), "err_msg": db.get("msg", None) }) # 处理FTP列表 if "data_list" in backup_info and "ftp" in backup_info["data_list"]: for ftp in backup_info["data_list"]["ftp"]: result["data"]["data_status"]["ftp_list"].append({ "name": ftp.get("name", ""), "size": ftp.get("size", 0), "status": ftp.get("status", 0), "err_msg": ftp.get("msg", None) }) # 处理计划任务 if "data_list" in backup_info and "crontab" in backup_info["data_list"]: crontab_data = backup_info["data_list"]["crontab"] try: if crontab_data["crontab_json"]: if os.path.exists(crontab_data["crontab_json"]): crontab_data["crontab_json"] = json.loads(public.ReadFile(crontab_data["crontab_json"])) crontab_list=[] for crontab in crontab_data["crontab_json"]: crontab_list.append({ "name": crontab.get("name", ""), "size": crontab.get("id", 0), "status": 2, "err_msg": None }) result["data"]["data_status"]["crontab_list"] = crontab_list except: result["data"]["data_status"]["crontab_list"] = { "crontab_count": 0, "crontab_size": 0, "status": 2, "err_msg": None } # 处理SSH列表 if "data_list" in backup_info and "ssh" in backup_info["data_list"]: ssh_data = backup_info["data_list"]["ssh"] result["data"]["data_status"]["ssh_list"] = { "ssh_size": ssh_data.get("ssh_size", 0), "command_size": ssh_data.get("command_size", 0), "status": 2, "err_msg": None } # 处理防火墙列表 if "data_list" in backup_info and "firewall" in backup_info["data_list"]: firewall_data = backup_info["data_list"]["firewall"] result["data"]["data_status"]["firewall_list"] = { "port_size": firewall_data.get("firewall_forward", 0), "ip_rule_size": firewall_data.get("firewall_ip", 0), "status": 2, "err_msg": None } # 处理插件列表 if "data_list" in backup_info and "plugin" in backup_info["data_list"]: plugin_data = backup_info["data_list"]["plugin"] # 检查插件数据格式 if isinstance(plugin_data, dict): # 新格式:{"plugin_name": {"status": x, "err_msg": y}} for plugin_name, plugin_info in plugin_data.items(): display_name = self.get_plugin_display_name(plugin_name) plugin_item = { "name": display_name, "display_name": display_name, "size": plugin_info.get("size", 0), "status": plugin_info.get("status", 2), "err_msg": plugin_info.get("err_msg", None) } result["data"]["data_status"]["plugin_list"].append(plugin_item) else: # 旧格式:[{"name": x, "size": y}] for plugin in plugin_data: plugin_name = plugin.get("name", "") display_name = self.get_plugin_display_name(plugin_name) result["data"]["data_status"]["plugin_list"].append({ "name": display_name, "display_name": display_name, "size": plugin.get("size", 0), "status": 2, "err_msg": None }) if "data_list" in backup_info and "vmail" in backup_info["data_list"]: vmail_data = backup_info["data_list"]["vmail"] result["data"]["data_status"]["vmail_list"].append({ "name": "邮局数据", "vmail_size": vmail_data.get("size", 0), "status": 2, "err_msg": None }) if "data_list" in backup_info and "node" in backup_info["data_list"]: node_data = backup_info["data_list"]["node"]["node_list"] for node in node_data: result["data"]["data_status"]["btnode_list"].append({ "name": node.get("name", ""), "server_ip": node.get("server_ip", ""), "status": 2, "err_msg": None }) return result # except Exception as e: # return { # "status": False, # "msg": "获取详情失败", # "error_msg": str(e), # "data": {} # } def get_backup_log(self,timestamp): backup_log_file = self.base_path + '/backup.log' history_log_file=self.history_log_path + '/' + str(timestamp) + '_backup.log' if os.path.exists(self.backup_pl_file): backup_timestamp=int(public.ReadFile(self.backup_pl_file)) if int(backup_timestamp) == int(timestamp): return public.ReadFile(backup_log_file) if os.path.exists(history_log_file): return public.ReadFile(history_log_file) else: return None def get_plugin_display_name(self, plugin_name): """获取插件的显示名称""" plugin_display_names = { "btwaf": "nginx防火墙", "monitor": "网站监控报表", "tamper_core": "企业级防篡改", "syssafe": "系统加固" } return plugin_display_names.get(plugin_name, plugin_name) def test_cloud_connection(self,cloud_name): """云存储连接测试""" from CloudStoraUpload import CloudStoraUpload _cloud = CloudStoraUpload() obj = _cloud.run(cloud_name) # cloud_name 如: 'alioss', 'qiniu', 'txcos' 等 if not obj: return False try: _cloud.obj.get_list('/') return True except: try: _cloud.obj.get_list(_cloud.obj.backup_path) return True except: return False if __name__ == '__main__': # 获取命令行参数 if len(sys.argv) < 3: print("Usage: btpython backup_manager.py ") sys.exit(1) method_name = sys.argv[1] # 方法名 timestamp = sys.argv[2] # IP地址 backup_manager = BackupManager() # 实例化对象 if hasattr(backup_manager, method_name): # 检查方法是否存在 method = getattr(backup_manager, method_name) # 获取方法 method(timestamp) # 调用方法 else: print(f"Error: 方法 '{method_name}' 不存在")