update
This commit is contained in:
@@ -120,6 +120,63 @@ def move_guid_files():
|
|||||||
|
|
||||||
return redirect(url_for("main.index"))
|
return redirect(url_for("main.index"))
|
||||||
|
|
||||||
|
@utils_bp.route("/move_gpu_files", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def move_gpu_files():
|
||||||
|
"""
|
||||||
|
data/idrac_info → data/gpu_serial 로 GPU 시리얼 텍스트 파일 이동
|
||||||
|
"""
|
||||||
|
src = Path(Config.IDRAC_INFO_FOLDER) # 예: data/idrac_info
|
||||||
|
dst = Path(Config.GPU_FOLDER) # 예: data/gpu_serial
|
||||||
|
dst.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
moved = 0
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
for file in src.iterdir():
|
||||||
|
if not file.is_file():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# GPU 관련 텍스트 파일만 이동 (GUID 등 제외)
|
||||||
|
if not file.name.lower().endswith(".txt"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 파일 존재 확인
|
||||||
|
if not file.exists():
|
||||||
|
errors.append(f"{file.name}: 파일이 존재하지 않음")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 대상 파일이 이미 존재하면 스킵
|
||||||
|
target = dst / file.name
|
||||||
|
if target.exists():
|
||||||
|
logging.warning(f"⚠️ 이미 존재하여 건너뜀: {file.name}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 파일 이동
|
||||||
|
shutil.move(str(file), str(target))
|
||||||
|
moved += 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"{file.name}: {str(e)}"
|
||||||
|
errors.append(error_msg)
|
||||||
|
logging.error(f"❌ GPU 파일 이동 실패: {error_msg}")
|
||||||
|
|
||||||
|
# 결과 메시지
|
||||||
|
if moved > 0:
|
||||||
|
flash(f"GPU 시리얼 파일이 성공적으로 이동되었습니다. ({moved}개)", "success")
|
||||||
|
logging.info(f"✅ GPU 파일 이동 완료 ({moved}개)")
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
logging.warning(f"⚠️ 일부 파일 이동 실패: {errors}")
|
||||||
|
flash(f"일부 GPU 파일 이동 실패: {len(errors)}개", "warning")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"❌ GPU 이동 오류: {e}")
|
||||||
|
flash(f"오류 발생: {e}", "danger")
|
||||||
|
|
||||||
|
return redirect(url_for("main.index"))
|
||||||
|
|
||||||
@utils_bp.route("/update_server_list", methods=["POST"])
|
@utils_bp.route("/update_server_list", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
@@ -182,6 +239,56 @@ def update_guid_list():
|
|||||||
|
|
||||||
return redirect(url_for("main.index"))
|
return redirect(url_for("main.index"))
|
||||||
|
|
||||||
|
@utils_bp.route("/update_gpu_list", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def update_gpu_list():
|
||||||
|
"""
|
||||||
|
GPU 시리얼용 리스트(gpu_serial_list.txt)를 갱신하고 Excel을 생성합니다.
|
||||||
|
- form name="gpu_list_content" 로 내용 전달 (S/T 목록 라인별)
|
||||||
|
- txt_to_excel.py --preset gpu --list-file <gpu_serial_list.txt>
|
||||||
|
"""
|
||||||
|
content = request.form.get("server_list_content")
|
||||||
|
if not content:
|
||||||
|
flash("내용을 입력하세요.", "warning")
|
||||||
|
return redirect(url_for("main.index"))
|
||||||
|
|
||||||
|
server_list_dir = Path(Config.SERVER_LIST_FOLDER)
|
||||||
|
list_path = server_list_dir / "gpu_list.txt"
|
||||||
|
# txt_to_excel.py는 server_list 폴더에 둔다고 가정 (위치 다르면 경로만 수정)
|
||||||
|
script_path = server_list_dir / "GPUTOExecl.py"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1) gpu_serial_list.txt 저장
|
||||||
|
list_path.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
|
# 2) 엑셀 생성 실행 (GPU 프리셋)
|
||||||
|
cmd = [
|
||||||
|
sys.executable,
|
||||||
|
str(script_path),
|
||||||
|
"--preset", "gpu",
|
||||||
|
"--list-file", str(list_path),
|
||||||
|
]
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True,
|
||||||
|
cwd=str(server_list_dir), # data/server_list 기준 실행
|
||||||
|
timeout=300,
|
||||||
|
)
|
||||||
|
logging.info(f"[GPU] 리스트 스크립트 실행 STDOUT:\n{result.stdout}")
|
||||||
|
if result.stderr:
|
||||||
|
logging.warning(f"[GPU] 리스트 스크립트 STDERR:\n{result.stderr}")
|
||||||
|
|
||||||
|
flash("GPU 리스트가 업데이트되었습니다.", "success")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
logging.error(f"[GPU] 스크립트 오류: {e.stderr}")
|
||||||
|
flash(f"스크립트 실행 실패: {e.stderr}", "danger")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"[GPU] 처리 오류: {e}")
|
||||||
|
flash(f"GPU 리스트 처리 중 오류 발생: {e}", "danger")
|
||||||
|
|
||||||
|
return redirect(url_for("main.index"))
|
||||||
|
|
||||||
@utils_bp.route("/download_excel")
|
@utils_bp.route("/download_excel")
|
||||||
@login_required
|
@login_required
|
||||||
@@ -192,4 +299,4 @@ def download_excel():
|
|||||||
return redirect(url_for("main.index"))
|
return redirect(url_for("main.index"))
|
||||||
|
|
||||||
logging.info(f"엑셀 파일 다운로드: {path}")
|
logging.info(f"엑셀 파일 다운로드: {path}")
|
||||||
return send_file(str(path), as_attachment=True, download_name="mac_info.xlsx")
|
return send_file(str(path), as_attachment=True, download_name="mac_info.xlsx")
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
{# 플래시 메시지 #}
|
{# 플래시 메시지 #}
|
||||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
<div class="position-fixed top-0 end-0 p-3" style="z-index: 11">
|
<div class="position-fixed top-0 end-0 p-3" style="z-index: 1050">
|
||||||
{% for cat, msg in messages %}
|
{% for cat, msg in messages %}
|
||||||
<div class="alert alert-{{ cat }} alert-dismissible fade show shadow-lg" role="alert">
|
<div class="alert alert-{{ cat }} alert-dismissible fade show shadow-lg" role="alert">
|
||||||
<i class="bi bi-{{ 'check-circle' if cat == 'success' else 'exclamation-triangle' }} me-2"></i>
|
<i class="bi bi-{{ 'check-circle' if cat == 'success' else 'exclamation-triangle' }} me-2"></i>
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="ips" class="form-label">
|
<label for="ips" class="form-label">
|
||||||
IP 주소 (각 줄에 하나)
|
IP 주소 (각 줄에 하나)
|
||||||
<span class="badge bg-secondary ms-2" id="ipLineCount">0줄</span>
|
<span class="badge bg-secondary ms-2" id="ipLineCount">0 대설정</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea id="ips" name="ips" rows="4" class="form-control font-monospace"
|
<textarea id="ips" name="ips" rows="4" class="form-control font-monospace"
|
||||||
placeholder="예: 192.168.1.1 192.168.1.2 192.168.1.3" required></textarea>
|
placeholder="예: 192.168.1.1 192.168.1.2 192.168.1.3" required></textarea>
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="server_list_content" class="form-label">
|
<label for="server_list_content" class="form-label">
|
||||||
서버 리스트 (덮어쓰기)
|
서버 리스트 (덮어쓰기)
|
||||||
<span class="badge bg-secondary ms-2" id="serverLineCount">0줄</span>
|
<span class="badge bg-secondary ms-2" id="serverLineCount">0 대설정</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea id="server_list_content" name="server_list_content" rows="8"
|
<textarea id="server_list_content" name="server_list_content" rows="8"
|
||||||
class="form-control font-monospace" style="font-size: 0.95rem;"
|
class="form-control font-monospace" style="font-size: 0.95rem;"
|
||||||
@@ -116,6 +116,11 @@
|
|||||||
class="btn btn-success">
|
class="btn btn-success">
|
||||||
GUID to Excel
|
GUID to Excel
|
||||||
</button>
|
</button>
|
||||||
|
<button type="submit" formaction="{{ url_for('utils.update_gpu_list') }}"
|
||||||
|
class="btn btn-success">
|
||||||
|
GPU to Excel
|
||||||
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -143,75 +148,78 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# 파일 관리 도구 #}
|
{# 파일 관리 도구 #}
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card border shadow-sm">
|
<div class="card border shadow-sm">
|
||||||
<div class="card-header bg-light border-0 py-2">
|
<div class="card-header bg-light border-0 py-2">
|
||||||
<h6 class="mb-0">
|
<h6 class="mb-0">
|
||||||
<i class="bi bi-tools me-2"></i>
|
<i class="bi bi-tools me-2"></i>
|
||||||
파일 관리 도구
|
파일 관리 도구
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-4">
|
|
||||||
<div class="row g-3">
|
|
||||||
{# ZIP 다운로드 #}
|
|
||||||
<div class="col-md-6 col-xl-3">
|
|
||||||
<label class="form-label">ZIP 다운로드</label>
|
|
||||||
<form method="post" action="{{ url_for('main.download_zip') }}">
|
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" name="zip_filename"
|
|
||||||
placeholder="파일명" required>
|
|
||||||
<button class="btn btn-primary" type="submit">
|
|
||||||
다운로드
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# 파일 백업 #}
|
<div class="card-body p-4 file-tools">
|
||||||
<div class="col-md-6 col-xl-3">
|
|
||||||
<label class="form-label">파일 백업</label>
|
|
||||||
<form method="post" action="{{ url_for('main.backup_files') }}">
|
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" name="backup_prefix"
|
|
||||||
placeholder="PO로 시작">
|
|
||||||
<button class="btn btn-success" type="submit">
|
|
||||||
백업
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# MAC 파일 이동 #}
|
<!-- 한 줄로 정렬: 화면이 넓을 때 5등분 / 좁아지면 자동 줄바꿈 -->
|
||||||
<div class="col-md-6 col-xl-3">
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xxl-5 g-3 align-items-end">
|
||||||
<label class="form-label">MAC 파일 이동</label>
|
|
||||||
<form id="macMoveForm" method="post" action="{{ url_for('utils.move_mac_files') }}">
|
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
||||||
<button class="btn btn-warning w-100" type="submit">
|
|
||||||
MAC Move
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# GUID 파일 이동 #}
|
<!-- ZIP 다운로드 -->
|
||||||
<div class="col-md-6 col-xl-3">
|
<div class="col">
|
||||||
<label class="form-label">GUID 파일 이동</label>
|
<label class="form-label text-nowrap">ZIP 다운로드</label>
|
||||||
<form id="guidMoveForm" method="post" action="{{ url_for('utils.move_guid_files') }}">
|
<form method="post" action="{{ url_for('main.download_zip') }}">
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
<button class="btn btn-info w-100" type="submit">
|
<div class="input-group">
|
||||||
GUID Move
|
<input type="text" class="form-control" name="zip_filename" placeholder="파일명" required>
|
||||||
</button>
|
<button class="btn btn-primary" type="submit">다운로드</button>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 파일 백업 -->
|
||||||
|
<div class="col">
|
||||||
|
<label class="form-label text-nowrap">파일 백업</label>
|
||||||
|
<form method="post" action="{{ url_for('main.backup_files') }}">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" name="backup_prefix" placeholder="PO로 시작">
|
||||||
|
<button class="btn btn-success" type="submit">백업</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- MAC 파일 이동 -->
|
||||||
|
<div class="col">
|
||||||
|
<label class="form-label text-nowrap">MAC 파일 이동</label>
|
||||||
|
<form id="macMoveForm" method="post" action="{{ url_for('utils.move_mac_files') }}">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<button class="btn btn-warning w-100" type="submit">MAC Move</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GUID 파일 이동 -->
|
||||||
|
<div class="col">
|
||||||
|
<label class="form-label text-nowrap">GUID 파일 이동</label>
|
||||||
|
<form id="guidMoveForm" method="post" action="{{ url_for('utils.move_guid_files') }}">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<button class="btn btn-info w-100" type="submit">GUID Move</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GPU 파일 이동 -->
|
||||||
|
<div class="col">
|
||||||
|
<label class="form-label text-nowrap">GPU 파일 이동</label>
|
||||||
|
<form id="gpuMoveForm" method="post" action="{{ url_for('utils.move_gpu_files') }}">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<button class="btn btn-info w-100" type="submit">GPU Move</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{# 처리된 파일 목록 - 목록별 버튼 스타일 분리 (processed-list) #}
|
{# 처리된 파일 목록 - 목록별 버튼 스타일 분리 (processed-list) #}
|
||||||
<div class="row mb-4 processed-list">
|
<div class="row mb-4 processed-list">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
|||||||
Reference in New Issue
Block a user