diff --git a/scripts/db_sync.py b/scripts/db_sync.py new file mode 100644 index 0000000..0a46d2c --- /dev/null +++ b/scripts/db_sync.py @@ -0,0 +1,134 @@ +import subprocess +import os +import datetime +import sys + +from db.mongo_manager import MONGO_DB_URL + +# ================= 配置区域 ================= +# 数据库连接信息 +MONGO_HOST = "mongo.lpaconsulting.fr" +MONGO_PORT = "27017" +MONGO_DB_NAME = "appointment" # 你要备份/恢复的数据库名 +MONGO_USER = "appointment" # 如果没有密码,保持为空字符串 "" +MONGO_PASS = "Rdv@2022" # 如果没有密码,保持为空字符串 "" + +# 备份存放的根目录 +BACKUP_DIR_ROOT = "./mongo_backups" + +# =========================================== + +def get_auth_args(): + """构建认证参数列表""" + args = [] + if MONGO_USER and MONGO_PASS: + args.extend(["--username", MONGO_USER, "--password", MONGO_PASS, "--authenticationDatabase", "appointment"]) + return args + +def backup_mongo(): + """执行备份操作""" + # 1. 创建带有时间戳的备份文件夹 + timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + backup_path = os.path.join(BACKUP_DIR_ROOT, timestamp) + + if not os.path.exists(backup_path): + os.makedirs(backup_path) + + print(f"[*] 开始备份数据库: {MONGO_DB_NAME} 到 {backup_path} ...") + + # 2. 构建 mongodump 命令 + # 命令格式: mongodump --host --port --db --out [auth] + cmd = [ + "mongodump", + "--host", MONGO_HOST, + "--port", MONGO_PORT, + "--db", MONGO_DB_NAME, + "--out", backup_path + ] + + # 添加认证参数 + cmd.extend(get_auth_args()) + + try: + # 3. 执行命令 + result = subprocess.run(cmd, check=True, text=True, capture_output=True) + print(f"[+] 备份成功!") + print(f" 存储路径: {backup_path}") + print(f" 日志: {result.stderr}") # mongodump 通常把进度输出到 stderr + return backup_path + except subprocess.CalledProcessError as e: + print(f"[-] 备份失败: {e}") + print(f" 错误信息: {e.stderr}") + return None + +def restore_mongo(backup_source_path): + """ + 执行恢复操作 + backup_source_path: 备份文件夹的路径 (例如 ./mongo_backups/2023-10-27_10-00-00) + """ + # mongodump 的输出结构通常是: backup_dir/db_name/collection.bson + # 所以我们需要指向具体的数据库文件夹,或者指向父文件夹并指定 --db + + target_dir = os.path.join(backup_source_path, MONGO_DB_NAME) + + if not os.path.exists(target_dir): + print(f"[-] 错误: 在路径 {backup_source_path} 下找不到数据库 {MONGO_DB_NAME} 的备份文件。") + return + + print(f"[*] 开始恢复数据库: {MONGO_DB_NAME} 从 {target_dir} ...") + + # 构建 mongorestore 命令 + # 命令格式: mongorestore --host --port --db [auth] + cmd = [ + "mongorestore", + "--host", MONGO_HOST, + "--port", MONGO_PORT, + "--db", MONGO_DB_NAME, + "--drop", # 警告:这会在恢复前删除现有集合,确保数据干净。根据需要移除此项。 + target_dir + ] + + cmd.extend(get_auth_args()) + + try: + result = subprocess.run(cmd, check=True, text=True, capture_output=True) + print(f"[+] 恢复成功!") + print(f" 日志: {result.stderr}") + except subprocess.CalledProcessError as e: + print(f"[-] 恢复失败: {e}") + print(f" 错误信息: {e.stderr}") + +# ================= 主程序入口 ================= +if __name__ == "__main__": + print("请选择操作:") + print("1. 备份数据库 (Backup)") + print("2. 恢复数据库 (Restore)") + + choice = input("请输入数字 (1/2): ").strip() + + if choice == "1": + backup_mongo() + elif choice == "2": + # 列出所有备份供用户选择 + if not os.path.exists(BACKUP_DIR_ROOT): + print("[-] 没有找到备份目录。") + else: + backups = sorted(os.listdir(BACKUP_DIR_ROOT)) + if not backups: + print("[-] 目录为空。") + else: + print("\n可用备份:") + for idx, name in enumerate(backups): + print(f"{idx + 1}. {name}") + + try: + idx_choice = int(input("\n请选择要恢复的备份编号: ")) - 1 + if 0 <= idx_choice < len(backups): + selected_backup = os.path.join(BACKUP_DIR_ROOT, backups[idx_choice]) + restore_mongo(selected_backup) + else: + print("[-] 无效的选择。") + except ValueError: + print("[-] 请输入数字。") + else: + print("[-] 无效输入,退出。") \ No newline at end of file