import os
import glob
import re
import sys
import argparse
import pandas as pd
import numpy as np
def main():
print("🚀 [Step6 개시] res_usage_ 계열 고도화 엑셀 리포터 엔진 가동...")
parser = argparse.ArgumentParser(description="Step6 리소스 정산 엑셀 마스터 빌더")
parser.add_argument(
"--cluster",
type=str,
choices=["COMPUTE", "STORAGE", "compute", "storage"],
help="대상 클러스터 컨텍스트 명시 (COMPUTE 또는 STORAGE)"
)
args = parser.parse_args()
cluster_mode = args.cluster or os.getenv("CLUSTER_MODE", "")
cluster_mode = cluster_mode.upper()
if cluster_mode:
print(f"🎯 클러스터 Argument/컨텍스트 고정 완료: [merged/{cluster_mode}/]")
search_pattern = str(MERGED_DIR / cluster_mode / f"pareto_ns_{cluster_mode}_*.parquet")
else:
print("🔍 클러스터 미지정: merged/ 하위 모든 클러스터 서브폴더(*)를 자동 순회 탐색합니다.")
search_pattern = str(MERGED_DIR / "*" / "pareto_ns_*.parquet")
pareto_files = glob.glob(search_pattern)
if not pareto_files:
print(f"❌ 오류: 탐색된 파레토 가공원부(*.parquet) 파일이 없습니다. 타겟 경로를 확인하세요: {search_pattern}")
return
processed_count = 0
for file_path in pareto_files:
filename = os.path.basename(file_path)
match = re.search(r"pareto_ns_(.*)_(.*)\.parquet", filename)
if not match:
continue
infra_tag = match.group(1)
date_tag = match.group(2)
p1 = MERGED_DIR / infra_tag / f"daily_enriched_{infra_tag}_{date_tag}.parquet"
p2 = Path(file_path)
p3 = MERGED_DIR / infra_tag / f"daily_ns_usage_{infra_tag}_{date_tag}.parquet"
if not (p1.exists() and p3.exists()):
print(f"⚠️ [세트 불완전] merged/{infra_tag}/ 하위에 쌍이 되는 가공 데이터가 유실되어 작업을 건너뜁니다.")
continue
print(f"\n" + "="*60)
print(f"🔄 [서브폴더 파티션 검증 완료] Cluster: {infra_tag} | Date: {date_tag} 컴파일 가동")
print("="*60)
df_pod = pd.read_parquet(p1)
df_ns = pd.read_parquet(p2)
df_daily_ns = pd.read_parquet(p3)
excel_name = f"res_usage_report_{infra_tag.lower()}_{date_tag}.xlsx"
wb = Workbook()
build_sheet_summary(wb, df_pod, df_ns, infra_tag)
build_sheet_pareto(wb, df_ns, infra_tag)
build_sheet_ns_daily(wb, df_daily_ns, infra_tag)
build_sheet_cpu(wb, df_pod, infra_tag)
build_sheet_memory(wb, df_pod, infra_tag)
build_sheet_oom(wb, df_pod, infra_tag)
build_sheet_violations(wb, df_pod, infra_tag)
build_sheet_trends(wb, df_pod, infra_tag)
build_sheet_workload(wb, df_pod, infra_tag)
build_sheet_extra_charts(wb, infra_tag, date_tag)
out_path = OUT_DIR / excel_name
print(f"💾 openpyxl 스트림 디스크 저장 가동 중... ➡️ {out_path}")
wb.save(out_path)
print(f"📦 [로컬 컴파일 마감 완료]: {excel_name} ({out_path.stat().st_size/1024:.0f} KB)")
minio_endpoint = os.getenv("MINIO_ENDPOINT")
minio_access_key = os.getenv("MINIO_ACCESS_KEY")
minio_secret_key = os.getenv("MINIO_SECRET_KEY")
bucket_name = os.getenv("MINIO_REPORT_BUCKET", "devops-test")
if all([minio_endpoint, minio_access_key, minio_secret_key]):
try:
endpoint_clean = minio_endpoint.replace("http://", "").replace("https://", "")
secure_flag = minio_endpoint.startswith("https://")
minio_client = Minio(
endpoint_clean,
access_key=minio_access_key,
secret_key=minio_secret_key,
secure=secure_flag
)
if not minio_client.bucket_exists(bucket_name):
minio_client.make_bucket(bucket_name)
object_key = f"reports/{infra_tag.lower()}/{excel_name}"
print(f"🪣 [오브젝트 스토리지 싱크] devops-test 버킷 배포 ➡️ MinIO://{object_key} 업로드 중...")
minio_client.fput_file(bucket_name, object_key, str(out_path))
print("🏁 === [전사 배포 마감 성공] 고도화 res_usage_ 마스터 엑셀 리포트 배포 자산화 완료 ===")
except Exception as e:
print(f"❌ [배포 에러] 사내 MinIO 원격 업로드 중 예외 발생: {str(e)}")
else:
print("⚠️ [안내] 접속 환경변수 생략으로 로컬 아카이빙 처리 후 해당 파티션을 마감합니다.")
processed_count += 1
print(f"\n🏁 === [전체 자동 매칭 빌드 완료] 총 {processed_count}개 세트 인프라 마스터 리포트 빌드 프로세스가 종결되었습니다. ===")