use anyhow::{Context, Result}; use log::{error, info, warn}; use std::collections::HashMap; // --- 애플리케이션 모듈 선언 --- mod config_reader; mod db; // 데이터베이스 관련 모듈 (connection, compare, sync 포함) mod file; // 파일 처리 관련 모듈 (json_reader, decrypt 포함) mod logger; // --- 필요한 구조체 및 함수 임포트 --- use config_reader::read_app_config; use db::{ compare::{compare_data, ComparisonResult}, // 데이터 비교 함수 및 결과 구조체 connection::connect_db, // DB 연결 함수 sync::execute_sync, // DB 동기화 실행 함수 }; use file::{ decrypt::decrypt_db_config, // DB 설정 복호화 함수 json_reader::{read_and_process_json_files, ProcessedHwInfo}, // JSON 처리 함수 및 구조체 }; use logger::setup_logger; // 로거 설정 함수 // --- 애플리케이션 메인 진입점 --- #[tokio::main] async fn main() -> Result<()> { // .env 파일 로드 (환경 변수 사용 위함, 예: 복호화 키) dotenvy::dotenv().ok(); // 파일 없어도 오류 아님 // 1. 로거 초기화 setup_logger().context("로거 설정 실패")?; info!("자원 관리 동기화 애플리케이션 시작..."); info!("환경 변수 로드 시도 완료."); // 실제 로드 여부는 dotenvy 결과 확인 필요 // 2. 애플리케이션 설정 파일 읽기 let config_path = "config/config.json"; // 설정 파일 경로 info!("설정 파일 읽기 시도: {}", config_path); let app_config = read_app_config(config_path).context("애플리케이션 설정 읽기 실패")?; info!("설정 로드 완료: JSON 경로='{}', DB 설정 파일='{}'", app_config.json_files_path, app_config.db_config_path); // 3. DB 인증 정보 복호화 info!("DB 설정 파일 복호화 시도: {}", app_config.db_config_path); let db_creds = decrypt_db_config(&app_config.db_config_path).context("DB 인증 정보 복호화 실패")?; info!("DB 설정 복호화 완료."); // 성공 로그 (민감 정보 노출 주의) // 4. 데이터베이스 연결 풀 생성 info!("데이터베이스 연결 시도: 호스트={}, DB={}", db_creds.host, db_creds.db); let db_pool = connect_db(&db_creds).await.context("데이터베이스 연결 풀 생성 실패")?; info!("데이터베이스 연결 풀 생성 완료."); // 5. JSON 파일 읽기 및 처리 let processed_data: HashMap> = match read_and_process_json_files(&app_config.json_files_path) { Ok(data) => data, Err(e) => { // JSON 처리 실패 시 즉시 종료 error!("JSON 파일 처리 실패: {}", e); return Err(e.context("JSON 파일 처리 중 치명적 오류 발생")); } }; // 처리할 데이터가 없는 경우 종료 if processed_data.is_empty() { warn!("처리할 유효한 JSON 데이터 없음. 종료."); return Ok(()); } info!("총 {}개 호스트 데이터 처리 완료.", processed_data.len()); // 6. 데이터 비교 (JSON vs DB) let comparison_results: HashMap = match compare_data(&db_pool, &processed_data).await { Ok(results) => results, Err(e) => { // 데이터 비교 실패 시 즉시 종료 error!("데이터 비교 실패: {}", e); return Err(e.context("데이터 비교 중 치명적 오류 발생")); } }; // 변경 사항 없는 경우 종료 if comparison_results.is_empty() { info!("DB와 비교 결과, 변경 사항 없음. 종료."); return Ok(()); } info!("총 {}개 호스트 변경 사항 발견.", comparison_results.len()); // 7. DB 동기화 실행 (추가/할당, 할당 해제) info!("DB 동기화 작업 시작..."); let mut success_count = 0; let mut fail_count = 0; let total_hosts_to_sync = comparison_results.len(); // 각 호스트별 변경 사항 DB에 적용 for (hostname, changes) in comparison_results { info!("'{}' 호스트 DB 동기화 처리 중...", hostname); match execute_sync( &db_pool, &hostname, changes.adds, // 추가/할당 대상 전달 changes.deletes // 할당 해제 대상 전달 ).await { Ok(_) => { // 성공 시 카운트 증가 success_count += 1; info!("'{}' 호스트 DB 동기화 성공.", hostname); } Err(e) => { // 실패 시 카운트 증가 및 에러 로그 fail_count += 1; error!("'{}' 호스트 DB 동기화 에러: {}", hostname, e); // 개별 호스트 실패 시 전체 프로세스를 중단할지, 아니면 계속 진행할지 결정 // 여기서는 계속 진행하고 마지막에 요약 } } } // 8. 최종 결과 요약 로깅 info!("--- DB 동기화 작업 요약 ---"); info!("총 대상 호스트: {}", total_hosts_to_sync); info!("성공 처리 호스트: {}", success_count); info!("오류 발생 호스트: {}", fail_count); if fail_count > 0 { // 실패한 호스트가 있으면 에러 레벨 로그 추가 error!("일부 호스트 동기화 중 오류 발생. 상세 내용은 위 로그 확인 필요."); } info!("자원 관리 동기화 애플리케이션 정상 종료."); Ok(()) }