verify_migration2.sh

진웅·2025년 7월 22일

minIO

목록 보기
11/21
#!/bin/bash

# DistCp Migration 검증 스크립트 (랜덤 샘플링 기능 추가)
# 사용법: ./verify_migration.sh <folder_list_file> <source_base> <target_base> [sample_count]
# 특징: 오류가 발생해도 중단하지 않고 끝까지 수행

set +e  # 오류 발생 시에도 계속 진행

# 색상 정의
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 사용법 출력
usage() {
    echo "Usage: $0 <folder_list_file> <source_base> <target_base> [sample_count]"
    echo ""
    echo "예시:"
    echo "  $0 /tmp/distcp_folders.txt hdfs://hdfsf.com/a/b/c s3a://y/z"
    echo "  $0 /tmp/distcp_folders.txt hdfs://hdfsf.com/a/b/c s3a://y/z 50  # 랜덤 50개만 검증"
    echo ""
    echo "매개변수:"
    echo "  sample_count: 랜덤 샘플 개수 (생략시 전체 검증)"
    exit 1
}

# 매개변수 확인
if [ $# -lt 3 ]; then
    usage
fi

FOLDER_LIST_FILE="$1"
SOURCE_BASE="$2"
TARGET_BASE="$3"
SAMPLE_COUNT="$4"  # 선택적 매개변수

# 파일 존재 확인
if [ ! -f "$FOLDER_LIST_FILE" ]; then
    echo -e "${RED}❌ 폴더 목록 파일을 찾을 수 없습니다: $FOLDER_LIST_FILE${NC}"
    exit 1
fi

# 결과 변수 초기화
TOTAL_FOLDERS=0
MATCHED_FOLDERS=0
MISSING_TARGET_FOLDERS=0
MISSING_SOURCE_FOLDERS=0
COUNT_MISMATCH_FOLDERS=0
SIZE_MISMATCH_FOLDERS=0
ERROR_FOLDERS=0
SOURCE_TOTAL_SIZE=0
TARGET_TOTAL_SIZE=0

# 임시 파일 생성
TEMP_DIR="/tmp/distcp_verify_$$"
mkdir -p "$TEMP_DIR"

# 종료 시 정리
cleanup() {
    rm -rf "$TEMP_DIR"
}
trap cleanup EXIT

# 로그 파일
LOG_FILE="$TEMP_DIR/verification.log"
MISSING_LOG="$TEMP_DIR/missing_folders.log"
MISMATCH_LOG="$TEMP_DIR/mismatch_folders.log"
ERROR_LOG="$TEMP_DIR/error_folders.log"

# 파일 크기를 읽기 쉬운 형태로 변환
format_size() {
    local size=$1
    if [ $size -eq 0 ]; then
        echo "0 B"
        return
    fi
    
    local units=("B" "KB" "MB" "GB" "TB")
    local unit=0
    local formatted_size=$size
    
    while [ $formatted_size -ge 1024 ] && [ $unit -lt 4 ]; do
        formatted_size=$((formatted_size / 1024))
        unit=$((unit + 1))
    done
    
    echo "$formatted_size ${units[$unit]}"
}

# 폴더 정보 가져오기 (파일 개수, 총 크기) - 오류 처리 강화
get_folder_info() {
    local folder_path="$1"
    local info_file="$2"
    
    # 초기값 설정
    echo "exists=false" > "$info_file"
    echo "file_count=0" >> "$info_file"
    echo "total_size=0" >> "$info_file"
    
    # hadoop fs -ls -R 실행 (타임아웃 적용)
    if timeout 60 hadoop fs -ls -R "$folder_path" 2>/dev/null | grep "^-" > "$info_file.tmp" 2>/dev/null; then
        # 파일이 있는지 확인
        if [ -s "$info_file.tmp" ]; then
            # 파일 개수
            local file_count=$(wc -l < "$info_file.tmp" 2>/dev/null || echo "0")
            
            # 총 크기 계산 (awk로 더 빠르게) - 오류 처리 추가
            local total_size=$(awk '{sum += $5} END {print sum+0}' "$info_file.tmp" 2>/dev/null || echo "0")
            
            # 결과 저장
            echo "exists=true" > "$info_file"
            echo "file_count=$file_count" >> "$info_file"
            echo "total_size=$total_size" >> "$info_file"
            
            rm -f "$info_file.tmp" 2>/dev/null
            return 0
        fi
    fi
    
    # 실패한 경우 임시 파일 정리
    rm -f "$info_file.tmp" 2>/dev/null
    return 1
}

# xxx 추출 함수
extract_xxx() {
    local full_path="$1"
    echo "${full_path##*/}"
}

# 타겟 경로 생성
build_target_path() {
    local xxx="$1"
    echo "${TARGET_BASE%/}/$xxx"
}

# 랜덤 샘플링 함수
sample_folders() {
    local input_array=("$@")
    local total_count=${#input_array[@]}
    
    if [ -z "$SAMPLE_COUNT" ] || [ "$SAMPLE_COUNT" -ge "$total_count" ]; then
        # 샘플링 없이 전체 사용
        echo "${input_array[@]}"
        return
    fi
    
    echo -e "${YELLOW}전체 ${total_count}개 폴더 중 랜덤 ${SAMPLE_COUNT}개 선택${NC}"
    
    # 랜덤 인덱스 생성
    local indices=()
    for ((i=0; i<total_count; i++)); do
        indices+=($i)
    done
    
    # Fisher-Yates 셔플 알고리즘
    for ((i=total_count-1; i>0; i--)); do
        local j=$((RANDOM % (i+1)))
        local temp=${indices[$i]}
        indices[$i]=${indices[$j]}
        indices[$j]=$temp
    done
    
    # 선택된 폴더들 반환
    local selected_folders=()
    for ((i=0; i<SAMPLE_COUNT; i++)); do
        local idx=${indices[$i]}
        selected_folders+=("${input_array[$idx]}")
    done
    
    echo "${selected_folders[@]}"
}

# 단일 폴더 검증
verify_folder() {
    local source_folder="$1"
    local xxx=$(extract_xxx "$source_folder")
    local target_folder=$(build_target_path "$xxx")
    
    local source_info="$TEMP_DIR/source_$xxx.info"
    local target_info="$TEMP_DIR/target_$xxx.info"
    
    # 소스 폴더 정보 가져오기
    if ! get_folder_info "$source_folder" "$source_info"; then
        echo -e "${RED}❌ $xxx: 소스 폴더가 존재하지 않습니다${NC}"
        echo "$xxx|missing_source|$source_folder|$target_folder|소스 폴더가 존재하지 않습니다" >> "$ERROR_LOG"
        return 1
    fi
    
    # 타겟 폴더 정보 가져오기
    if ! get_folder_info "$target_folder" "$target_info"; then
        echo -e "${RED}❌ $xxx: 타겟 폴더가 존재하지 않습니다${NC}"
        echo "$xxx|missing_target|$source_folder|$target_folder|타겟 폴더가 존재하지 않습니다" >> "$MISSING_LOG"
        return 2
    fi
    
    # 정보 읽기
    if [ ! -f "$source_info" ]; then
        echo -e "${RED}❌ $xxx: 소스 정보 파일 생성 실패${NC}"
        echo "$xxx|error|$source_folder|$target_folder|소스 정보 파일 생성 실패" >> "$ERROR_LOG"
        return 1
    fi
    
    source "$source_info"
    local source_count=$file_count
    local source_size=$total_size
    
    if [ ! -f "$target_info" ]; then
        echo -e "${RED}❌ $xxx: 타겟 정보 파일 생성 실패${NC}"
        echo "$xxx|error|$source_folder|$target_folder|타겟 정보 파일 생성 실패" >> "$ERROR_LOG"
        return 1
    fi
    
    source "$target_info"
    local target_count=$file_count
    local target_size=$total_size
    
    # 파일 개수 비교
    if [ $source_count -ne $target_count ]; then
        echo -e "${YELLOW}❌ $xxx: 파일 개수 불일치 (소스: $source_count, 타겟: $target_count)${NC}"
        echo "$xxx|count_mismatch|$source_folder|$target_folder|파일 개수 불일치: 소스($source_count) vs 타겟($target_count)" >> "$MISMATCH_LOG"
        return 3
    fi
    
    # 크기 비교
    if [ $source_size -ne $target_size ]; then
        echo -e "${YELLOW}❌ $xxx: 크기 불일치 (소스: $(format_size $source_size), 타겟: $(format_size $target_size))${NC}"
        echo "$xxx|size_mismatch|$source_folder|$target_folder|크기 불일치: 소스($source_size) vs 타겟($target_size)" >> "$MISMATCH_LOG"
        return 4
    fi
    
    # 성공
    echo -e "${GREEN}✅ $xxx: 정상 (${source_count}개 파일, $(format_size $source_size))${NC}"
    echo "$xxx|matched|$source_folder|$target_folder|정상" >> "$LOG_FILE"
    return 0
}

# 메인 검증 함수
main_verification() {
    echo -e "${BLUE}=== DistCp Migration 검증 시작 ===${NC}"
    echo "폴더 목록: $FOLDER_LIST_FILE"
    echo "소스 베이스: $SOURCE_BASE"
    echo "타겟 베이스: $TARGET_BASE"
    echo "검증 시작: $(date)"
    echo "=" * 50
    
    # 폴더 목록 읽기
    local all_folders=()
    while IFS= read -r line; do
        line=$(echo "$line" | tr -d '\r' | xargs)  # 공백 및 개행 제거
        if [ -n "$line" ] && [[ ! "$line" =~ ^# ]]; then
            all_folders+=("$line")
        fi
    done < "$FOLDER_LIST_FILE"
    
    local total_folders_in_file=${#all_folders[@]}
    echo "파일에서 읽은 전체 폴더 수: $total_folders_in_file"
    
    # 샘플링 적용
    local folder_list
    if [ -n "$SAMPLE_COUNT" ] && [ "$SAMPLE_COUNT" -lt "$total_folders_in_file" ]; then
        echo -e "${YELLOW}랜덤 샘플링: $SAMPLE_COUNT개 폴더 선택${NC}"
        IFS=' ' read -ra folder_list <<< "$(sample_folders "${all_folders[@]}")"
        
        # 선택된 폴더들을 로그에 저장
        printf '%s\n' "${folder_list[@]}" > "$TEMP_DIR/selected_folders.txt"
        echo "선택된 폴더 목록이 저장됨: $TEMP_DIR/selected_folders.txt"
    else
        echo "전체 폴더 검증 수행"
        folder_list=("${all_folders[@]}")
    fi
    
    TOTAL_FOLDERS=${#folder_list[@]}
    echo "실제 검증 대상 폴더: $TOTAL_FOLDERS"
    echo
    
    # 처음 5개 폴더 미리보기
    echo "처음 5개 폴더 미리보기:"
    for i in $(seq 0 4); do
        if [ $i -lt ${#folder_list[@]} ]; then
            local source_folder="${folder_list[$i]}"
            local xxx=$(extract_xxx "$source_folder")
            echo "  $((i+1)). $xxx"
        fi
    done
    echo
    
    # 각 폴더 검증 (오류가 발생해도 계속 진행)
    local processed=0
    for source_folder in "${folder_list[@]}"; do
        local xxx=$(extract_xxx "$source_folder")
        
        # 폴더 검증 수행 (실패해도 계속 진행)
        verify_folder "$source_folder"
        local result=$?
        
        # 결과에 따른 카운터 증가 (모든 경우를 처리)
        case $result in
            0)  # 성공
                MATCHED_FOLDERS=$((MATCHED_FOLDERS + 1))
                ;;
            1)  # 소스 누락 또는 기타 오류
                if grep -q "missing_source" "$ERROR_LOG" 2>/dev/null && grep -q "$xxx" "$ERROR_LOG"; then
                    MISSING_SOURCE_FOLDERS=$((MISSING_SOURCE_FOLDERS + 1))
                else
                    ERROR_FOLDERS=$((ERROR_FOLDERS + 1))
                fi
                ;;
            2)  # 타겟 누락
                MISSING_TARGET_FOLDERS=$((MISSING_TARGET_FOLDERS + 1))
                ;;
            3)  # 개수 불일치
                COUNT_MISMATCH_FOLDERS=$((COUNT_MISMATCH_FOLDERS + 1))
                ;;
            4)  # 크기 불일치
                SIZE_MISMATCH_FOLDERS=$((SIZE_MISMATCH_FOLDERS + 1))
                ;;
            *)  # 기타 오류
                ERROR_FOLDERS=$((ERROR_FOLDERS + 1))
                ;;
        esac
        
        processed=$((processed + 1))
        
        # 진행률 표시 (10개마다)
        if [ $((processed % 10)) -eq 0 ] || [ $processed -eq $TOTAL_FOLDERS ]; then
            local progress=$((processed * 100 / TOTAL_FOLDERS))
            echo -e "${BLUE}진행률: $processed/$TOTAL_FOLDERS ($progress%) - 성공: $MATCHED_FOLDERS, 타겟누락: $MISSING_TARGET_FOLDERS, 개수불일치: $COUNT_MISMATCH_FOLDERS, 크기불일치: $SIZE_MISMATCH_FOLDERS, 오류: $ERROR_FOLDERS${NC}"
        fi
        
        # 잠깐 대기 (시스템 부하 감소)
        sleep 0.1
    done
    
    echo ""
    echo -e "${GREEN}모든 폴더 검증 완료!${NC}"
    echo "처리된 폴더: $processed / $TOTAL_FOLDERS"
}

# 결과 보고서 생성
generate_report() {
    local success_rate=0
    if [ $TOTAL_FOLDERS -gt 0 ]; then
        success_rate=$((MATCHED_FOLDERS * 100 / TOTAL_FOLDERS))
    fi
    
    echo
    echo -e "${BLUE}=== Migration 검증 결과 보고서 ===${NC}"
    echo "검증 완료 시간: $(date)"
    echo
    echo "=== 요약 ==="
    echo "총 폴더 수: $TOTAL_FOLDERS"
    echo "성공 폴더: $MATCHED_FOLDERS"
    echo "타겟 누락: $MISSING_TARGET_FOLDERS"
    echo "소스 누락: $MISSING_SOURCE_FOLDERS"
    echo "파일 개수 불일치: $COUNT_MISMATCH_FOLDERS"
    echo "크기 불일치: $SIZE_MISMATCH_FOLDERS"
    echo "처리 오류: $ERROR_FOLDERS"
    echo
    echo "성공률: $success_rate%"
    echo
    
    # 문제가 있는 폴더들 표시
    local total_issues=$((MISSING_TARGET_FOLDERS + MISSING_SOURCE_FOLDERS + COUNT_MISMATCH_FOLDERS + SIZE_MISMATCH_FOLDERS + ERROR_FOLDERS))
    
    if [ $total_issues -gt 0 ]; then
        echo -e "${RED}=== 문제가 있는 폴더들 ===${NC}"
        
        if [ -f "$MISSING_LOG" ] && [ -s "$MISSING_LOG" ]; then
            echo
            echo "타겟 누락 폴더들 (최대 10개):"
            head -10 "$MISSING_LOG" | while IFS='|' read -r xxx status source_path target_path error_msg; do
                echo "  - $xxx: $error_msg"
            done
        fi
        
        if [ -f "$MISMATCH_LOG" ] && [ -s "$MISMATCH_LOG" ]; then
            echo
            echo "불일치 폴더들 (최대 10개):"
            head -10 "$MISMATCH_LOG" | while IFS='|' read -r xxx status source_path target_path error_msg; do
                echo "  - $xxx: $error_msg"
            done
        fi
        
        if [ -f "$ERROR_LOG" ] && [ -s "$ERROR_LOG" ]; then
            echo
            echo "오류 폴더들 (최대 10개):"
            head -10 "$ERROR_LOG" | while IFS='|' read -r xxx status source_path target_path error_msg; do
                echo "  - $xxx: $error_msg"
            done
        fi
    fi
    
    echo
    echo "=== 최종 판정 ==="
    if [ $total_issues -eq 0 ]; then
        echo -e "${GREEN}✅ 모든 폴더가 정상적으로 마이그레이션되었습니다!${NC}"
        return 0
    else
        echo -e "${RED}❌ 총 $total_issues개 폴더에서 문제가 발견되었습니다.${NC}"
        echo "   - 타겟 누락: $MISSING_TARGET_FOLDERS"
        echo "   - 소스 누락: $MISSING_SOURCE_FOLDERS"
        echo "   - 파일 개수 불일치: $COUNT_MISMATCH_FOLDERS"
        echo "   - 크기 불일치: $SIZE_MISMATCH_FOLDERS"
        echo "   - 처리 오류: $ERROR_FOLDERS"
        return 1
    fi
}

# 상세 로그 저장
save_logs() {
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local log_dir="/tmp/distcp_verify_$timestamp"
    mkdir -p "$log_dir"
    
    # 로그 파일 복사
    [ -f "$LOG_FILE" ] && cp "$LOG_FILE" "$log_dir/success.log"
    [ -f "$MISSING_LOG" ] && cp "$MISSING_LOG" "$log_dir/missing.log"
    [ -f "$MISMATCH_LOG" ] && cp "$MISMATCH_LOG" "$log_dir/mismatch.log"
    [ -f "$ERROR_LOG" ] && cp "$ERROR_LOG" "$log_dir/error.log"
    [ -f "$TEMP_DIR/selected_folders.txt" ] && cp "$TEMP_DIR/selected_folders.txt" "$log_dir/selected_folders.txt"
    
    # 요약 정보 저장
    cat > "$log_dir/summary.txt" << EOF
검증 완료 시간: $(date)
실제 검증 폴더 수: $TOTAL_FOLDERS
$([ -n "$SAMPLE_COUNT" ] && echo "샘플링 적용: $SAMPLE_COUNT개 랜덤 선택")
성공 폴더: $MATCHED_FOLDERS
타겟 누락: $MISSING_TARGET_FOLDERS
소스 누락: $MISSING_SOURCE_FOLDERS
파일 개수 불일치: $COUNT_MISMATCH_FOLDERS
크기 불일치: $SIZE_MISMATCH_FOLDERS
처리 오류: $ERROR_FOLDERS
성공률: $((MATCHED_FOLDERS * 100 / TOTAL_FOLDERS))%
EOF
    
    echo
    echo "상세 로그가 저장되었습니다: $log_dir"
}

# 메인 실행
main() {
    main_verification
    generate_report
    local result=$?
    save_logs
    exit $result
}

# 스크립트 실행
main```
profile
bytebliss

0개의 댓글