Initial YakPanel commit

This commit is contained in:
Niranjan
2026-04-07 02:04:22 +05:30
commit 2826d3e7f3
5359 changed files with 1390724 additions and 0 deletions

View File

@@ -0,0 +1,197 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: miku <miku@yakpanel.com>
# -------------------------------------------------------------------
import json
import os
import re
import sys
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
if "/www/server/panel" not in sys.path:
sys.path.insert(0, "/www/server/panel")
import public
from YakPanel import app
import crontab_v2 as crontab
from mod.project.backup_restore.base_util import BaseUtil
from mod.project.backup_restore.config_manager import ConfigManager
class CrontabModule(BaseUtil, ConfigManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
def backup_crontab_data(self, timestamp):
self.print_log("====================================================", "backup")
self.print_log(public.lang("Starting a Backup Scheduled Task"), "backup")
backup_path = self.base_path + "/{timestamp}_backup/crontab".format(timestamp=timestamp)
if not os.path.exists(backup_path):
public.ExecShell('mkdir -p {}'.format(backup_path))
field = ('id,name,type,where1,where_hour,where_minute,echo,addtime,status,'
'save,backupTo,sName,sBody,sType,urladdress,save_local,notice,'
'notice_channel,db_type,split_type,split_value,type_id,rname,'
'keyword,post_param,flock,time_set,backup_mode,db_backup_path,'
'time_type,special_time,log_cut_path,user_agent,version,table_list,result,second')
crontab_data = public.M('crontab').order("id asc").field(field).select()
for task in crontab_data:
task['type_id'] = ""
crontab_json_path = "{}/crontab.json".format(backup_path)
public.WriteFile(crontab_json_path, json.dumps(crontab_data))
for item in crontab_data:
self.print_log(public.lang("Crontab Task {}".format(item['name'])), "backup")
public.ExecShell(f"\cp -rpa /www/server/cron/* {backup_path}/")
crontab_info = {
'status': 2,
'msg': None,
'crontab_json': crontab_json_path,
'file_sha256': self.get_file_sha256(crontab_json_path)
}
self.print_log(public.lang("Backup Crontab Task completion"), 'backup')
data_list = self.get_backup_data_list(timestamp)
data_list['data_list']['crontab'] = crontab_info
self.update_backup_data_list(timestamp, data_list)
def _add_crontab(self, crontab_item: dict, timestamp: int) -> None:
if crontab_item['name'] in ("Domain SSL Renew Let's Encrypt Certificate", "Renew Let's Encrypt Certificate"):
import acme_v2
if crontab_item['name'] == "Domain SSL Renew Let's Encrypt Certificate":
acme_v2.acme_v2().set_crond_v2()
elif crontab_item['name'] == "Renew Let's Encrypt Certificate":
acme_v2.acme_v2().set_crond()
self.print_log(
public.lang(f"Crontab Task: {crontab_item['name']} Add successfully ✓"),
"restore"
)
return
if crontab_item['name'] == "[Do not delete] Resource Manager - Get Process Traffic":
return
s_body = crontab_item['sBody']
s_body = re.sub(r'sudo -u .*? bash -c \'(.*?)\'', r'\1', s_body)
new_crontab = {
"name": crontab_item['name'],
"echo": crontab_item['echo'],
"type": crontab_item['type'],
"where1": crontab_item['where1'],
"hour": crontab_item['where_hour'],
"minute": crontab_item['where_minute'],
"status": crontab_item['status'],
"save": crontab_item['save'],
"backupTo": crontab_item['backupTo'],
"sType": crontab_item['sType'],
"sBody": s_body,
"sName": crontab_item['sName'],
"urladdress": crontab_item['urladdress'],
"save_local": crontab_item['save_local'],
"notice": crontab_item['notice'],
"notice_channel": crontab_item['notice_channel'],
"db_type": crontab_item['db_type'],
"split_type": crontab_item['split_type'],
"split_value": crontab_item['split_value'],
"keyword": crontab_item['keyword'],
"post_param": crontab_item['post_param'],
"flock": crontab_item['flock'],
"time_set": crontab_item['time_set'],
"backup_mode": crontab_item['backup_mode'],
"db_backup_path": crontab_item['db_backup_path'],
"time_type": crontab_item['time_type'],
"special_time": crontab_item['special_time'],
"user_agent": crontab_item['user_agent'],
"version": crontab_item['version'],
"table_list": crontab_item['table_list'],
"result": crontab_item['result'],
"log_cut_path": crontab_item['log_cut_path'],
"rname": crontab_item['rname'],
"type_id": crontab_item['type_id'],
"second": crontab_item.get('second', ''),
}
result = crontab.crontab().AddCrontab(new_crontab)
crontab_backup_path = self.base_path + f"/{timestamp}_backup/crontab"
back_up_echo_file = os.path.join(crontab_backup_path, crontab_item['echo'])
panel_echo_file = f"/www/server/cron/{crontab_item['echo']}"
if self.overwrite or not os.path.exists(panel_echo_file):
public.ExecShell(
f"\cp -rpa {back_up_echo_file} {panel_echo_file}"
)
if result['status'] != 0:
error_res = public.find_value_by_key(result, key="result", default="fail")
self.print_log(
public.lang(
f"Crontab Task: {crontab_item['name']} add fail, "
f"error: {error_res}, skip..."),
"restore"
)
else:
self.print_log(
public.lang(f"Crontab Task: {crontab_item['name']} Add successfully ✓"),
"restore"
)
def restore_crontab_data(self, timestamp):
self.print_log("==================================", "restore")
self.print_log(public.lang("Start restoring Crontab Task"), "restore")
restore_data = self.get_restore_data_list(timestamp)
cron_list = public.M('crontab').select()
cron_name_list = [i['name'] for i in cron_list]
crontab_data_json = restore_data['data_list']['crontab']['crontab_json']
restore_data['data_list']['crontab']['restore_status'] = 1
self.update_restore_data_list(timestamp, restore_data)
crontab_data = json.loads(public.ReadFile(crontab_data_json))
with app.app_context():
for crontab_item in crontab_data:
if self.overwrite:
try:
crontab.crontab().DelCrontab(public.to_dict_obj({"id": crontab_item['id']}))
except:
pass
self._add_crontab(crontab_item, timestamp)
else: # not overwrite
if crontab_item['name'] not in cron_name_list:
self._add_crontab(crontab_item, timestamp)
else:
self.print_log(public.lang(f"Crontab Task: {crontab_item['name']}"), "restore")
self.print_log(public.lang("Crontab Task complished"), "restore")
restore_data['data_list']['crontab']['restore_status'] = 2
self.update_restore_data_list(timestamp, restore_data)
def reload_crontab(self):
try:
crontab.crontab().CrondReload()
except:
pass
if __name__ == '__main__':
# 获取命令行参数
if len(sys.argv) < 2:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1] # 方法名
timestamp = sys.argv[2]
crontab_manager = CrontabModule() # 实例化对象
if hasattr(crontab_manager, method_name): # 检查方法是否存在
method = getattr(crontab_manager, method_name) # 获取方法
method(timestamp) # 调用方法
else:
print(f"Error: method '{method_name}' not found")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: miku <miku@yakpanel.com>
# -------------------------------------------------------------------
import os
import sys
import warnings
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
if "/www/server/panel" not in sys.path:
sys.path.insert(0, "/www/server/panel")
import public
from YakPanel import app
from mod.project.backup_restore.base_util import BaseUtil
from mod.project.backup_restore.config_manager import ConfigManager
from firewallModelV2.comModel import main as firewall_com
from safeModelV2.firewallModel import main as safe_firewall_main
warnings.filterwarnings("ignore", category=SyntaxWarning)
class FirewallModule(BaseUtil, ConfigManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
def backup_firewall_data(self, timestamp):
with app.app_context():
try:
self.print_log("====================================================", "backup")
self.print_log(public.lang("Starting backup of firewall data"), "backup")
backup_path = self.base_path + "/{timestamp}_backup/firewall".format(timestamp=timestamp)
if not os.path.exists(backup_path):
public.ExecShell('mkdir -p {}'.format(backup_path))
data_list = self.get_backup_data_list(timestamp)
port_data_path = firewall_com().export_rules(
public.to_dict_obj({"rule": 'port', 'chain': 'ALL'})
)['message'].get('result', '')
ip_data_path = firewall_com().export_rules(
public.to_dict_obj({"rule": 'ip', 'chain': 'ALL'})
)['message'].get('result', '')
forward_data_path = firewall_com().export_rules(
public.to_dict_obj({"rule": 'forward'})
)['message'].get('result', '')
country_data_path = safe_firewall_main().export_rules(
public.to_dict_obj({'rule_name': 'country_rule'})
)['message'].get('result', '')
firewall_info = {
"status": 2,
"err_msg": None
}
for data_path in [
port_data_path, ip_data_path, forward_data_path, country_data_path
]:
if "json" in data_path:
public.ExecShell('\cp -rpa {} {}'.format(data_path, backup_path))
file_name = data_path.split("/")[-1]
if "port_rule" in file_name:
self.print_log(public.lang("Firewall port rules ✓"), 'backup')
firewall_info["port_data_path"] = backup_path + "/" + file_name
elif "ip_rules" in file_name:
self.print_log(public.lang("Firewall IP rules ✓"), 'backup')
firewall_info["ip_data_path"] = backup_path + "/" + file_name
elif "port_forward" in file_name:
self.print_log(public.lang("Firewall forwarding rules ✓"), 'backup')
firewall_info["forward_data_path"] = backup_path + "/" + file_name
elif "country" in file_name:
self.print_log(public.lang("Firewall region rules ✓"), 'backup')
firewall_info["country_data_path"] = backup_path + "/" + file_name
# 将防火墙信息写入备份配置文件
data_list = self.get_backup_data_list(timestamp)
data_list['data_list']['firewall'] = firewall_info
self.update_backup_data_list(timestamp, data_list)
except Exception as e:
data_list['data_list']['firewall'] = {
"status": 3,
"err_msg": e
}
self.update_backup_data_list(timestamp, data_list)
self.print_log(public.lang("Firewall data backup completed"), "backup")
def init_firewall_data(self):
self.print_log(public.lang("Initializing firewall data"), "restore")
if not os.path.exists('/etc/systemd/system/BT-FirewallServices.service'):
panel_path = public.get_panel_path()
exec_shell = '('
if not os.path.exists('/usr/sbin/ipset'):
exec_shell = exec_shell + '{} install ipset -y;'.format(public.get_sys_install_bin())
exec_shell = exec_shell + 'sh {panel_path}/script/init_firewall.sh;btpython -u {panel_path}/script/upgrade_firewall.py )'.format(
panel_path=panel_path
)
public.ExecShell(exec_shell)
return {'status': True, 'msg': public.lang('Installed.')}
elif public.ExecShell("iptables -C INPUT -j IN_BT")[1] != '': # 丢失iptable链 需要重新创建
exec_shell = 'sh {}/script/init_firewall.sh'.format(public.get_panel_path())
public.ExecShell(exec_shell)
return {'status': True, 'msg': public.lang('Installed.')}
else:
return {'status': True, 'msg': public.lang('Installed.')}
def restore_firewall_data(self, timestamp):
with app.app_context():
self.print_log("====================================================", "restore")
self.print_log(public.lang("Starting restoration of firewall data"), "restore")
self.init_firewall_data()
resotre_data = self.get_restore_data_list(timestamp)
firewall_data = resotre_data['data_list']['firewall']
port_rule_file = firewall_data.get('port_data_path')
try:
if port_rule_file:
if os.path.exists(port_rule_file):
self.print_log(public.lang("Starting restoration of firewall port rules"), "restore")
result = firewall_com().import_rules(public.to_dict_obj({"rule": 'port', 'file': port_rule_file}))
if result['status'] == 0:
self.print_log(public.lang("Firewall port rules restored successfully ✓"), "restore")
else:
self.print_log(public.lang("Failed to restore firewall port rules"), "restore")
ip_rule_file = firewall_data.get('ip_data_path')
if ip_rule_file:
if os.path.exists(ip_rule_file):
self.print_log(public.lang("Starting restoration of firewall IP rules"), "restore")
result = firewall_com().import_rules(public.to_dict_obj({"rule": 'ip', 'file': ip_rule_file}))
if result['status'] == 0:
self.print_log(public.lang("Firewall IP rules restored successfully ✓"), "restore")
else:
self.print_log(public.lang("Failed to restore firewall IP rules"), "restore")
forward_rule_file = firewall_data.get('forward_data_path')
if forward_rule_file:
if os.path.exists(forward_rule_file):
self.print_log(public.lang("Starting restoration of firewall forwarding rules"), "restore")
result = firewall_com().import_rules(
public.to_dict_obj({"rule": 'forward', 'file': forward_rule_file}))
if result['status'] == 0:
self.print_log(public.lang("Firewall forwarding rules restored successfully ✓"), "restore")
else:
self.print_log(public.lang("Failed to restore firewall forwarding rules"), "restore")
country_rule_file = firewall_data.get('country_data_path')
if country_rule_file:
if os.path.exists(country_rule_file):
self.print_log(public.lang("Starting restoration of firewall region rules"), "restore")
public.ExecShell('\cp -rpa {} /www/server/panel/data/firewall'.format(country_rule_file))
country_rule_file_last_path = country_rule_file.split("/")[-1]
result = safe_firewall_main().import_rules(
public.to_dict_obj({'rule_name': 'country_rule', 'file_name': country_rule_file_last_path}))
if result['status'] == 0:
self.print_log(public.lang("Firewall region rules restored successfully ✓"), "restore")
else:
self.print_log(public.lang("Failed to restore firewall region rules"), "restore")
# 重启防火墙
self.print_log(public.lang("Starting firewall restart"), "restore")
firewall_com().set_status(public.to_dict_obj({'status': 1}))
self.print_log(public.lang("Firewall restart completed"), "restore")
resotre_data['data_list']['firewall']['status'] = 2
self.update_restore_data_list(timestamp, resotre_data)
except Exception as e:
self.print_log(public.lang("Failed to restore firewall data: {}").format(str(e)), "restore")
resotre_data['data_list']['firewall']['status'] = 3
resotre_data['data_list']['firewall']['err_msg'] = str(e)
self.update_restore_data_list(timestamp, resotre_data)
if __name__ == '__main__':
# 获取命令行参数
if len(sys.argv) < 2:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1] # 方法名
timestamp = sys.argv[2]
firewall_manager = FirewallModule() # 实例化对象
if hasattr(firewall_manager, method_name): # 检查方法是否存在
method = getattr(firewall_manager, method_name) # 获取方法
method(timestamp) # 调用方法
else:
print(f"Error: method '{method_name}' not found")

View File

@@ -0,0 +1,138 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: miku <miku@yakpanel.com>
# -------------------------------------------------------------------
import os.path
import sys
import time
import warnings
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
if "/www/server/panel" not in sys.path:
sys.path.insert(0, "/www/server/panel")
import public
from YakPanel import app
import ftp_v2 as ftp_client
from mod.project.backup_restore.data_manager import DataManager
warnings.filterwarnings("ignore", category=SyntaxWarning)
class FtpModule(DataManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
def backup_ftp_data(self, timestamp=None):
self.print_log("==================================", "backup")
self.print_log(public.lang("Start backing up FTP account information"), "backup")
ftp_data = public.M('ftps').field('name,pid,id,password,path,ps').select()
filtered_ftp = []
for ftp in ftp_data:
try:
if ftp.get('pid', 0) == 0:
ftp['related_site'] = ''
else:
ftp['related_site'] = self._get_current_site_name_by_pid(ftp.get('pid'))
ftp['status'] = 2
ftp['msg'] = None
filtered_ftp.append(ftp)
self.print_log(public.lang("{} user ✓").format(ftp['name']), "backup")
except Exception as e:
self.print_log(public.lang("Failed to backup FTP account information: {}").format(str(e)), "backup")
ftp['status'] = 3
ftp['msg'] = str(e)
filtered_ftp.append(ftp)
continue
self.print_log(public.lang("FTP account information backup completed"), "backup")
return filtered_ftp
def _add_ftp_user(self, ftp_client: ftp_client, ftp_data: dict) -> int:
"""
:return: ftp_data restore_status
"""
log_str = public.lang("Restoring {} account").format(ftp_data['name'])
args = public.dict_obj()
args.ftp_username = ftp_data['name']
args.path = ftp_data['path']
args.ftp_password = ftp_data['password']
args.ps = ftp_data['ps']
args.pid = self._get_current_pid_by_site_name(
os.path.basename(ftp_data.get('path', ''))
)
res = ftp_client.ftp().AddUser(args)
if res['status'] is False:
self.replace_log(log_str, public.lang("FTP creation failed: {}").format(res.get('message', 'create fail')),
"restore")
return 3
else:
new_log_str = public.lang("{} account ✓").format(ftp_data['name'])
self.replace_log(log_str, new_log_str, "restore")
return 2
def restore_ftp_data(self, timestamp=None):
self.print_log("====================================================", "restore")
self.print_log(public.lang("Start restoring FTP account configuration"), "restore")
restore_data = self.get_restore_data_list(timestamp)
with app.app_context():
for ftp_data in restore_data['data_list']['ftp']:
try:
if_exist = public.M('ftps').where('name=?', (ftp_data["name"],)).find()
log_str = public.lang("Restoring {} account").format(ftp_data['name'])
if if_exist:
self.print_log(log_str, "restore")
if not self.overwrite:
self.replace_log(log_str, public.lang("{} account ✓").format(if_exist.get('name', 'ftp')),
"restore")
continue
else:
ftp_client.ftp().DeleteUser(public.to_dict_obj(
{"id": if_exist['id'], "username": if_exist['name']}
))
time.sleep(0.5)
ftp_data['restore_status'] = self._add_ftp_user(ftp_client, ftp_data)
else:
ftp_data['restore_status'] = self._add_ftp_user(ftp_client, ftp_data)
self.replace_log(
log_str,
public.lang("ftp: [{}] account restored successfully ✓").format(
ftp_data.get('name', 'ftp')),
"restore"
)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
self.print_log(public.lang("Failed to restore FTP account configuration: {}").format(str(e)),
"restore")
self.update_restore_data_list(timestamp, restore_data)
self.print_log(public.lang("FTP account configuration restoration completed"), "restore")
if __name__ == '__main__':
# 获取命令行参数
if len(sys.argv) < 3:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1] # 方法名
timestamp = sys.argv[2] # IP地址
ftp_module = FtpModule() # 实例化对象
if hasattr(ftp_module, method_name): # 检查方法是否存在
method = getattr(ftp_module, method_name) # 获取方法
method(timestamp) # 调用方法
else:
print(f"Error: Method '{method_name}' not found")

View File

@@ -0,0 +1,114 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: miku <miku@yakpanel.com>
# -------------------------------------------------------------------
import os
import sys
import warnings
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
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.config_manager import ConfigManager
warnings.filterwarnings("ignore", category=SyntaxWarning)
class MailModule(BaseUtil, ConfigManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
self.vmail_data_path = '/www/vmail'
def backup_vmail_data(self, timestamp):
if not os.path.exists(self.vmail_data_path):
return False
data_list = self.get_backup_data_list(timestamp)
if not data_list:
return None
backup_path = self.base_path + "/{timestamp}_backup/vmail".format(timestamp=timestamp)
if not os.path.exists(backup_path):
public.ExecShell('mkdir -p {}'.format(backup_path))
self.print_log("====================================================", "backup")
self.print_log(public.lang("Start backing up mail server data"), 'backup')
maill_info = {
'status': 1,
'msg': None,
'vmail_backup_name': None,
}
data_list['data_list']['vmail'] = maill_info
self.update_backup_data_list(timestamp, data_list)
vmail_backup_name = "vmail_{timestamp}.tar.gz".format(timestamp=timestamp)
public.ExecShell("cd /www && tar -czvf {} vmail".format(vmail_backup_name))
public.ExecShell("mv /www/{} {}".format(vmail_backup_name, backup_path))
maill_info['vmail_backup_name'] = backup_path + "/" + vmail_backup_name
maill_info['status'] = 2
maill_info['msg'] = None
maill_info['size'] = self.get_file_size(backup_path + "/" + vmail_backup_name)
data_list['data_list']['vmail'] = maill_info
self.update_backup_data_list(timestamp, data_list)
backup_size = self.format_size(self.get_file_size(backup_path + "/" + vmail_backup_name))
self.print_log(public.lang("Mail server data backup completed. Data size: {}").format(backup_size), 'backup')
def restore_vmail_data(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
if not restore_data:
return None
vmail_data = restore_data['data_list']['vmail']
if not vmail_data:
return None
self.print_log("==================================", "restore")
self.print_log(public.lang("Start restoring mail server data"), "restore")
restore_data['data_list']['vmail']['restore_status'] = 1
self.update_restore_data_list(timestamp, restore_data)
vmail_backup_name = vmail_data['vmail_backup_name']
if not os.path.exists(vmail_backup_name):
self.print_log(public.lang("Restoration failed, file does not exist"), "restore")
return
if os.path.exists(self.vmail_data_path):
public.ExecShell("mv {} {}.bak".format(self.vmail_data_path, self.vmail_data_path))
public.ExecShell("\cp -rpa {} /www/{}".format(vmail_backup_name, os.path.basename(self.vmail_data_path)))
public.ExecShell("cd /www && tar -xzvf {}".format(os.path.basename(self.vmail_data_path)))
restore_data['data_list']['vmail']['restore_status'] = 2
self.update_restore_data_list(timestamp, restore_data)
self.print_log(public.lang("Mail server data restoration completed"), "restore")
if __name__ == '__main__':
# 获取命令行参数
if len(sys.argv) < 3:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1] # 方法名
timestamp = sys.argv[2] # IP地址
mail_module = MailModule() # 实例化对象
if hasattr(mail_module, method_name): # 检查方法是否存在
method = getattr(mail_module, method_name) # 获取方法
method(timestamp) # 调用方法
else:
print(f"Error: Method '{method_name}' not found")

View File

@@ -0,0 +1,541 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: miku <miku@yakpanel.com>
# -------------------------------------------------------------------
import json
import os
import subprocess
import sys
import time
import warnings
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
if "/www/server/panel" not in sys.path:
sys.path.insert(0, "/www/server/panel")
import public
from YakPanel import app
from mod.project.backup_restore.base_util import BaseUtil
from mod.project.backup_restore.config_manager import ConfigManager
warnings.filterwarnings("ignore", category=SyntaxWarning)
def get_plugin_object():
import PluginLoader
from panel_plugin_v2 import panelPlugin
p = panelPlugin()
soft_list = PluginLoader.get_plugin_list(0)
# noinspection PyTypeChecker
setattr(p, "_panelPlugin__plugin_s_list", panelPlugin.set_coexist(None, soft_list["list"]))
return p
class PluginModule(BaseUtil, ConfigManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
self.plugin_path = '/www/server/panel/plugin'
self._safe_flag = False
def backup_plugin_data(self, timestamp):
self.print_log("====================================================", "backup")
self.print_log(public.lang("Start backing up plugin data"), "backup")
backup_path = self.base_path + "/{timestamp}_backup/plugin".format(timestamp=timestamp)
if not os.path.exists(backup_path):
public.ExecShell('mkdir -p {}'.format(backup_path))
plugin_info = {}
btwaf_path = os.path.join(self.plugin_path, "btwaf")
monitor_path = os.path.join(self.plugin_path, "monitor")
tamper_core_path = os.path.join(self.plugin_path, "tamper_core")
syssafe_path = os.path.join(self.plugin_path, "syssafe")
if os.path.exists(btwaf_path):
result = self.backup_btwaf_data(timestamp)
plugin_info['btwaf'] = result
if os.path.exists(monitor_path):
result = self.backup_monitor_data(timestamp)
plugin_info['monitor'] = result
if os.path.exists(tamper_core_path):
result = self.backup_tamper_core_data(timestamp)
plugin_info['tamper_core'] = result
if os.path.exists(syssafe_path):
result = self.backup_syssafe_data(timestamp)
plugin_info['syssafe'] = result
data_list = self.get_backup_data_list(timestamp)
data_list['data_list']['plugin'] = plugin_info
self.update_backup_data_list(timestamp, data_list)
def backup_btwaf_data(self, timestamp):
backup_path = self.base_path + "/{timestamp}_backup/plugin/btwaf".format(timestamp=timestamp)
if not os.path.exists(backup_path):
public.ExecShell('mkdir -p {}'.format(backup_path))
try:
btwaf_info_json = json.loads(public.ReadFile(os.path.join(self.plugin_path, "btwaf", "info.json")))
result = {
"status": 2,
"err_msg": None,
"version": btwaf_info_json['versions'],
"size": self.get_file_size(os.path.join(self.plugin_path, "btwaf"))
}
public.ExecShell(
"\cp -rpa /www/server/btwaf/config.json {backup_path}/config.json".format(backup_path=backup_path))
public.ExecShell(
"\cp -rpa /www/server/btwaf/site.json {backup_path}/site.json".format(backup_path=backup_path))
public.ExecShell("\cp -rpa /www/server/btwaf/rule {backup_path}/rule".format(backup_path=backup_path))
backup_size = self.format_size(self.get_file_size(backup_path))
self.print_log(public.lang("Nginx firewall ✓ ({})").format(backup_size), 'backup')
return result
except:
return None
def backup_monitor_data(self, timestamp):
backup_path = self.base_path + "/{timestamp}_backup/plugin/monitor".format(timestamp=timestamp)
if not os.path.exists(backup_path):
public.ExecShell('mkdir -p {}'.format(backup_path))
try:
monitor_info_json = json.loads(public.ReadFile(os.path.join(self.plugin_path, "monitor", "info.json")))
result = {
"status": 2,
"err_msg": None,
"version": monitor_info_json['versions'],
"size": self.get_file_size(os.path.join(self.plugin_path, "monitor"))
}
if os.path.exists("/www/server/panel/plugin/monitor/site_robots.json"):
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/monitor/site_robots.json {backup_path}/site_robots.json".format(
backup_path=backup_path
)
)
if os.path.exists("/www/server/panel/plugin/monitor/site_sitemap_info.json"):
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/monitor/site_sitemap_info.json {backup_path}/site_sitemap_info.json".format(
backup_path=backup_path
)
)
if os.path.exists("/www/server/panel/plugin/monitor/spider_api.config"):
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/monitor/spider_api.config {backup_path}/spider_api.config".format(
backup_path=backup_path
)
)
if os.path.exists("/www/server/panel/plugin/monitor/baidu_user.config"):
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/monitor/baidu_user.config {backup_path}/baidu_user.config".format(
backup_path=backup_path
)
)
if os.path.exists("/www/server/panel/plugin/monitor/360_user.config"):
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/monitor/360_user.config {backup_path}/360_user.config".format(
backup_path=backup_path
)
)
public.ExecShell(
"\cp -rpa /www/server/monitor/config {backup_path}/config".format(backup_path=backup_path))
backup_size = self.format_size(self.get_file_size(backup_path))
self.print_log(public.lang("Website monitoring report ✓ ({})").format(backup_size), 'backup')
return result
except:
return None
def backup_tamper_core_data(self, timestamp):
backup_path = self.base_path + "/{timestamp}_backup/plugin/tamper_core".format(timestamp=timestamp)
if not os.path.exists(backup_path):
public.ExecShell('mkdir -p {}'.format(backup_path))
try:
tamper_core_info_json = json.loads(
public.ReadFile(os.path.join(self.plugin_path, "tamper_core", "info.json")))
result = {
"status": 2,
"err_msg": None,
"version": tamper_core_info_json['versions'],
"size": self.get_file_size(os.path.join(self.plugin_path, "tamper_core"))
}
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/tamper_core/tamper_push_template.json {backup_path}/tamper_push_template.json".format(
backup_path=backup_path
)
)
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/tamper_core/rule.json {backup_path}/rule.json".format(
backup_path=backup_path
)
)
public.ExecShell(
"\cp -rpa /www/server/tamper/config_ps.json {backup_path}/config_ps.json".format(
backup_path=backup_path
)
)
public.ExecShell(
"\cp -rpa /www/server/tamper/tamper.conf {backup_path}/tamper.conf".format(
backup_path=backup_path
)
)
backup_size = self.format_size(self.get_file_size(backup_path))
self.print_log(public.lang("Enterprise tamper protection ✓ ({})").format(backup_size), 'backup')
return result
except:
return None
def backup_syssafe_data(self, timestamp):
backup_path = self.base_path + "/{timestamp}_backup/plugin/syssafe".format(timestamp=timestamp)
if not os.path.exists(backup_path):
public.ExecShell('mkdir -p {}'.format(backup_path))
try:
syssafe_info_json = json.loads(public.ReadFile(os.path.join(self.plugin_path, "syssafe", "info.json")))
result = {
"status": 2,
"err_msg": None,
"version": syssafe_info_json['versions'],
"size": self.get_file_size(os.path.join(self.plugin_path, "syssafe"))
}
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/syssafe/config.json {backup_path}/config.json".format(
backup_path=backup_path
)
)
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/syssafe/sys_process.json {backup_path}/sys_process.json".format(
backup_path=backup_path
)
)
public.ExecShell(
"\cp -rpa /www/server/panel/plugin/syssafe/config {backup_path}/".format(
backup_path=backup_path
)
)
backup_size = self.format_size(self.get_file_size(backup_path))
self.print_log(public.lang("System hardening ✓ ({})").format(backup_size), 'backup')
return result
except:
return None
def _sys_safe_pids(self) -> list:
try:
cmd = """ps aux |grep -E "(bt_syssafe|syssafe_main|syssafe_pub)"|
grep -v grep|grep -v systemctl|grep -v "init.d"|awk '{print $2}'|xargs"""
sysafe_output = subprocess.check_output(cmd, shell=True, text=True)
pids = sysafe_output.strip().split()
return pids if pids else []
except Exception:
return []
def restore_plugin_data(self, timestamp):
""""
恢复插件数据
"""
self.print_log("====================================================", "restore")
self.print_log(public.lang("Start restoring plugin data"), "restore")
self.print_log(public.lang("If the migrated machine is not bound to a yakpanel user and upgraded to Professional version, plugin restoration failures may occur"), "restore")
restore_data = self.get_restore_data_list(timestamp)
plugin_info = restore_data['data_list']['plugin']
# ============================= start =====================================
self._safe_flag = True if self._sys_safe_pids() else False
try:
public.ExecShell("/etc/init.d/bt_syssafe stop")
except:
pass
# ============================== btwaf =====================================
if 'btwaf' in plugin_info and plugin_info['btwaf']:
log_str = public.lang("Start installing Nginx firewall")
self.print_log(log_str, "restore")
restore_data['data_list']['plugin']['btwaf']['restore_status'] = 1
self.update_restore_data_list(timestamp, restore_data)
plugin_version = plugin_info['btwaf']['version']
# 检查btwaf目录下是否有正在运行的进程
self.before_install_plugin('btwaf')
install_result = self.install_plugin('btwaf', plugin_version)
if install_result['status'] is True:
new_log_str = public.lang("Nginx firewall ✓")
self.replace_log(log_str, new_log_str, "restore")
log_str = public.lang("Start restoring Nginx firewall data")
self.print_log(log_str, "restore")
self.restore_btwaf_data(timestamp)
restore_data['data_list']['plugin']['btwaf']['restore_status'] = 2
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang("Nginx firewall data ✓")
self.replace_log(log_str, new_log_str, "restore")
else:
restore_data['data_list']['plugin']['btwaf']['restore_status'] = 3
restore_data['data_list']['plugin']['btwaf']['err_msg'] = install_result['msg']
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang("Nginx firewall ✗")
self.replace_log(log_str, new_log_str, "restore")
# ====================================== monitor ==============================================
if 'monitor' in plugin_info and plugin_info['monitor']:
log_str = public.lang("Start installing website monitoring report")
self.print_log(log_str, "restore")
restore_data['data_list']['plugin']['monitor']['restore_status'] = 1
self.update_restore_data_list(timestamp, restore_data)
plugin_version = plugin_info['monitor']['version']
self.before_install_plugin('monitor')
install_result = self.install_plugin('monitor', plugin_version)
if install_result['status'] is True:
new_log_str = public.lang("Website monitoring report ✓")
self.replace_log(log_str, new_log_str, "restore")
log_str = public.lang("Start restoring website monitoring report data")
self.print_log(log_str, "restore")
self.restore_monitor_data(timestamp)
restore_data['data_list']['plugin']['monitor']['restore_status'] = 2
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang("Website monitoring report data ✓")
self.replace_log(log_str, new_log_str, "restore")
else:
restore_data['data_list']['plugin']['monitor']['restore_status'] = 3
restore_data['data_list']['plugin']['monitor']['err_msg'] = install_result['msg']
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang("Website monitoring report ✗")
self.replace_log(log_str, new_log_str, "restore")
# ========================= tamper_core ======================================
if 'tamper_core' in plugin_info and plugin_info['tamper_core']:
log_str = public.lang("Start installing enterprise tamper protection")
self.print_log(log_str, "restore")
restore_data['data_list']['plugin']['tamper_core']['restore_status'] = 1
self.update_restore_data_list(timestamp, restore_data)
plugin_version = plugin_info['tamper_core']['version']
self.before_install_plugin('tamper_core')
install_result = self.install_plugin('tamper_core', plugin_version)
if install_result['status'] is True:
public.ExecShell("/etc/init.d/bt-tamper stop")
new_log_str = public.lang("Enterprise tamper protection ✓")
self.replace_log(log_str, new_log_str, "restore")
log_str = public.lang("Start restoring enterprise tamper protection data")
self.print_log(log_str, "restore")
self.restore_tamper_core_data(timestamp)
restore_data['data_list']['plugin']['tamper_core']['restore_status'] = 2
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang("Enterprise tamper protection data ✓")
self.replace_log(log_str, new_log_str, "restore")
else:
restore_data['data_list']['plugin']['tamper_core']['restore_status'] = 3
restore_data['data_list']['plugin']['tamper_core']['err_msg'] = install_result['msg']
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang("Enterprise tamper protection ✗")
self.replace_log(log_str, new_log_str, "restore")
# ========================= syssafe ===========================================
if 'syssafe' in plugin_info and plugin_info['syssafe']:
log_str = public.lang("Start installing system hardening")
self.print_log(log_str, "restore")
restore_data['data_list']['plugin']['syssafe']['restore_status'] = 1
self.update_restore_data_list(timestamp, restore_data)
plugin_version = plugin_info['syssafe']['version']
self.before_install_plugin('syssafe')
install_result = self.install_plugin('syssafe', plugin_version)
if install_result['status'] is True:
public.ExecShell("/etc/init.d/bt_syssafe stop")
new_log_str = public.lang("System hardening ✓")
self.replace_log(log_str, new_log_str, "restore")
log_str = public.lang("Start restoring system hardening data")
self.print_log(log_str, "restore")
self.restore_syssafe_data(timestamp)
restore_data['data_list']['plugin']['syssafe']['restore_status'] = 2
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang("System hardening data ✓")
self.replace_log(log_str, new_log_str, "restore")
else:
restore_data['data_list']['plugin']['syssafe']['restore_status'] = 3
restore_data['data_list']['plugin']['syssafe']['err_msg'] = install_result['msg']
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang("System hardening ✗")
self.replace_log(log_str, new_log_str, "restore")
# ============================= end =====================================
if self._safe_flag is True:
try:
if os.path.exists("/www/server/panel/plugin/syssafe/syssafe_main.py"):
from plugin.syssafe.syssafe_main import syssafe_main as safe_main
res = safe_main().set_open(None)
public.print_log("Syssafe set_open result: {}".format(res))
except Exception as e:
public.print_log("Failed to start syssafe: {}".format(str(e)))
self.print_log(public.lang("Plugin data restoration complete"), "restore")
def restore_btwaf_data(self, timestamp):
restore_path = self.base_path + "/{timestamp}_backup/plugin/btwaf".format(timestamp=timestamp)
plugin_path = "/www/server/btwaf"
if os.path.exists(restore_path) and os.path.exists(plugin_path):
public.ExecShell(
"\cp -rpa {restore_path}/config.json /www/server/btwaf/config.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/site.json /www/server/btwaf/site.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/rule/* /www/server/btwaf/rule".format(
restore_path=restore_path
)
)
def restore_monitor_data(self, timestamp):
restore_path = self.base_path + "/{timestamp}_backup/plugin/monitor".format(timestamp=timestamp)
plugin_path = "/www/server/panel/plugin/monitor/"
if os.path.exists(restore_path) and os.path.exists(plugin_path):
public.ExecShell(
"\cp -rpa {restore_path}/site_robots.json /www/server/panel/plugin/monitor/site_robots.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/site_sitemap_info.json /www/server/panel/plugin/monitor/site_sitemap_info.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/spider_api.config /www/server/panel/plugin/monitor/spider_api.config".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/baidu_user.config /www/server/panel/plugin/monitor/baidu_user.config".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/360_user.config /www/server/panel/plugin/monitor/360_user.config".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/config/* /www/server/monitor/config".format(
restore_path=restore_path
)
)
def restore_tamper_core_data(self, timestamp):
restore_path = self.base_path + "/{timestamp}_backup/plugin/tamper_core".format(timestamp=timestamp)
plugin_path = "/www/server/panel/plugin/tamper_core/"
if os.path.exists(restore_path) and os.path.exists(plugin_path):
public.ExecShell(
"\cp -rpa {restore_path}/tamper_push_template.json /www/server/panel/plugin/tamper_core/tamper_push_template.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/rule.json /www/server/panel/plugin/tamper_core/rule.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/config_ps.json /www/server/tamper/config_ps.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/tamper.conf /www/server/tamper/tamper.conf".format(
restore_path=restore_path
)
)
public.ExecShell("/etc/init.d/bt-tamper stop")
def restore_syssafe_data(self, timestamp):
restore_path = self.base_path + "/{timestamp}_backup/plugin/syssafe".format(timestamp=timestamp)
plugin_path = "/www/server/panel/plugin/syssafe/"
if os.path.exists(restore_path) and os.path.exists(plugin_path):
public.ExecShell(
"\cp -rpa {restore_path}/config.json /www/server/panel/plugin/syssafe/config.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/sys_process.json /www/server/panel/plugin/syssafe/sys_process.json".format(
restore_path=restore_path
)
)
public.ExecShell(
"\cp -rpa {restore_path}/config/* /www/server/panel/plugin/syssafe/config".format(
restore_path=restore_path
)
)
public.ExecShell("/etc/init.d/bt_syssafe stop")
def before_install_plugin(self, plugin_name: str):
try:
if plugin_name == "btwaf":
cmd = "ps aux | grep 'BT-WAF' | grep -v grep | awk '{print $2}'"
cmd_output = subprocess.check_output(cmd, shell=True, text=True)
pids1 = cmd_output.strip()
if pids1:
subprocess.run(["kill", "-9", str(pids1)], check=True)
xss_path = "/www/server/panel/plugin/btwaf/nginx_btwaf_xss"
lsof_output = subprocess.check_output(f"lsof -t {xss_path}", shell=True, text=True)
pids2 = lsof_output.strip().split()
for p2 in pids2:
subprocess.run(["kill", "-9", str(p2)], check=True)
time.sleep(1)
elif plugin_name == "syssafe":
public.ExecShell("/etc/init.d/bt_syssafe stop")
time.sleep(1)
elif plugin_name == "monitor":
pass
elif plugin_name == "tamper_core":
pass
time.sleep(1)
except:
pass
def install_plugin(self, sName, plugin_version):
with app.app_context():
try:
plugin = get_plugin_object()
version_parts = plugin_version.split(".", 1)
sVersion = version_parts[0]
sMin_version = version_parts[1] if len(version_parts) > 1 else ""
get = public.dict_obj()
get.sName = sName
get.version = sVersion
get.min_version = sMin_version
info = plugin.install_plugin(get)["message"]
args = public.dict_obj()
args.tmp_path = info.get("tmp_path")
args.plugin_name = sName
args.install_opt = info.get("install_opt")
info = plugin.input_package(args)
return info
except Exception:
import traceback
print(traceback.format_exc())
return {
'status': False,
'msg': public.lang('Installation failed')
}
if __name__ == '__main__':
# 获取命令行参数
if len(sys.argv) < 2:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1] # 方法名
timestamp = sys.argv[2]
plugin_manager = PluginModule() # 实例化对象
if hasattr(plugin_manager, method_name): # 检查方法是否存在
method = getattr(plugin_manager, method_name) # 获取方法
method(timestamp) # 调用方法
else:
print(f"Error: Method '{method_name}' not found")

View File

@@ -0,0 +1,911 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: miku <miku@yakpanel.com>
# -------------------------------------------------------------------
import json
import os
import shutil
import sys
import time
import warnings
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
if "/www/server/panel" not in sys.path:
sys.path.insert(0, "/www/server/panel")
import public
from public.hook_import import hook_import
hook_import()
from wp_toolkit import wpbackup
import db
from YakPanel import app
import panel_site_v2 as panelSite
from mod.project.backup_restore.data_manager import DataManager
warnings.filterwarnings("ignore", category=SyntaxWarning)
class SiteModule(DataManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
self.site_dir_auth_path = "/www/server/panel/data/site_dir_auth.json"
self.redirect_conf_path = "/www/server/panel/data/redirect.conf"
self.proxy_conf_path = "/www/server/panel/data/proxyfile.json"
@staticmethod
def copy_directory(src: str, dst: str, overwrite: bool = False) -> None:
"""
site 复制文件夹
src: 源路径
dst: 目标路径
overwrite: 是否覆盖
"""
if not src or not dst:
return
if src == dst:
return
if isinstance(overwrite, int):
overwrite = False if overwrite == 0 else True
def _copy2(src_file: str, dst_file: str):
if overwrite or not os.path.exists(dst_file):
try:
shutil.copy2(src_file, dst_file)
except:
try:
public.ExecShell("chattr -i {}".format(dst_file))
shutil.copy2(src_file, dst_file)
except:
pass
# 如果源路径不存在,直接返回
if not os.path.exists(src):
return
# 确保目标目录存在
if not os.path.exists(dst):
os.makedirs(dst, 0o755, exist_ok=True)
# 复制源目录下的所有内容到目标目录
for item in os.listdir(src):
src_item = os.path.join(src, item)
dst_item = os.path.join(dst, item)
if os.path.isdir(src_item):
# 递归调用自身来复制子目录内容
SiteModule.copy_directory(src_item, dst_item, overwrite)
else:
# 复制文件
_copy2(src_item, dst_item)
@staticmethod
def _db_cp(source_db: str, target_db: str, tables: list = None) -> None:
"""
指定表复制到新db中
source_db: 源db路径
target_db: 目标db路径
tables: 要复制的表列表, None时复制所有
"""
if not source_db:
return
source_db = f"'{source_db}'"
target_db = f"'{target_db}'"
if not tables:
public.ExecShell(f"sqlite3 {source_db} .dump | sqlite3 {target_db}")
return
for table in tables:
public.ExecShell(f"sqlite3 {target_db} 'DROP TABLE IF EXISTS {table};'")
tables_for_dump = " ".join(tables)
tables_cmd = f"sqlite3 {source_db} '.dump {tables_for_dump}'"
tables_for_sql_in = ", ".join([f"'{t}'" for t in tables])
triggers_cmd = f"""sqlite3 {source_db} \"
SELECT sql || ';' FROM sqlite_master WHERE type='trigger' AND tbl_name IN ({tables_for_sql_in}) AND sql IS NOT NULL;\"
"""
res_cmd = f"({tables_cmd}; {triggers_cmd}) | sqlite3 {target_db}"
public.ExecShell(res_cmd)
public.ExecShell(f"sqlite3 {target_db} '.dump' | sqlite3 {target_db}")
@staticmethod
def chmod_dir_file(path: str, dir_mode: int = 0o755, file_mode: int = 0o644):
if not path:
return
for root, dirs, files in os.walk(path):
for d in dirs:
try:
os.chmod(os.path.join(root, d), dir_mode)
except:
continue
for f in files:
try:
os.chmod(os.path.join(root, f), file_mode)
except:
continue
if os.path.isdir(path):
try:
os.chmod(path, dir_mode)
except:
pass
elif os.path.isfile(path):
try:
os.chmod(path, file_mode)
except:
pass
def get_site_backup_conf(self, timestamp=None):
# todo node, 待优化
site_data = public.M('sites').where("project_type != ?", "Node").field('name,path,project_type,id,ps').select()
domian_data = public.M('domain').field('name,id,pid,id,port').select()
wp_onekey = public.M('wordpress_onekey').field('s_id,prefix,user,pass').select()
filtered_sites = [site for site in site_data]
filtered_domain = [name for name in domian_data]
pid_map = {}
for domain in filtered_domain:
pid = domain["pid"]
if pid not in pid_map:
pid_map[pid] = []
pid_map[pid].append(
{
"name": domain["name"],
"port": domain["port"],
}
)
for site in filtered_sites:
# domain
site_id = site["id"]
if site_id in pid_map:
site["domains"] = pid_map[site_id]
# wp prefix
hit = False
for p in wp_onekey:
try: # wp may be not exist
if p["s_id"] == site["id"] and p.get('prefix'):
site["wp_onekey"] = {
"prefix": p['prefix'],
"user": p.get('user', ''),
"pass": p.get('pass', ''),
}
hit = True
break
except:
pass
if not hit:
site["wp_onekey"] = {}
site["data_type"] = "backup"
site["status"] = 0
site["msg"] = None
return filtered_sites
def backup_site_data(self, timestamp):
data_list = self.get_backup_data_list(timestamp)
if not data_list:
return None
data_backup_path = data_list['backup_path']
site_backup_path = data_backup_path + '/site/'
if not os.path.exists(site_backup_path):
public.ExecShell('mkdir -p {}'.format(site_backup_path))
self.print_log("====================================================", 'backup')
self.print_log(public.lang("Start backing up site data"), 'backup')
self.backup_site_config(site_backup_path)
site_sql = db.Sql()
site_sql.table('sites')
domain_sql = db.Sql()
domain_sql.table('domain')
for site in data_list['data_list']['site']:
# 备份db数据库数据
site_id = site['id']
site_db_record = site_sql.where('id=?', (site_id,)).find()
site['site_db_record'] = site_db_record
# 备份网站数据
site['path'] = str(site['path']).rstrip('/')
last_path = os.path.basename(site['path'])
site["last_path"] = last_path
site_path = site_backup_path + last_path
if site["project_type"] == "PHP":
try:
site["php_ver"] = panelSite.panelSite().GetSitePHPVersion(
public.to_dict_obj({'siteName': site['name']})
)['phpversion']
except:
site["php_ver"] = None
site['status'] = 1
log_str = public.lang("Backing up {} project: {}").format(site['project_type'], site['name'])
self.print_log(log_str, "backup")
self.update_backup_data_list(timestamp, data_list)
# 备份网站项目
public.ExecShell("cp -rpa {} {}".format(site['path'], site_path))
site_zip = site_backup_path + last_path + ".zip"
public.ExecShell("cd {} && zip -r {}.zip {}".format(site_backup_path, last_path, last_path))
if os.path.exists(site_zip):
site_zip_size = public.ExecShell("du -sb {}".format(site_zip))[0].split("\t")[0]
site['data_file_name'] = site_zip
site['size'] = site_zip_size
site['zip_sha256'] = self.get_file_sha256(site_zip)
# 创建配置文件备份目录
webserver_conf_path = ["apache", "cert", "config", "nginx", "open_basedir",
"openlitespeed", "other_php", "rewrite", "ssl",
"ssl_saved", "template", "tomcat"]
conf_backup_path = site_backup_path + site['name'] + "_conf/"
public.ExecShell(f"mkdir -p '{conf_backup_path}'")
# 创建子目录
for wpath in webserver_conf_path:
web_conf_backup_path = conf_backup_path + wpath
public.ExecShell(f"mkdir -p '{web_conf_backup_path}'")
# 备份网站配置文件
self.backup_web_conf(site['name'], conf_backup_path)
# 打包网站配置文件
site_name = site['name']
site_conf_zip = site_backup_path + site_name + "_conf.zip"
public.ExecShell("cd {} && zip -r {}_conf.zip {}_conf".format(site_backup_path, site_name, site_name))
if os.path.exists(site_conf_zip):
site['conf_file_name'] = site_conf_zip
site['zip_sha256'] = self.get_file_sha256(site_conf_zip)
site['conf_sha256'] = self.get_file_sha256(site_conf_zip)
site['status'] = 2
format_backup_file_size = self.format_size(int(site['size']))
new_log_str = public.lang("{} project {} ✓ ({})").format(
site['project_type'], site['name'], format_backup_file_size
)
self.replace_log(log_str, new_log_str, 'backup')
self.update_backup_data_list(timestamp, data_list)
self.print_log(public.lang("Site data backup completed"), 'backup')
def backup_site_config(self, site_backup_path):
public.ExecShell(
"\cp -rpa /www/server/panel/data/default.db {site_backup_path}default.db".format(
site_backup_path=site_backup_path
)
)
# 备份加密访问配置文件
if os.path.exists("/www/server/panel/data/site_dir_auth.json"):
public.ExecShell(
"\cp -rpa /www/server/panel/data/site_dir_auth.json {site_backup_path}site_dir_auth.json".format(
site_backup_path=site_backup_path
)
)
# 备份加密密码
if os.path.exists("/www/server/pass/"):
public.ExecShell(
"\cp -rpa /www/server/pass/ {site_backup_path}pass/".format(
site_backup_path=site_backup_path
)
)
# 备份反代配置
if os.path.exists("/www/server/proxy_project/sites"):
public.ExecShell("mkdir -p {site_backup_path}proxy_project/".format(site_backup_path=site_backup_path))
public.ExecShell(
"\cp -rpa /www/server/proxy_project/sites {site_backup_path}proxy_project/sites/".format(
site_backup_path=site_backup_path
)
)
# 备份重定向配置
if os.path.exists("/www/server/panel/data/redirect.conf"):
public.ExecShell(
"\cp -rpa /www/server/panel/data/redirect.conf {site_backup_path}redirect.conf".format(
site_backup_path=site_backup_path
)
)
if os.path.exists("/www/server/panel/data/proxyfile.json"):
public.ExecShell(
"\cp -rpa /www/server/panel/data/proxyfile.json {site_backup_path}proxyfile.json".format(
site_backup_path=site_backup_path
)
)
# 备份wp加速配置文件
if os.path.exists("/www/server/nginx/conf/"):
nginx_conf_list = os.listdir("/www/server/nginx/conf/")
for nginx_conf_name in nginx_conf_list:
if "wpfastcgi" in nginx_conf_name:
public.ExecShell(
"\cp -rpa /www/server/nginx/conf/{nginx_conf_name} {site_backup_path}{nginx_conf_name}".format(
nginx_conf_name=nginx_conf_name, site_backup_path=site_backup_path
)
)
# 备份well-known文件
if os.path.exists("/www/server/panel/vhost/nginx/well-known"):
public.ExecShell(
"\cp -rpa /www/server/panel/vhost/nginx/well-known {site_backup_path}/well-known".format(
site_backup_path=site_backup_path
)
)
public.ExecShell("mkdir -p {site_backup_path}/monitor_conf/".format(site_backup_path=site_backup_path))
public.ExecShell(
"\cp -rpa /www/server/panel/vhost/nginx/0.monitor*.conf {site_backup_path}/monitor_conf/".format(
site_backup_path=site_backup_path
)
)
def restore_site_config(self, backup_path):
default_db_file = backup_path + "default.db"
dir_auth_file = backup_path + "site_dir_auth.json"
pass_path = backup_path + "pass"
proxy_project_path = backup_path + "proxy_project"
redirect_file = backup_path + "redirect.conf"
proxyfile_file = backup_path + "proxyfile.json"
if os.path.exists(default_db_file) and self.overwrite:
panel_current = public.S("users").find()
public.ExecShell(f"\cp -rpa {default_db_file} /www/server/panel/data/default.db")
os.chmod("/www/server/panel/data/default.db", 0o600)
if "id" in panel_current:
del panel_current["id"]
public.S("users").where("id=?", (1,)).update(panel_current)
if os.path.exists(pass_path):
self.copy_directory(
src=pass_path,
dst="/www/server/pass",
overwrite=self.overwrite,
)
self.chmod_dir_file("/www/server/pass", file_mode=0o644)
if os.path.exists(proxy_project_path):
target = "/www/server/proxy_project"
self.copy_directory(
src=proxy_project_path,
dst=target,
overwrite=self.overwrite,
)
self.chmod_dir_file(target, file_mode=0o644)
if os.path.exists(dir_auth_file):
target = "/www/server/panel/data/site_dir_auth.json"
if not os.path.exists(target) or self.overwrite:
public.ExecShell(f"\cp -rpa {dir_auth_file} /www/server/panel/data/site_dir_auth.json")
self.chmod_dir_file(target, file_mode=0o600)
if os.path.exists(redirect_file):
target = "/www/server/panel/data/redirect.conf"
if not os.path.exists(target) or self.overwrite:
public.ExecShell(f"\cp -rpa {redirect_file} /www/server/panel/data/redirect.conf")
self.chmod_dir_file(target, file_mode=0o600)
if os.path.exists(proxyfile_file):
target = "/www/server/panel/data/proxyfile.json"
if not os.path.exists(target) or self.overwrite:
public.ExecShell(f"\cp -rpa {proxyfile_file} /www/server/panel/data/proxyfile.json")
self.chmod_dir_file(target, file_mode=0o600)
public.ExecShell(f"\cp -rpa {backup_path}/*wpfastcgi.conf /www/server/nginx/conf/")
self.chmod_dir_file("/www/server/nginx/conf", file_mode=0o644)
if os.path.exists(backup_path + "well-known"):
target = "/www/server/panel/vhost/nginx/well-known"
if not os.path.exists(target):
public.ExecShell(f"mkdir -p {target}")
public.ExecShell(f"\cp -rpa {backup_path}well-known/* /www/server/panel/vhost/nginx/well-known/")
self.chmod_dir_file(target, dir_mode=0o600, file_mode=0o600)
public.ExecShell(f"\cp -rpa {backup_path}monitor_conf/* /www/server/panel/vhost/nginx/")
self.chmod_dir_file("/www/server/panel/vhost/nginx", dir_mode=0o600, file_mode=0o600)
def restore_site_python_env(self, timestamp):
self.print_log("================================================", "restore")
self.print_log(public.lang("Starting to restore site Python dependencies..."), 'restore')
restore_data = self.get_restore_data_list(timestamp)
site_data = restore_data['data_list']['site']
for site in site_data:
if site['project_type'] == 'Python':
python_site_config = site['site_db_record']['project_config']
requirement_path = json.loads(python_site_config)['requirement_path']
vpath = json.loads(python_site_config)['vpath']
if requirement_path:
pip3_path = vpath + "/bin/pip3"
pip2_path = vpath + "/bin/pip2"
pip_install_cmd = None
if os.path.exists(pip3_path):
pip_install_cmd = "{} install -r {}".format(pip3_path, requirement_path)
elif os.path.exists(pip2_path):
pip_install_cmd = "{} install -r {}".format(pip2_path, requirement_path)
if pip_install_cmd:
public.ExecShell(pip_install_cmd)
self.print_log(public.lang("Site Python dependencies restoration completed"), 'restore')
def backup_web_conf(self, site_name: str, conf_backup_path: str) -> None:
"""备份网站配置文件
Args:
site_name: 网站名称
conf_backup_path: 配置文件备份路径
"""
# 定义需要备份的配置文件和路径映射
conf_paths = {
'cert': "/www/server/panel/vhost/cert/{site_name}".format(site_name=site_name),
'rewrite': "/www/server/panel/vhost/rewrite/{site_name}.conf".format(site_name=site_name),
'nginx': {
'main': "/www/server/panel/vhost/nginx/{site_name}.conf".format(site_name=site_name),
'redirect': "/www/server/panel/vhost/nginx/redirect/{site_name}".format(site_name=site_name),
'proxy': "/www/server/panel/vhost/nginx/proxy/{site_name}".format(site_name=site_name),
'dir_auth': "/www/server/panel/vhost/nginx/dir_auth/{site_name}".format(site_name=site_name)
},
'apache': {
'main': "/www/server/panel/vhost/apache/{site_name}.conf".format(site_name=site_name),
'redirect': "/www/server/panel/vhost/apache/redirect/{site_name}".format(site_name=site_name),
'proxy': "/www/server/panel/vhost/apache/proxy/{site_name}".format(site_name=site_name),
'dir_auth': "/www/server/panel/vhost/apache/dir_auth/{site_name}".format(site_name=site_name)
},
'openlitespeed': {
'main': '/www/server/panel/vhost/openlitespeed',
'detail': '/www/server/panel/vhost/openlitespeed/detail',
'listen': '/www/server/panel/vhost/openlitespeed/listen',
'ssl': '/www/server/panel/vhost/openlitespeed/detail/ssl',
},
}
# 备份证书
if os.path.exists(conf_paths['cert']):
public.ExecShell(f"mkdir -p {conf_backup_path}cert/")
public.ExecShell(f"\cp -rpa {conf_paths['cert']} {conf_backup_path}cert/")
# 备份伪静态
if os.path.exists(conf_paths['rewrite']):
public.ExecShell(f"\cp -rpa {conf_paths['rewrite']} {conf_backup_path}rewrite")
rewrite_file_list = os.listdir("/www/server/panel/vhost/rewrite/")
for rewrite_file in rewrite_file_list:
if rewrite_file.endswith(".conf"):
if site_name in rewrite_file:
public.ExecShell(
f"\cp -rpa /www/server/panel/vhost/rewrite/{rewrite_file} {conf_backup_path}rewrite"
)
# 备份nginx配置
nginx_paths = conf_paths['nginx']
if os.path.exists(nginx_paths['main']):
public.ExecShell(f"\cp -rpa {nginx_paths['main']} {conf_backup_path}nginx/")
if not os.path.exists(nginx_paths['main']):
web_conf_list = os.listdir("/www/server/panel/vhost/nginx/")
for web_conf_name in web_conf_list:
if web_conf_name.endswith(".conf"):
if site_name in web_conf_name:
public.ExecShell(
f"\cp -rpa /www/server/panel/vhost/nginx/{web_conf_name} {conf_backup_path}nginx/"
)
if os.path.exists(nginx_paths['redirect']):
public.ExecShell(f"mkdir -p {conf_backup_path}nginx/redirect/{site_name}/")
public.ExecShell(f"\cp -rpa {nginx_paths['redirect']}/* {conf_backup_path}nginx/redirect/{site_name}/")
if os.path.exists(nginx_paths['proxy']):
public.ExecShell(f"mkdir -p {conf_backup_path}nginx/proxy/{site_name}/")
public.ExecShell(f"\cp -rpa {nginx_paths['proxy']}/* {conf_backup_path}nginx/proxy/{site_name}/")
if os.path.exists(nginx_paths['dir_auth']):
public.ExecShell(f"mkdir -p {conf_backup_path}nginx/dir_auth/{site_name}/")
public.ExecShell(f"\cp -rpa {nginx_paths['dir_auth']}/* {conf_backup_path}nginx/dir_auth/{site_name}/")
# 备份apache配置
apache_paths = conf_paths['apache']
if os.path.exists(apache_paths['main']):
public.ExecShell(f"\cp -rpa {apache_paths['main']} {conf_backup_path}apache/")
if not os.path.exists(apache_paths['main']):
web_conf_list = os.listdir("/www/server/panel/vhost/apache/")
for web_conf_name in web_conf_list:
if web_conf_name.endswith(".conf"):
if site_name in web_conf_name:
public.ExecShell(
f"\cp -rpa /www/server/panel/vhost/apache/{web_conf_name} {conf_backup_path}apache/"
)
if os.path.exists(apache_paths['redirect']):
public.ExecShell(f"mkdir -p {conf_backup_path}apache/redirect/{site_name}/")
public.ExecShell(f"\cp -rpa {apache_paths['redirect']}/* {conf_backup_path}apache/redirect/{site_name}/")
if os.path.exists(apache_paths['proxy']):
public.ExecShell(f"mkdir -p {conf_backup_path}apache/proxy/{site_name}/")
public.ExecShell(f"\cp -rpa {apache_paths['proxy']}/* {conf_backup_path}apache/proxy/{site_name}/")
if os.path.exists(apache_paths['dir_auth']):
public.ExecShell(f"mkdir -p {conf_backup_path}apache/dir_auth/{site_name}/")
public.ExecShell(f"\cp -rpa {apache_paths['dir_auth']}/* {conf_backup_path}apache/dir_auth/{site_name}/")
# 备份openlitespeed配置
ols_paths = conf_paths['openlitespeed']
if os.path.exists(ols_paths['main']):
for web_conf_name in os.listdir(ols_paths['main']):
if site_name in web_conf_name:
public.ExecShell(
f"\cp -rpa /www/server/panel/vhost/openlitespeed/{web_conf_name} {conf_backup_path}openlitespeed/"
)
if os.path.exists(conf_paths['openlitespeed']['detail']):
public.ExecShell(f"mkdir -p {conf_backup_path}openlitespeed/detail")
for detail in os.listdir(conf_paths['openlitespeed']['detail']):
if site_name in detail:
public.ExecShell(
f"\cp -rpa {ols_paths['main']}/detail/{detail} {conf_backup_path}openlitespeed/detail/"
)
if os.path.exists(conf_paths['openlitespeed']['listen']):
public.ExecShell(
f"cp -rpa {conf_paths['openlitespeed']['listen']} {conf_backup_path}openlitespeed/listen"
)
if os.path.exists(conf_paths['openlitespeed']['ssl']):
public.ExecShell(f"mkdir -p {conf_backup_path}openlitespeed/detail/ssl")
for ssl in os.listdir(conf_paths['openlitespeed']['ssl']):
if site_name in ssl:
public.ExecShell(
f"cp -rpa {conf_paths['openlitespeed']['ssl']}/{ssl} {conf_backup_path}openlitespeed/detail/ssl/{ssl}"
)
def restore_web_conf(self, site_name: str, conf_backup_path: str) -> None:
"""还原网站配置文件
Args:
site_name: 网站名称
conf_backup_path: 配置文件备份路径
"""
# 定义需要还原的配置文件和路径映射
conf_paths = {
'cert': "/www/server/panel/vhost/cert/{site_name}".format(site_name=site_name),
'rewrite': "/www/server/panel/vhost/rewrite/{site_name}.conf".format(site_name=site_name),
'nginx': {
'main': "/www/server/panel/vhost/nginx/{site_name}.conf".format(site_name=site_name),
'redirect': "/www/server/panel/vhost/nginx/redirect/{site_name}".format(site_name=site_name),
'proxy': "/www/server/panel/vhost/nginx/proxy/{site_name}".format(site_name=site_name)
},
'apache': {
'main': "/www/server/panel/vhost/apache/{site_name}.conf".format(site_name=site_name),
'redirect': "/www/server/panel/vhost/apache/redirect/{site_name}".format(site_name=site_name),
'proxy': "/www/server/panel/vhost/apache/proxy/{site_name}".format(site_name=site_name)
},
'openlitespeed': {
'main': '/www/server/panel/vhost/openlitespeed',
'detail': '/www/server/panel/vhost/openlitespeed/detail',
'listen': '/www/server/panel/vhost/openlitespeed/listen',
'ssl': '/www/server/panel/vhost/openlitespeed/detail/ssl',
},
}
# 还原证书
if os.path.exists(f"{conf_backup_path}cert"):
public.ExecShell(f"\cp -rpa {conf_backup_path}cert {conf_paths['cert']}")
# 还原伪静态
if os.path.exists(f"{conf_backup_path}rewrite"):
public.ExecShell(f"\cp -rpa {conf_backup_path}rewrite {conf_paths['rewrite']}")
# 还原nginx配置
if os.path.exists(f"{conf_backup_path}nginx"):
public.ExecShell(f"\cp -rpa {conf_backup_path}nginx {conf_paths['nginx']['main']}")
if os.path.exists(f"{conf_backup_path}nginx/redirect"):
public.ExecShell(f"\cp -rpa {conf_backup_path}nginx/redirect {conf_paths['nginx']['redirect']}")
if os.path.exists(f"{conf_backup_path}nginx/proxy"):
public.ExecShell(f"\cp -rpa {conf_backup_path}nginx/proxy {conf_paths['nginx']['proxy']}")
# 还原apache配置
if os.path.exists(f"{conf_backup_path}apache"):
public.ExecShell(f"\cp -rpa {conf_backup_path}apache {conf_paths['apache']['main']}")
if os.path.exists(f"{conf_backup_path}apache/redirect"):
public.ExecShell(f"\cp -rpa {conf_backup_path}apache/redirect {conf_paths['apache']['redirect']}")
if os.path.exists(f"{conf_backup_path}apache/proxy"):
public.ExecShell(f"\cp -rpa {conf_backup_path}apache/proxy {conf_paths['apache']['proxy']}")
# 还原openlitespeed配置
if os.path.exists(f"{conf_backup_path}openlitespeed"):
for web_cf_name in os.listdir(f"{conf_backup_path}openlitespeed"):
if site_name in web_cf_name:
public.ExecShell(
f"\cp -rpa {conf_backup_path}openlitespeed/{web_cf_name} {conf_paths['openlitespeed']['main']}/{web_cf_name}"
)
detail_path = f"{conf_backup_path}openlitespeed/detail"
if os.path.exists(detail_path):
if not os.path.exists(conf_paths['openlitespeed']['detail']):
public.ExecShell(f"mkdir -p {conf_paths['openlitespeed']['detail']}")
for detail in os.listdir(detail_path):
if site_name in detail:
public.ExecShell(
f"\cp -rpa {detail_path}/{detail} {conf_paths['openlitespeed']['detail']}/{detail}"
)
listen_path = f"{conf_backup_path}openlitespeed/listen"
if os.path.exists(listen_path):
public.ExecShell(
f"\cp -rpa {listen_path} {conf_paths['openlitespeed']['listen']}/listen"
)
ssl_path = f"{conf_backup_path}openlitespeed/detail/ssl"
if os.path.exists(ssl_path):
if not os.path.exists(conf_paths['openlitespeed']['ssl']):
public.ExecShell(f"mkdir -p {conf_paths['openlitespeed']['ssl']}")
for ssl in os.listdir(ssl_path):
if site_name in ssl:
public.ExecShell(
f"\cp -rpa {ssl_path}/{ssl} {conf_paths['openlitespeed']['ssl']}/{ssl}"
)
def _restore_site_db_data(self, site_db_record: dict) -> int:
sql = db.Sql()
sql.table('sites')
if 'id' in site_db_record:
del site_db_record['id']
# SQL关键字字段
if 'index' in site_db_record:
del site_db_record['index']
if_exist = sql.where(
'name=? AND project_type=?',
(site_db_record['name'], site_db_record['project_type'])
).find()
if if_exist:
return if_exist['id']
# insert db record
try:
new_id = sql.insert(site_db_record)
return new_id
except Exception as e:
raise public.lang("Site database insert failed: {}").format(str(e))
def _restore_site_domian_db_data(self, pid: int, domains: list) -> None:
domain_sql = db.Sql()
domain_sql.table('domain')
for domain in domains:
try:
if not domain_sql.where('name=?', (domain['name'],)).count():
domain_sql.add(
'pid, name, port, addtime',
(pid, domain['name'], int(domain['port']), public.getDate())
)
except Exception as e:
public.print_log("Domain database insert failed: {}".format(str(e)))
continue
def _backup_site(self, site: dict, backupPath: str) -> None:
try:
if site.get("project_type", "").lower() == "php":
find = public.M('sites').where("id=?", (site['id'],)).field('name,path,id').find()
fileName = find['name'] + '_' + time.strftime(
'%Y%m%d_%H%M%S', time.localtime()
) + '.zip'
zipName = backupPath + '/' + fileName
if not (os.path.exists(backupPath)):
os.makedirs(backupPath)
tmps = '/tmp/panelExec.log'
execStr = f"cd '{find['path']}' && zip '{zipName}' . -x .user.ini > {tmps} 2>&1"
public.ExecShell(execStr)
public.M('backup').add(
'type,name,pid,filename,size,addtime',
(0, fileName, find['id'], zipName, 0, public.getDate())
)
elif "wp" in site.get("project_type", "").lower():
bak_obj = wpbackup(int(site['id']))
bak_obj.backup_full()
except:
pass
def restore_site_data(self, timestamp: str) -> None:
"""还原站点数据
Args:
timestamp: 备份时间戳
"""
restore_data = self.get_restore_data_list(timestamp)
site_backup_path = self.base_path + "/{timestamp}_backup/site/".format(timestamp=timestamp)
# 还原site环境配置, 全局配置
self.restore_site_config(site_backup_path)
if not os.path.exists(site_backup_path):
self.print_log(public.lang("Site backup directory does not exist: {}").format(site_backup_path), 'restore')
return
self.print_log("====================================================", "restore")
self.print_log(public.lang("Start restoring site data"), 'restore')
backupPath = public.M('config').where('id=?', (1,)).getField('backup_path')
backupPath = backupPath + '/site/' if backupPath else "/www/backup/site/"
with app.app_context():
for site in restore_data['data_list']['site']:
log_str = public.lang("Restoring {} project: {}").format(site.get("project_type"), site.get("name"))
try:
site_name = site['name']
site['restore_status'] = 1
self.update_restore_data_list(timestamp, restore_data)
self.print_log(log_str, 'restore')
if self.overwrite:
# site backup if overwrite
self._backup_site(site, backupPath)
# data
if not self.overwrite and 'site_db_record' in site:
site_id = self._restore_site_db_data(site['site_db_record'])
if site_id and 'domains' in site:
# 还原域名记录
self._restore_site_domian_db_data(site_id, site['domains'])
# site file
site_path = str(site['path']).rstrip('/')
last_path: str = os.path.basename(site_path) if site['last_path'] == '' else site['last_path'] # site name
# site abs path
site_zip = site_backup_path + last_path + ".zip"
if os.path.exists(site_zip):
public.ExecShell(f"cd {site_backup_path} && unzip -o {last_path}.zip")
site_data_path = site_backup_path + last_path # site unzip file
if os.path.exists(site_data_path):
site_parent_path = os.path.dirname(site_path) # /www/wwwroot
if not os.path.exists(site_parent_path):
public.ExecShell("mkdir -p {}".format(site_parent_path))
public.ExecShell("chown -R www:www {}".format(site_parent_path))
public.ExecShell("chmod -R 755 {}".format(site_parent_path))
src_site = os.path.join(site_backup_path, last_path)
dst_site = os.path.join(site_parent_path, last_path)
public.print_log('copying site directory from {} to {}'.format(src_site, dst_site))
self.copy_directory(
src=src_site,
dst=dst_site,
overwrite=self.overwrite,
)
try:
shutil.rmtree(src_site)
except Exception as e:
public.print_log(public.lang("Failed to delete source site directory: {}").format(str(e)))
# makesure
public.ExecShell(f"chown -R www:www {dst_site}")
user_ini = dst_site + "/.user.ini"
if not os.path.exists(user_ini) or self.overwrite:
public.writeFile(user_ini, f"open_basedir={site_parent_path}/:/tmp/")
public.ExecShell("chmod 644 " + user_ini)
public.ExecShell("chown root:root " + user_ini)
public.ExecShell("chattr +i " + user_ini)
# site config
site_conf_zip = site_backup_path + site_name + "_conf.zip"
if os.path.exists(site_conf_zip):
public.ExecShell(
"cd {site_backup_path} && unzip -o {site_name}_conf.zip".format(
site_backup_path=site_backup_path, site_name=site_name
)
)
public.ExecShell(
"cd {site_backup_path} && \cp -rpa {site_name}_conf/* /www/server/panel/vhost".format(
site_backup_path=site_backup_path, site_name=site_name
)
)
new_log_str = public.lang("{} project: {}").format(site['project_type'], site['name'])
self.replace_log(log_str, new_log_str, 'restore')
site['restore_status'] = 2
self.update_restore_data_list(timestamp, restore_data)
except Exception as e:
site['restore_status'] = 3
self.update_restore_data_list(timestamp, restore_data)
new_log_str = public.lang(f"{site['project_type']} project: {site['name']} Reason: {str(e)}")
self.replace_log(log_str, new_log_str, 'restore')
continue
self.print_log(public.lang("Site data restoration completed"), 'restore')
# 还原site 所有Python环境
# self.restore_site_python_env(timestamp)
def backup_site_dir_auth(self, site_name: str):
if os.path.exists(self.site_dir_auth_path):
site_dir_auth_data = json.loads(public.ReadFile(self.site_dir_auth_path))
if site_name in site_dir_auth_data:
result = {site_name: site_dir_auth_data[site_name]}
return result
return False
def restore_site_dir_auth(self, site_name: str, backup_data_path: str):
if os.path.exists(backup_data_path):
dir_auth_backup_data = json.loads(public.ReadFile(backup_data_path))
if os.path.exists(self.site_dir_auth_path):
site_dir_auth_data = json.loads(public.ReadFile(self.site_dir_auth_path))
site_dir_auth_data[site_name] = dir_auth_backup_data[site_name]
public.WriteFile(self.site_dir_auth_path, json.dumps(site_dir_auth_data))
def backup_dir_pass(self, site_name: str, backup_data_path: str):
if os.path.exists(self.site_dir_auth_path):
site_dir_auth_data = json.loads(public.ReadFile(self.site_dir_auth_path))
if site_name in site_dir_auth_data:
result = {site_name: site_dir_auth_data[site_name]}
return result
return {}
def backup_redirect_conf(self, site_name: str):
if os.path.exists(self.redirect_conf_path):
redirect_conf_data = json.loads(public.ReadFile(self.redirect_conf_path))
for item in redirect_conf_data:
if site_name in item['sitename']:
return item
return False
def restore_redirect_conf(self, site_name: str, backup_data_path: str):
if os.path.exists(backup_data_path):
redirect_conf_data = json.loads(public.ReadFile(backup_data_path))
local_redirect_conf_data = []
if os.path.exists(self.redirect_conf_path):
local_redirect_conf_data = json.loads(public.ReadFile(self.redirect_conf_path))
data_exists = None
for item in local_redirect_conf_data:
if item['sitename'] == redirect_conf_data['sitename']:
data_exists = True
if not data_exists:
local_redirect_conf_data.append(redirect_conf_data)
public.WriteFile(self.redirect_conf_path, json.dumps(local_redirect_conf_data))
return False
def backup_proxy_conf(self, site_name: str):
if os.path.exists(self.proxy_conf_path):
proxy_conf_data = json.loads(public.ReadFile(self.proxy_conf_path))
for item in proxy_conf_data:
if site_name in item['sitename']:
return item
return False
def restore_proxy_conf(self, site_name: str, backup_data_path: str):
if os.path.exists(backup_data_path):
proxy_conf_data = json.loads(public.ReadFile(backup_data_path))
local_proxy_conf_data = []
if os.path.exists(self.proxy_conf_path):
local_proxy_conf_data = json.loads(public.ReadFile(self.proxy_conf_path))
data_exists = None
for item in local_proxy_conf_data:
if item['sitename'] == proxy_conf_data['sitename']:
data_exists = True
if not data_exists:
local_proxy_conf_data.append(proxy_conf_data)
public.WriteFile(self.proxy_conf_path, json.dumps(local_proxy_conf_data))
return False
if __name__ == '__main__':
# 获取命令行参数
if len(sys.argv) < 3:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1] # 方法名
timestamp = sys.argv[2] # IP地址
site_module = SiteModule() # 实例化对象
if hasattr(site_module, method_name): # 检查方法是否存在
method = getattr(site_module, method_name) # 获取方法
method(timestamp) # 调用方法
else:
print(f"Error: Method '{method_name}' 'does not exist'")

View File

@@ -0,0 +1,829 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: miku <miku@yakpanel.com>
# -------------------------------------------------------------------
import json
import os
import re
import sys
import warnings
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
if "/www/server/panel" not in sys.path:
sys.path.insert(0, "/www/server/panel")
import public
from YakPanel import app
from mod.project.backup_restore.base_util import BaseUtil
from mod.project.backup_restore.config_manager import ConfigManager
warnings.filterwarnings("ignore", category=SyntaxWarning)
OFFICIAL_URL = public.OfficialDownloadBase()
class SoftModule(BaseUtil, ConfigManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
self.packet = False
def get_install_type(self):
if os.path.exists("/usr/bin/yum") or os.path.exists("/usr/bin/dnf") or os.path.exists("/usr/sbin/yum"):
return 1
elif os.path.exists(
"/usr/bin/apt"
) or os.path.exists(
"/usr/sbin/apt-get"
) or os.path.exists(
"/usr/bin/apt-get"
):
return 4
else:
return 0
def get_web_server(self):
if os.path.exists("/www/server/nginx/sbin/nginx"):
nginx_version = public.ExecShell("nginx -v 2>&1")[0].replace("\n", "")
version_match = re.search(r'nginx/(\d+\.\d+)', nginx_version)
if version_match:
nginx_version = version_match.group(1)
result = {
"name": "nginx",
"version": nginx_version,
"size": BaseUtil().get_file_size("/www/server/nginx/"),
"status": 2,
}
self.print_log("nginx {}".format(nginx_version), 'backup')
return result
if os.path.exists("/www/server/apache/bin/httpd"):
apache_version = public.ExecShell("httpd -v 2>&1")[0].replace("\n", "")
version_match = re.search(r'Apache/(\d+\.\d+)', apache_version)
if version_match:
apache_version = version_match.group(1)
result = {
"name": "apache",
"version": apache_version,
"size": BaseUtil().get_file_size("/www/server/apache/"),
"status": 2,
}
self.print_log("apache {}".format(apache_version), 'backup')
return result
if os.path.exists("/usr/local/lsws/bin/openlitespeed"):
openlitespeed_version = public.ExecShell(
"/usr/local/lsws/bin/openlitespeed -v 2>&1")[0].replace("\n", "")
version_match = re.search(r'LiteSpeed/(\d+\.\d+\.\d+) Open', openlitespeed_version)
if version_match:
openlitespeed_version = version_match.group(1)
result = {
"name": "openlitespeed",
"version": openlitespeed_version,
"size": BaseUtil().get_file_size("/usr/local/lsws/"),
"status": 2,
}
self.print_log("openlitespeed {}".format(openlitespeed_version), 'backup')
return result
def get_php_server(self):
php_dir = "/www/server/php"
if os.path.exists(php_dir):
phplist = []
for dir_name in os.listdir(php_dir):
dir_path = dir_path = os.path.join(php_dir, dir_name)
if os.path.isdir(dir_path) and os.path.exists(os.path.join(dir_path, 'bin/php')):
phplist.append(int(dir_name))
result = []
for php_ver in phplist:
php_ext = public.ExecShell("/www/server/php/{}/bin/php -m".format(php_ver))[0].split("\n")
filtered_data = [item for item in php_ext if item not in ('[PHP Modules]', '[Zend Modules]', '')]
php_result = {
"name": "php",
"version": php_ver,
"php_ext": filtered_data,
"size": BaseUtil().get_file_size("/www/server/php/{}".format(php_ver)),
"status": 2,
}
# 将PHP版本号转换为带小数点的格式
if isinstance(php_ver, (int, str)) and len(str(php_ver)) == 2:
# 例如54 -> 5.4, 70 -> 7.0
php_result['version'] = f"{str(php_ver)[0]}.{str(php_ver)[1]}"
elif isinstance(php_ver, (int, str)) and len(str(php_ver)) == 3:
# 例如82 -> 8.2
php_result['version'] = f"{str(php_ver)[0]}.{str(php_ver)[1:]}"
result.append(php_result)
self.print_log("php {}".format(php_result['version']), 'backup')
return result
return None
def get_mysql_server(self):
if os.path.exists("/www/server/mysql/bin/mysql"):
mysql_version = None
if os.path.exists("/www/server/mysql/version.pl"):
mysql_version = public.ReadFile("/www/server/mysql/version.pl").replace("\n", "")
elif os.path.exists("/www/server/mysql/version_check.pl"):
mysql_version = public.ExecShell("/www/server/mysql/version_check.pl")[0].replace("\n", "")
match = re.search(r'10\.\d+', mysql_version)
if match:
version = match.group()
type = "mariadb"
mysql_version = version
else:
type = "mysql"
mysql_version = mysql_version[0:3]
result = {
"type": type,
"version": mysql_version,
"size": BaseUtil().get_file_size("/www/server/mysql/"),
"status": 2,
}
self.print_log("mysql {}".format(mysql_version), 'backup')
return result
else:
return False
def get_ftp_server(self, get=None):
if os.path.exists("/www/server/pure-ftpd/bin/pure-pw"):
size = BaseUtil().get_file_size("/www/server/pure-ftpd/")
try:
pure_ftp_port = \
public.ExecShell("cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep Bind|awk '{print $2}'")[
0].replace("\n", "").replace("0.0.0.0,", "")
pure_ftp_port = int(pure_ftp_port)
except:
pure_ftp_port = 21
self.print_log("pure-ftpd {}".format(pure_ftp_port), 'backup')
return {
"name": "pure-ftpd",
"version": "1.0.49",
"size": size,
"port": int(pure_ftp_port),
"status": 2,
}
else:
return None
def get_node_list(self, timestamp):
node_dir = "/www/server/nodejs"
if not os.path.exists(node_dir):
return None
node_list = []
result = []
for dir_name in os.listdir(node_dir):
if re.match(r"^v[1-9]\d*(\.\d+)*$", dir_name):
node_list.append(dir_name)
for node_ver in node_list:
node_ver_path = os.path.join(node_dir, node_ver)
node_mod_path = os.path.join(node_ver_path, "lib", "node_modules")
if os.path.isdir(node_mod_path):
mod_list = os.listdir(node_mod_path)
else:
mod_list = []
node_result = {
"name": "node",
"version": node_ver,
"mod_list": mod_list,
"size": BaseUtil().get_file_size("/www/server/nodejs/{}".format(node_ver)),
"status": 2,
}
result.append(node_result)
self.print_log("node {}".format(node_ver), 'backup')
if result and self.packet:
backup_path = os.path.join(self.base_path, f"{timestamp}_backup/plugin")
public.ExecShell(f"\cp -rpa /www/server/nodejs/* {backup_path}/nodejs/*")
return result
def get_redis_server(self):
if os.path.exists("/www/server/redis/src/redis-server") and os.path.exists("/www/server/redis/version.pl"):
redis_version = public.ReadFile("/www/server/redis/version.pl")
size = BaseUtil().get_file_size("/www/server/redis/")
self.print_log("redis {}".format(redis_version[0:3]), 'backup')
return {
"name": "redis",
"version": redis_version[0:3],
"size": size,
"status": 2,
}
else:
return None
def get_memcached_server(self):
if os.path.exists("/usr/local/memcached/bin/memcached"):
size = BaseUtil().get_file_size("/usr/local/memcached/")
self.print_log("memcached {}".format("1.6.12"), 'backup')
return {
"name": "memcached",
"version": "1.6.12",
"size": size,
"status": 2,
}
else:
return None
def get_mongodb_server(self):
if os.path.exists("/www/server/mongodb/version.pl"):
mongod = "/www/server/mongodb/bin/mongod"
mongo = "/www/server/mongodb/bin/mongo"
if os.path.exists(mongod) or os.path.exists(mongo):
mongodb_version = public.ReadFile("/www/server/mongodb/version.pl")
size = BaseUtil().get_file_size("/www/server/mongodb/")
self.print_log("mongodb {}".format(mongodb_version[0:3]), 'backup')
return {
"name": "mongodb",
"version": mongodb_version[0:3],
"size": size,
"status": 2,
}
else:
return None
def get_pgsql_server(self):
if os.path.exists("/www/server/pgsql/bin/pg_config"):
pgsql_version = \
public.ExecShell("/www/server/pgsql/bin/pg_config --version")[0].replace("\n", "").split(" ")[1]
size = BaseUtil().get_file_size("/www/server/pgsql/")
self.print_log("pgsql {}".format(pgsql_version), 'backup')
return {
"name": "pgsql",
"version": pgsql_version,
"size": size,
"status": 2,
}
else:
return None
def get_phpmyadmin_version(self):
if os.path.exists("/www/server/phpmyadmin/version.pl"):
phpmyadmin_version = public.ReadFile("/www/server/phpmyadmin/version.pl").replace("\n", "")
size = BaseUtil().get_file_size("/www/server/phpmyadmin/")
self.print_log("phpmyadmin {}".format(phpmyadmin_version), 'backup')
return {
"name": "phpmyadmin",
"version": phpmyadmin_version,
"size": size,
"status": 2,
}
else:
return None
def get_soft_data(self, timestamp=None, packet: bool = False):
self.print_log("====================================================", "backup")
self.print_log(public.lang("Start backing up software information"), "backup")
self.packet = packet
result = {
"web_server": self.get_web_server(),
"php_server": self.get_php_server(),
"mysql_server": self.get_mysql_server(),
"ftp_server": self.get_ftp_server(),
# "node_list": self.get_node_list(timestamp),
"redis_server": self.get_redis_server(),
"memcached_server": self.get_memcached_server(),
"mongodb_server": self.get_mongodb_server(),
"pgsql_server": self.get_pgsql_server(),
"phpmyadmin_version": self.get_phpmyadmin_version(),
}
public.WriteFile("/root/soft.json", json.dumps(result))
self.print_log(public.lang("Software information backup completed"), 'backup')
return result
# ======================== install software ========================
def install_web_server(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
web_server = restore_data['data_list']['soft']['web_server']
install_type = self.get_install_type()
log_str = public.lang("Start installing nginx-{}").format(web_server.get('version', 'latest'))
try:
result = None
if web_server['name'] == 'nginx':
self.print_log(log_str, "restore")
web_server['restore_status'] = 1
web_server['msg'] = None
self.update_restore_data_list(timestamp, restore_data)
result = public.ExecShell(
"cd /www/server/panel/install && wget -O nginx.sh {}/install/{}/nginx.sh && bash nginx.sh install {}".format(
OFFICIAL_URL, install_type, web_server['version']
)
)
elif web_server['name'] == 'apache':
self.print_log(public.lang("Start installing apache service"), "restore")
web_server['restore_status'] = 1
web_server['msg'] = None
self.update_restore_data_list(timestamp, restore_data)
result = public.ExecShell(
"cd /www/server/panel/install && wget -O apache.sh {}/install/{}/apache.sh && bash apache.sh install {}".format(
OFFICIAL_URL, install_type, web_server['version']
)
)
if web_server['name'] == 'nginx' and os.path.exists("/www/server/nginx/sbin/nginx"):
new_log_str = "{}-{}".format(web_server['name'], web_server['version'])
self.replace_log(log_str, new_log_str, "restore")
web_server['restore_status'] = 2
web_server['msg'] = None
self.update_restore_data_list(timestamp, restore_data)
elif web_server['name'] == 'apache' and os.path.exists("/www/server/apache/bin/httpd"):
new_log_str = "{}-{}".format(web_server['name'], web_server['version'])
self.replace_log(log_str, new_log_str, "restore")
web_server['restore_status'] = 2
web_server['msg'] = None
self.update_restore_data_list(timestamp, restore_data)
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"{}-{} ✗ Installation failed Reason: {} \n Please try to reinstall the web server in the software store after the restore task ends").format(
web_server['name'], web_server['version'], err_msg
)
self.replace_log(log_str, new_log_str, "restore")
web_server['restore_status'] = 3
web_server['msg'] = new_log_str
self.update_restore_data_list(timestamp, restore_data)
except Exception as e:
err_msg = public.lang(
"{}-{} ✗ Installation failed Reason: {} \n Please try to reinstall the web server in the software store after the restore task ends").format(
web_server['name'], web_server['version'], str(e)
)
web_server['restore_status'] = 3
web_server['msg'] = err_msg
self.update_restore_data_list(timestamp, restore_data)
self.print_log(public.lang("Web server installation completed"), "restore")
def install_php_server(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
php_server = restore_data['data_list']['soft']['php_server']
install_type = self.get_install_type()
for php in php_server:
php_ver = php['version']
self.update_restore_data_list(timestamp, restore_data)
log_str = public.lang("Start installing php-{}").format(php_ver)
self.print_log(log_str, "restore")
path_ver = php_ver.replace('.', '')
if os.path.exists("/www/server/php/{}".format(path_ver)):
new_log_str = "php-{}".format(php_ver)
self.replace_log(log_str, new_log_str, "restore")
continue
result = public.ExecShell(
"cd /www/server/panel/install && wget -O php.sh {}/install/{}/php.sh && bash php.sh install {}".format(
OFFICIAL_URL, install_type, php_ver
)
)
if not os.path.exists("/www/server/php/{}".format(path_ver)):
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"php-{} ✗ Installation failed Reason: {} \n Please try to reinstall php in the software store after the restore task ends").format(
php_ver,
err_msg)
php["restore_status"] = 3
php["msg"] = err_msg
self.replace_log(log_str, new_log_str, "restore")
else:
php["restore_status"] = 2
php["msg"] = "success"
new_log_str = "php-{}".format(php_ver)
self.replace_log(log_str, new_log_str, "restore")
self.update_restore_data_list(timestamp, restore_data)
def install_node(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
node_list = restore_data['data_list']['soft']['node_list']
for node_data in node_list:
node_ver = node_data['version']
log_str = public.lang("Start installing node-{}").format(node_ver)
self.print_log(log_str, "restore")
if os.path.exists("/www/server/nodejs/{}".format(node_ver)):
new_log_str = "node-{}".format(node_ver)
self.replace_log(log_str, new_log_str, "restore")
continue
result = public.ExecShell(
"cd /www/server/panel/install && wget -O node_plugin_install.sh {}/install/0/node_plugin_install.sh && bash node_plugin_install.sh {}".format(
OFFICIAL_URL, node_ver
)
)
for mod_list in node_data['mod_list']:
mod_name = mod_list
mod_shell = '''
export PATH
export HOME=/root
export NODE_PATH="/www/server/nodejs/{node_ver}/etc/node_modules"
/www/server/nodejs/{node_ver}//bin/npm config set registry https://registry.npmmirror.com/
/www/server/nodejs/{node_ver}//bin/npm config set prefix /www/server/nodejs/{node_ver}/
/www/server/nodejs/{node_ver}//bin/npm config set cache /www/server/nodejs/{node_ver}//cache
/www/server/nodejs/{node_ver}//bin/npm config set strict-ssl false
/www/server/nodejs/{node_ver}//bin/yarn config set registry https://registry.npmmirror.com/
/www/server/nodejs/{node_ver}/bin/npm install {mod_name} -g &> /www/server/panel/plugin/nodejs/exec.log
'''.format(node_ver=node_ver, mod_name=mod_name)
result = public.ExecShell(mod_shell)
if os.path.exists("/www/server/nodejs/{}".format(node_ver)):
new_log_str = "node-{}".format(node_ver)
self.replace_log(log_str, new_log_str, "restore")
node_data["restore_status"] = 2
node_data["msg"] = None
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"node-{} ✗ Installation failed Reason: {} \n Please try to reinstall node in the software store after the restore task ends").format(
node_ver, err_msg)
self.replace_log(log_str, new_log_str, "restore")
node_data["restore_status"] = 3
node_data["msg"] = err_msg
self.update_restore_data_list(timestamp, restore_data)
def install_mysql_server(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
mysql_server = restore_data['data_list']['soft']['mysql_server']
install_type = self.get_install_type()
if mysql_server['type'] == 'mariadb':
log_str = public.lang("Start installing mariadb-{}").format(mysql_server['version'])
self.print_log(log_str, "restore")
if os.path.exists("/www/server/mysql/bin/mysql"):
new_log_str = "mariadb-{}".format(mysql_server['version'])
self.replace_log(log_str, new_log_str, "restore")
return
result = public.ExecShell(
"cd /www/server/panel/install && wget -O mysql.sh {}/install/{}/mysql.sh && bash mysql.sh install {}".format(
OFFICIAL_URL, install_type, f"mariadb_{mysql_server['version']}"
)
)
if os.path.exists("/www/server/mysql/bin/mysql"):
new_log_str = "mariadb-{}".format(mysql_server['version'])
self.replace_log(log_str, new_log_str, "restore")
mysql_server["restore_status"] = 2
mysql_server["msg"] = None
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"mariadb-{} ✗ Installation failed Reason: {} \n Please try to reinstall mariadb in the software store after the restore task ends").format(
mysql_server['version'], err_msg
)
self.replace_log(log_str, new_log_str, "restore")
mysql_server["restore_status"] = 3
mysql_server["msg"] = err_msg
self.update_restore_data_list(timestamp, restore_data)
return
if mysql_server['type'] == 'mysql':
log_str = public.lang("Start installing mysql-{}").format(mysql_server['version'])
self.print_log(log_str, "restore")
if os.path.exists("/www/server/mysql/bin/mysql"):
new_log_str = "mysql-{}".format(mysql_server['version'])
self.replace_log(log_str, new_log_str, "restore")
return
result = public.ExecShell(
"cd /www/server/panel/install && wget -O mysql.sh {}/install/{}/mysql.sh && bash mysql.sh install {}".format(
OFFICIAL_URL, install_type, mysql_server['version']
)
)
if os.path.exists("/www/server/mysql/bin/mysql"):
new_log_str = "mysql-{}".format(mysql_server['version'])
self.replace_log(log_str, new_log_str, "restore")
mysql_server["restore_status"] = 2
mysql_server["msg"] = None
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"mysql-{} ✗ Installation failed Reason: {} \n Please try to reinstall mysql in the software store after the restore task ends").format(
mysql_server['version'], err_msg
)
self.replace_log(log_str, new_log_str, "restore")
mysql_server["restore_status"] = 3
mysql_server["msg"] = err_msg
self.update_restore_data_list(timestamp, restore_data)
def install_mongodb_server(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
mongodb_server = restore_data['data_list']['soft']['mongodb_server']
# install_type = self.get_install_type()
log_str = public.lang("Start installing mongodb-{}").format(mongodb_server['version'])
self.print_log(log_str, "restore")
mongo = "/www/server/mongodb/bin/mongo"
mongod = "/www/server/mongodb/bin/mongod"
if (os.path.exists(mongo) or os.path.exists(mongod)) and os.path.exists("/www/server/mongodb/version.pl"):
new_log_str = "mongodb-{}".format(mongodb_server['version'])
self.replace_log(log_str, new_log_str, "restore")
return
result = public.ExecShell(
"cd /www/server/panel/install && wget -O mongodb.sh {}/install/0/mongodb.sh && bash mongodb.sh install {}".format(
OFFICIAL_URL, mongodb_server['version']
)
)
if os.path.exists(mongo) or os.path.exists(mongod):
new_log_str = "mongodb-{}".format(mongodb_server['version'])
self.replace_log(log_str, new_log_str, "restore")
mongodb_server["restore_status"] = 2
mongodb_server["msg"] = None
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"mongodb-{} ✗ Installation failed Reason: {} \n Please try to reinstall mongodb in the software store after the restore task ends").format(
mongodb_server['version'], err_msg)
self.replace_log(log_str, new_log_str, "restore")
mongodb_server["restore_status"] = 3
mongodb_server["msg"] = err_msg
self.update_restore_data_list(timestamp, restore_data)
def install_memcached_server(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
memcached_server = restore_data['data_list']['soft']['memcached_server']
# install_type = self.get_install_type()
log_str = public.lang("Start installing memcached-{}").format(memcached_server['version'])
self.print_log(log_str, "restore")
if os.path.exists("/usr/local/memcached/bin/memcached"):
new_log_str = "memcached-{}".format(memcached_server['version'])
self.replace_log(log_str, new_log_str, "restore")
return
result = public.ExecShell(
f"cd /www/server/panel/install && wget -O memcached.sh {OFFICIAL_URL}/install/0/memcached.sh && bash memcached.sh install"
)
if os.path.exists("/usr/local/memcached/bin/memcached"):
new_log_str = "memcached-{}".format(memcached_server['version'])
self.replace_log(log_str, new_log_str, "restore")
memcached_server["restore_status"] = 2
memcached_server["msg"] = None
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"memcached-{} ✗ Installation failed Reason: {} \n Please try to reinstall memcached in the software store after the restore task ends").format(
memcached_server['version'], err_msg)
self.replace_log(log_str, new_log_str, "restore")
memcached_server["restore_status"] = 3
memcached_server["msg"] = err_msg
self.update_restore_data_list(timestamp, restore_data)
def install_redis_server(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
redis_server = restore_data['data_list']['soft']['redis_server']
# install_type = self.get_install_type()
log_str = public.lang("Start installing redis-{}").format(redis_server['version'])
self.print_log(log_str, "restore")
if os.path.exists("/www/server/redis/src/redis-server") and os.path.exists("/www/server/redis/version.pl"):
new_log_str = "redis-{}".format(redis_server['version'])
self.replace_log(log_str, new_log_str, "restore")
return
result = public.ExecShell(
"cd /www/server/panel/install && wget -O redis.sh {}/install/0/redis.sh && bash redis.sh install {}".format(
OFFICIAL_URL, redis_server['version']
)
)
if os.path.exists("/www/server/redis/src/redis-cli"):
new_log_str = "redis-{}".format(redis_server['version'])
self.replace_log(log_str, new_log_str, "restore")
redis_server["restore_status"] = 2
redis_server["msg"] = None
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = "redis-{}{}".format(redis_server['version'], err_msg)
self.replace_log(log_str, new_log_str, "restore")
redis_server["restore_status"] = 3
redis_server["msg"] = err_msg
self.update_restore_data_list(timestamp, restore_data)
def install_pgsql_server(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
pgsql_server = restore_data['data_list']['soft']['pgsql_server']
log_str = public.lang("Start installing pgsql-{}").format(pgsql_server['version'])
self.print_log(log_str, "restore")
if os.path.exists("/www/server/pgsql/bin/pg_config"):
new_log_str = "pgsql-{}".format(pgsql_server['version'])
self.replace_log(log_str, new_log_str, "restore")
return
self.update_restore_data_list(timestamp, restore_data)
down_file = "postgresql-{pgsql_version}.tar.gz".format(pgsql_version=pgsql_server['version'])
down_url = "{}/src/postgresql-{}.tar.gz".format(
OFFICIAL_URL, pgsql_server['version']
)
result = public.ExecShell(
"cd /www/server/panel/install && wget -O pgsql_install.sh {}/install/0/pgsql_install.sh && bash pgsql_install.sh {} {}".format(
OFFICIAL_URL, down_file, down_url
)
)
if os.path.exists("/www/server/pgsql/bin/psql"):
new_log_str = "pgsql-{}".format(pgsql_server['version'])
self.replace_log(log_str, new_log_str, "restore")
pgsql_server["restore_status"] = 2
pgsql_server["msg"] = None
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = "pgsql-{}{}".format(pgsql_server['version'], err_msg)
self.replace_log(log_str, new_log_str, "restore")
pgsql_server["restore_status"] = 3
pgsql_server["msg"] = err_msg
self.update_restore_data_list(timestamp, restore_data)
def install_phpmyadmin(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
phpmyadmin_server = restore_data['data_list']['soft']['phpmyadmin_version']
log_str = public.lang("Start installing phpmyadmin-{}").format(phpmyadmin_server['version'])
self.print_log(log_str, "restore")
result = public.ExecShell(
"cd /www/server/panel/install && wget -O phpmyadmin.sh {}/install/0/phpmyadmin.sh && bash phpmyadmin.sh install {}".format(
OFFICIAL_URL, phpmyadmin_server['version']
)
)
if os.path.exists("/www/server/phpmyadmin/version.pl"):
phpmyadmin_server["restore_status"] = 2
phpmyadmin_server["msg"] = None
new_log_str = "phpmyadmin-{}".format(phpmyadmin_server['version'])
self.replace_log(log_str, new_log_str, "restore")
else:
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"phpmyadmin-{} ✗ Installation failed Reason: {} \n Please try to reinstall phpmyadmin in the software store after the restore task ends").format(
phpmyadmin_server['version'], err_msg
)
self.replace_log(log_str, new_log_str, "restore")
phpmyadmin_server["restore_status"] = 3
phpmyadmin_server["msg"] = err_msg
self.update_restore_data_list(timestamp, restore_data)
def install_ftp_server(self, timestamp):
restore_data = self.get_restore_data_list(timestamp)
ftp_server = restore_data['data_list']['soft']['ftp_server']
log_str = public.lang("Start installing ftp-{}").format(ftp_server['version'])
self.print_log(log_str, "restore")
if os.path.exists("/www/server/pure-ftpd/bin/pure-pw"):
new_log_str = "ftp-{}".format(ftp_server['version'])
self.replace_log(log_str, new_log_str, "restore")
ftp_server["restore_status"] = 2
ftp_server["msg"] = None
self.update_restore_data_list(timestamp, restore_data)
return
result = public.ExecShell(
f"cd /www/server/panel/install && wget -O pureftpd.sh {OFFICIAL_URL}/install/0/pureftpd.sh && bash pureftpd.sh install"
)
public.ExecShell("rm -f /www/server/pure-ftpd/etc/pureftpd.passwd")
public.ExecShell("rm -f /www/server/pure-ftpd/etc/pureftpd.pdb")
if not os.path.exists("/www/server/pure-ftpd/bin/pure-pw"):
combined_output = (result[0] + result[1]).splitlines()
err_msg = '\n'.join(combined_output[-10:])
new_log_str = public.lang(
"ftp-{} ✗ Installation failed Reason: {} \nPlease try to reinstall ftp in the software store after the restore task ends").format(
ftp_server['version'], err_msg)
self.replace_log(log_str, new_log_str, "restore")
ftp_server["restore_status"] = 3
ftp_server["msg"] = err_msg
else:
new_log_str = "ftp-{}".format(ftp_server['version'])
self.replace_log(log_str, new_log_str, "restore")
ftp_server["restore_status"] = 2
ftp_server["msg"] = None
self.update_restore_data_list(timestamp, restore_data)
import ftp
if ftp_server['port'] != 21:
with app.app_context():
args = public.dict_obj()
args.port = str(ftp_server['port'])
ftp.ftp().setPort(args)
def restore_env(self, timestamp):
self.print_log("==================================", "restore")
self.print_log(public.lang("Start restoring panel running environment"), "restore")
self.print_log(public.lang("Will skip installation if the same environment exists"), "restore")
restore_data = self.get_restore_data_list(timestamp)
self.update_restore_data_list(timestamp, restore_data)
soft_json_data = restore_data['data_list']['soft']
try:
if soft_json_data['web_server']:
self.install_web_server(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing web server: {}".format(str(e)))
pass
try:
if soft_json_data['php_server']:
self.install_php_server(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing PHP server: {}".format(str(e)))
pass
try:
if soft_json_data['mysql_server']:
self.install_mysql_server(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing MySQL server: {}".format(str(e)))
pass
try:
if soft_json_data['ftp_server']:
self.install_ftp_server(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing FTP server: {}".format(str(e)))
pass
# try:
# if soft_json_data['node_list']:
# self.install_node(timestamp)
# except Exception as e:
# import traceback
# public.print_log(traceback.format_exc())
# public.print_log("Error installing Node.js: {}".format(str(e)))
# pass
try:
if soft_json_data['redis_server']:
self.install_redis_server(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing Redis server: {}".format(str(e)))
pass
try:
if soft_json_data['memcached_server']:
self.install_memcached_server(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing Memcached server: {}".format(str(e)))
pass
try:
if soft_json_data['mongodb_server']:
self.install_mongodb_server(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing MongoDB server: {}".format(str(e)))
pass
try:
if soft_json_data['pgsql_server']:
self.install_pgsql_server(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing PostgreSQL server: {}".format(str(e)))
pass
try:
if soft_json_data['phpmyadmin_version']:
self.install_phpmyadmin(timestamp)
except Exception as e:
import traceback
public.print_log(traceback.format_exc())
public.print_log("Error installing phpMyAdmin: {}".format(str(e)))
pass
if __name__ == '__main__':
# 获取命令行参数
if len(sys.argv) < 2:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1] # 方法名 p
timestamp = sys.argv[2]
soft_manager = SoftModule() # 实例化对象
if hasattr(soft_manager, method_name): # 检查方法是否存在
method = getattr(soft_manager, method_name) # 获取方法
method(timestamp) # 调用方法
else:
print(f"Error: {public.lang('Method')} '{method_name}' {public.lang('does not exist')}")

View File

@@ -0,0 +1,92 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: miku <miku@yakpanel.com>
# -------------------------------------------------------------------
import os
import sys
import warnings
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
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.config_manager import ConfigManager
warnings.filterwarnings("ignore", category=SyntaxWarning)
class SshModule(BaseUtil, ConfigManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
self.ssh_path = "/www/server/panel/config/ssh_info"
def backup_ssh_data(self, timestamp):
self.print_log("====================================================", "backup")
self.print_log(public.lang("Start backing up terminal data"), "backup")
ssh_backup_path = self.base_path + "/{timestamp}_backup/ssh".format(timestamp=timestamp)
if not os.path.exists(ssh_backup_path):
public.ExecShell('mkdir -p {}'.format(ssh_backup_path))
print(self.ssh_path)
public.ExecShell("\cp -rpa {} {}".format(self.ssh_path, ssh_backup_path))
ssh_info = {
'status': 2,
'msg': None,
'ssh_info_path': ssh_backup_path,
}
backup_size = self.format_size(self.get_file_size(ssh_backup_path))
self.print_log(public.lang("Terminal data backup completed. Data size: {}").format(backup_size), 'backup')
data_list = self.get_backup_data_list(timestamp)
data_list['data_list']['ssh'] = ssh_info
self.update_backup_data_list(timestamp, data_list)
def restore_ssh_data(self, timestamp):
self.print_log("==================================", "restore")
self.print_log(public.lang("Start restoring terminal data"), "restore")
restore_data = self.get_restore_data_list(timestamp)
ssh_data = restore_data['data_list']['ssh']
ssh_info_path = ssh_data['ssh_info_path'] + "/ssh_info"
restore_data['data_list']['ssh']['restore_status'] = 1
self.update_restore_data_list(timestamp, restore_data)
if not os.path.exists(ssh_info_path):
self.print_log(public.lang("Restore failed, file does not exist"), "restore")
return
if not os.path.exists(self.ssh_path):
public.ExecShell("mkdir -p {}".format(self.ssh_path))
public.ExecShell("\cp -rpa {}/* {}".format(ssh_info_path, self.ssh_path))
self.print_log(public.lang("Terminal data restoration completed"), "restore")
restore_data['data_list']['ssh']['restore_status'] = 2
self.update_restore_data_list(timestamp, restore_data)
if __name__ == '__main__':
# 获取命令行参数
if len(sys.argv) < 2:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1] # 方法名
timestamp = sys.argv[2]
ssh_manager = SshModule() # 实例化对象
if hasattr(ssh_manager, method_name): # 检查方法是否存在
method = getattr(ssh_manager, method_name) # 获取方法
method(timestamp) # 调用方法
else:
print(f"Error: Method '{method_name}' does not exist")

View File

@@ -0,0 +1,343 @@
# coding: utf-8
# -------------------------------------------------------------------
# yakpanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 yakpanel(http://www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
import os
import sys
import time
from pathlib import Path
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
if "/www/server/panel/class_v2" not in sys.path:
sys.path.insert(0, "/www/server/panel/class_v2")
if "/www/server/panel" not in sys.path:
sys.path.insert(0, "/www/server/panel")
import public
from public.hook_import import hook_import
hook_import()
from YakPanel import app
from ssl_domainModelV2.api import DomainObject
from ssl_domainModelV2.service import CertHandler
from ssl_domainModelV2.config import UserFor
from ssl_domainModelV2.model import DnsDomainSSL, DnsDomainProvider
from mod.project.backup_restore.data_manager import DataManager
class SSLModel(DataManager):
def __init__(self):
super().__init__()
self.base_path = '/www/backup/backup_restore'
self.bakcup_task_json = self.base_path + '/backup_task.json'
def get_ssl_backup_conf(self, timestamp: int = None) -> dict:
"""
Get SSL certificate and DNS API provider backup configuration
"""
ssl_list = [
{
**ssl.as_dict(),
"data_type": "backup",
"status": 0,
"msg": None,
} for ssl in DnsDomainSSL.objects.filter(is_order=0) # 过滤商业证书
]
provider_list = [
{
**x.as_dict(),
# 与备份的 status 字段冲突, 使用 account status
"account_status": x.status,
"data_type": "backup",
"status": 0,
"msg": None,
} for x in DnsDomainProvider.objects.all()
]
res = {
"ssl_list": ssl_list,
"provider_list": provider_list,
}
return res
def backup_ssl_data(self, timestamp) -> None:
"""
Backup domain management center
"""
# 总配置
data_list = self.get_backup_data_list(timestamp)
if not data_list:
return None
data_backup_path = data_list.get("backup_path")
ssl_backup_path = Path(data_backup_path) / "ssl"
ssl_backup_path.mkdir(parents=True, exist_ok=True)
self.print_log("==================================", "backup")
self.print_log(public.lang("Start backing up SSL certificate information"), "backup")
for ssl in data_list['data_list']['ssl'].get("ssl_list", []): # SSL in the general configuration
try:
if not ssl.get("path") or not os.path.exists(ssl.get("path")):
err = public.lang("{} {} Certificate file does not exist ✗").format(
ssl['info'].get("issuer_O", ""), ssl['dns']
)
self.print_log(err, "backup")
ssl["status"] = 3
ssl["msg"] = err
continue
if ssl.get("not_after_ts") < time.time() * 1000:
err = public.lang("{} [{}] Certificate has expired ✗").format(
ssl['info'].get("issuer_O", ""), str(ssl['dns'])
)
self.print_log(err, "backup")
ssl["status"] = 3
ssl["msg"] = err
continue
domian_path = ssl_backup_path / ssl.get("hash")
CertHandler.make_last_info(domian_path, force=True)
public.ExecShell(f"\cp -rpa {ssl['path']} {domian_path}")
ssl["status"] = 2
self.print_log(public.lang("{} {}").format(
ssl['info'].get("issuer_O", ""), ssl['dns']
), "backup")
except Exception as e:
err = public.lang("{} {} Backup failed: {}").format(
ssl['info'].get('issuer_O', ''), ssl['dns'], str(e)
)
ssl["status"] = 3
ssl["msg"] = err
self.print_log(err, "backup")
continue
new_provider_info = [
{**x, "status": 2} for x in data_list['data_list']['ssl'].get("provider_list", [])
]
data_list['data_list']['ssl']['provider_list'] = new_provider_info
self.print_log(public.lang("DNS API provider information backup completed"), "backup")
self.update_backup_data_list(timestamp, data_list)
self.print_log(public.lang("SSL certificate information backup completed"), "backup")
def _rebuild_deploy(self, ssl_obj: DnsDomainSSL, backup_ssl: dict) -> None:
try:
def r_log(log_str: str, new_log: str):
self.replace_log(log_str, new_log, "restore")
used = backup_ssl.get("user_for", {})
if not ssl_obj or not used:
return
# pre clear
for other_ssl in DnsDomainSSL.objects.filter(hash__ne=ssl_obj.hash):
is_change = False
for site_name in used.get(UserFor.sites, []):
if site_name in other_ssl.sites_uf:
other_ssl.sites_uf.remove(site_name)
is_change = True
for mail_name in used.get(UserFor.mails, []):
if mail_name in other_ssl.mails_uf:
other_ssl.mails_uf.remove(mail_name)
is_change = True
for panel_name in used.get(UserFor.panel, []):
if panel_name in other_ssl.panel_uf:
other_ssl.panel_uf = []
is_change = True
if is_change:
other_ssl.save()
if used.get(UserFor.sites):
log_str = public.lang("Restoring deployment sites for certificate {}...").format(backup_ssl['subject'])
self.print_log(log_str, "restore")
build_sites = ssl_obj.deploy_sites(
site_names=used[UserFor.sites], replace=True
)
r_log(log_str, public.lang("Restored deployment sites for certificate {}: {}").format(
backup_ssl['subject'], build_sites.get('msg')
))
if used.get(UserFor.mails):
log_str = public.lang("Restoring deployment mailboxes for certificate {}...").format(
backup_ssl['subject'])
self.print_log(log_str, "restore")
build_mails = ssl_obj.deploy_mails(
mail_names=used[UserFor.mails]
)
r_log(log_str, public.lang("Restored deployment mailboxes for certificate {}: {}").format(
backup_ssl['subject'], build_mails.get('msg')
))
if used.get(UserFor.panel):
log_str = public.lang("Restoring deployment panel for certificate {}...").format(backup_ssl['subject'])
self.print_log(log_str, "restore")
build_panel = ssl_obj.deploy_panel(
recover=0
)
r_log(log_str, public.lang("Restored deployment panel for certificate {}: {}").format(
backup_ssl['subject'], build_panel.get('msg')
))
except Exception as e:
public.print_log("rebuild deploy error: {}".format(str(e)))
def _restore_ssl(self, backup_ssl: dict, pem: str, key: str) -> None:
exist_obj = DnsDomainSSL.objects.filter(
hash=CertHandler.get_hash(cert_pem=pem)
).first()
if exist_obj:
if not self.overwrite:
return
# overwrite
# exist_obj.provider_id = backup_ssl["provider_id"]
# exist_obj.not_after = backup_ssl["not_after"]
# exist_obj.not_after_ts = backup_ssl["not_after_ts"]
exist_obj.user_for = backup_ssl["user_for"]
exist_obj.info = backup_ssl["info"]
exist_obj.alarm = backup_ssl["alarm"]
exist_obj.auto_renew = backup_ssl["auto_renew"]
exist_obj.auth_info = backup_ssl["auth_info"]
exist_obj.log = backup_ssl["log"]
exist_obj.save()
# ssl_obj = exist_obj
else:
try:
insert = CertHandler().save_by_data(
cert_pem=pem,
private_key=key,
new_auth_info=backup_ssl["auth_info"],
)
if not insert:
raise Exception(public.lang("Certificate insertion failed, please check the log"))
except Exception as e:
raise Exception(public.lang(f"Certificate Restore Failed: {str(e)}"))
# ssl_obj = DnsDomainSSL.objects.filter(hash=insert["hash"]).first()
# if ssl_obj:
# # it will update the ssl field 'user_for'
# self._rebuild_deploy(
# ssl_obj=ssl_obj,
# backup_ssl=backup_ssl,
# )
def _restore_provider(self, provider: dict):
if_exist = DnsDomainProvider.objects.filter(
name=provider["name"],
api_user=provider.get("api_user", ""),
api_key=provider["api_key"],
).first()
if if_exist:
if self.overwrite:
return
return
res = DomainObject().create_dns_api(
public.to_dict_obj({
"name": provider["name"],
"api_user": provider.get("api_user", ""),
"api_key": provider["api_key"],
"status": provider.get("account_status", 1),
"permission": provider.get("permission", "-"),
"alias": provider["alias"],
"ps": provider["ps"],
})
)
if res.get("status", 0) != 0:
raise Exception(public.lang(
f"Restore DNS API provider failed: {res.get('message', 'create dns api error')}"
))
def restore_ssl_data(self, timestamp: int) -> None:
""" Restore domain management center """
self.print_log("====================================================", "restore")
self.print_log(public.lang("Start restoring domain SSL certificate configuration"), "restore")
restore_data = self.get_restore_data_list(timestamp)
if not restore_data:
self.print_log(public.lang("No restore data found"), "restore")
return
ssl_cert_path = Path(restore_data.get("backup_path")) / "ssl"
if not ssl_cert_path.exists():
self.print_log(
public.lang("Backup directory {} does not exist, unable to restore SSL certificate information").format(
ssl_cert_path
), "restore")
return
ssl_info = restore_data["data_list"].get("ssl", {})
with app.app_context():
# ======================= ssl =============================
for ssl in ssl_info.get("ssl_list", []):
log_str = public.lang("Restoring {} Subject: {}").format(
ssl['info'].get('issuer_O'), ssl['subject']
)
try:
self.print_log(log_str, "restore")
ssl["restore_status"] = 1
ssl_path = ssl_cert_path / ssl["hash"]
if not ssl_path.exists():
raise Exception(public.lang("Certificate file does not exist"))
pem = ssl_path / "fullchain.pem"
key = ssl_path / "privkey.pem"
if not pem.exists() or not key.exists():
raise Exception(public.lang("Missing certificate or private key file"))
self._restore_ssl(
backup_ssl=ssl,
pem=public.readFile(str(pem)),
key=public.readFile(str(key)),
)
ssl["restore_status"] = 2
self.replace_log(
log_str,
public.lang(f"Restored {ssl['info'].get('issuer_O')} Subject: {ssl['subject']}"),
"restore"
)
except Exception as e:
err_msg = public.lang(
f"Restoring {ssl['info'].get('issuer_O', '')} Subject: {ssl['subject']} failed: {str(e)}"
)
ssl["restore_status"] = 3
ssl["msg"] = str(e)
self.replace_log(log_str, err_msg, "restore")
self.update_restore_data_list(timestamp, restore_data)
# ======================= dns provider =============================
for provider in ssl_info.get("provider_list", []):
log_str = public.lang(f"Restoring DNS API {provider['name']}: {provider['alias']}...")
try:
self.print_log(log_str, "restore")
self._restore_provider(provider)
time.sleep(1)
provider["restore_status"] = 2
self.replace_log(
log_str,
public.lang(f"Restored DNS API {provider['name']}: {provider['alias']}"),
"restore"
)
except Exception as e:
err_msg = public.lang(f"Restoring DNS API provider: {provider['name']} failed: {str(e)}")
provider["restore_status"] = 3
provider["msg"] = str(e)
self.replace_log(log_str, err_msg, "restore")
self.update_restore_data_list(timestamp, restore_data)
self.update_restore_data_list(timestamp, restore_data)
self.print_log(public.lang("SSL certificate information restoration completed"), "restore")
if __name__ == '__main__':
if len(sys.argv) < 3:
print("Usage: btpython backup_manager.py <method> <timestamp>")
sys.exit(1)
method_name = sys.argv[1]
timestamp = sys.argv[2]
database_module = SSLModel()
if hasattr(database_module, method_name):
method = getattr(database_module, method_name)
method(timestamp)
else:
print(f"Error: method '{method_name}' not found")