from flask import Blueprint, render_template, request, jsonify, flash, redirect, url_for from flask_login import login_required, current_user import logging import difflib from pathlib import Path from config import Config from backend.services.redfish_client import RedfishClient from backend.routes.xml import sanitize_preserve_unicode scp_bp = Blueprint("scp", __name__) logger = logging.getLogger(__name__) @scp_bp.route("/scp/diff", methods=["GET"]) @login_required def diff_scp(): """ 두 XML 파일의 차이점을 비교하여 보여줍니다. """ file1_name = request.args.get("file1") file2_name = request.args.get("file2") if not file1_name or not file2_name: flash("비교할 두 파일을 선택해주세요.", "warning") return redirect(url_for("xml.xml_management")) try: file1_path = Path(Config.XML_FOLDER) / sanitize_preserve_unicode(file1_name) file2_path = Path(Config.XML_FOLDER) / sanitize_preserve_unicode(file2_name) if not file1_path.exists() or not file2_path.exists(): flash("파일을 찾을 수 없습니다.", "danger") return redirect(url_for("xml.xml_management")) # 파일 내용 읽기 (LF로 통일) # 파일 내용 읽기 (LF로 통일) # Monaco Editor에 원본 텍스트를 그대로 전달하기 위해 splitlines() 제거 # 파일 내용 읽기 (LF로 통일) logger.info(f"Reading file1: {file1_path}") content1 = file1_path.read_text(encoding="utf-8", errors="replace").replace("\r\n", "\n") logger.info(f"Reading file2: {file2_path}") content2 = file2_path.read_text(encoding="utf-8", errors="replace").replace("\r\n", "\n") logger.info(f"Content1 length: {len(content1)}, Content2 length: {len(content2)}") return render_template("scp_diff.html", file1=file1_name, file2=file2_name, content1=content1, content2=content2) except Exception as e: logger.error(f"Diff error: {e}") flash(f"비교 중 오류가 발생했습니다: {str(e)}", "danger") return redirect(url_for("xml.xml_management")) @scp_bp.route("/scp/content/") @login_required def get_scp_content(filename): """ XML 파일 내용을 반환하는 API (Monaco Editor용) """ try: safe_name = sanitize_preserve_unicode(filename) path = Path(Config.XML_FOLDER) / safe_name if not path.exists(): return "File not found", 404 # 텍스트로 읽어서 반환 content = path.read_text(encoding="utf-8", errors="replace").replace("\r\n", "\n") return content, 200, {'Content-Type': 'text/plain; charset=utf-8'} except Exception as e: logger.error(f"Content read error: {e}") return str(e), 500 @scp_bp.route("/scp/export", methods=["POST"]) @login_required def export_scp(): """ iDRAC에서 설정을 내보내기 (Export) 네트워크 공유 설정이 필요합니다. """ data = request.form target_ip = data.get("target_ip") username = data.get("username") password = data.get("password") # Share Parameters share_ip = data.get("share_ip") share_name = data.get("share_name") share_user = data.get("share_user") share_pwd = data.get("share_pwd") filename = data.get("filename") if not all([target_ip, username, password, share_ip, share_name, filename]): flash("필수 정보가 누락되었습니다.", "warning") return redirect(url_for("xml.xml_management")) share_params = { "IPAddress": share_ip, "ShareName": share_name, "FileName": filename, "ShareType": "CIFS", # 기본값 CIFS "UserName": share_user, "Password": share_pwd } try: with RedfishClient(target_ip, username, password) as client: job_id = client.export_system_configuration(share_params) if job_id: flash(f"내보내기 작업이 시작되었습니다. Job ID: {job_id}", "success") else: flash("작업을 시작했으나 Job ID를 받지 못했습니다.", "warning") except Exception as e: logger.error(f"Export failed: {e}") flash(f"내보내기 실패: {str(e)}", "danger") return redirect(url_for("xml.xml_management")) @scp_bp.route("/scp/import", methods=["POST"]) @login_required def import_scp(): """ iDRAC로 설정 가져오기 (Import/Deploy) """ data = request.form target_ip = data.get("target_ip") username = data.get("username") password = data.get("password") # Share Parameters share_ip = data.get("share_ip") share_name = data.get("share_name") share_user = data.get("share_user") share_pwd = data.get("share_pwd") filename = data.get("filename") import_mode = data.get("import_mode", "Replace") if not all([target_ip, username, password, share_ip, share_name, filename]): flash("필수 정보가 누락되었습니다.", "warning") return redirect(url_for("xml.xml_management")) share_params = { "IPAddress": share_ip, "ShareName": share_name, "FileName": filename, "ShareType": "CIFS", "UserName": share_user, "Password": share_pwd } try: with RedfishClient(target_ip, username, password) as client: job_id = client.import_system_configuration(share_params, import_mode=import_mode) if job_id: flash(f"설정 적용(Import) 작업이 시작되었습니다. Job ID: {job_id}", "success") else: flash("작업을 시작했으나 Job ID를 받지 못했습니다.", "warning") except Exception as e: logger.error(f"Import failed: {e}") flash(f"설정 적용 실패: {str(e)}", "danger") return redirect(url_for("xml.xml_management"))