Advertisement
bil-awal

5b_remote_copy_rsync.sh

Jun 17th, 2025
413
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 17.50 KB | Cryptocurrency | 0 0
  1. #!/bin/bash
  2. # =============================================================================
  3. # File: 5b_remote_copy_rsync_modified.sh
  4. # Deskripsi: Menyalin file ke server remote menggunakan RSYNC/SCP (Auto-Fallback)
  5. # Author: Modified from original by bil-awal
  6. # =============================================================================
  7.  
  8. # Konfigurasi default
  9. DEFAULT_PORT=22
  10. DEFAULT_RSYNC_OPTIONS="-ahz --info=progress2"
  11. DEFAULT_SCP_OPTIONS="-r -p -v"
  12. SSH_TIMEOUT=10
  13.  
  14. # Global variable untuk transfer method
  15. TRANSFER_METHOD=""
  16.  
  17. # Fungsi untuk menampilkan cara penggunaan
  18. usage() {
  19.     echo "Penggunaan: $0 <file_source> <username> <ip_address> [port] [destination_path]"
  20.     echo ""
  21.     echo "Parameter:"
  22.     echo "  file_source      - File atau direktori yang akan disalin"
  23.     echo "  username         - Username di server remote"
  24.     echo "  ip_address       - IP address server tujuan"
  25.     echo "  port (opsional)  - Port SSH (default: 22)"
  26.     echo "  destination_path (opsional) - Path tujuan (default: /home/username/)"
  27.     echo ""
  28.     echo "Contoh:"
  29.     echo "  $0 /home/user/document.txt admin 192.168.1.100"
  30.     echo "  $0 /var/log/myapp/ deploy 10.0.0.5 2222"
  31.     echo "  $0 backup.tar.gz user 192.168.1.50 22 /tmp/"
  32.     exit 1
  33. }
  34.  
  35. # Fungsi logging
  36. log() {
  37.     local level="$1"
  38.     shift
  39.     local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
  40.     echo "[$timestamp] [$level] $*"
  41. }
  42.  
  43. # Validasi jumlah parameter
  44. if [ "$#" -lt 3 ] || [ "$#" -gt 5 ]; then
  45.     echo "Error: Jumlah parameter tidak sesuai!"
  46.     usage
  47. fi
  48.  
  49. # Variabel
  50. SOURCE_PATH="$1"
  51. REMOTE_USER="$2"
  52. REMOTE_IP="$3"
  53. REMOTE_PORT="${4:-$DEFAULT_PORT}"
  54. REMOTE_DEST="${5:-/home/$REMOTE_USER/}"
  55. RSYNC_OPTIONS="${RSYNC_OPTIONS:-$DEFAULT_RSYNC_OPTIONS}"
  56. SCP_OPTIONS="${SCP_OPTIONS:-$DEFAULT_SCP_OPTIONS}"
  57.  
  58. # Fungsi untuk validasi input yang lebih baik
  59. validate_inputs() {
  60.     # Validasi source path
  61.     if [ ! -e "$SOURCE_PATH" ]; then
  62.         log "ERROR" "File atau direktori '$SOURCE_PATH' tidak ditemukan!"
  63.         exit 1
  64.     fi
  65.    
  66.     # Validasi username tidak kosong
  67.     if [ -z "$REMOTE_USER" ]; then
  68.         log "ERROR" "Username tidak boleh kosong!"
  69.         exit 1
  70.     fi
  71.    
  72.     # Validasi port (harus numerik dan dalam range valid)
  73.     if ! [[ "$REMOTE_PORT" =~ ^[0-9]+$ ]] || [ "$REMOTE_PORT" -lt 1 ] || [ "$REMOTE_PORT" -gt 65535 ]; then
  74.         log "ERROR" "Port '$REMOTE_PORT' tidak valid! Harus antara 1-65535."
  75.         exit 1
  76.     fi
  77.    
  78.     # Validasi format IP address atau hostname
  79.     if echo "$REMOTE_IP" | grep -qE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then
  80.         # Validasi IP address lebih detail
  81.         IFS='.' read -ra ADDR <<< "$REMOTE_IP"
  82.         for i in "${ADDR[@]}"; do
  83.             if [ "$i" -gt 255 ]; then
  84.                 log "ERROR" "IP address '$REMOTE_IP' tidak valid!"
  85.                 exit 1
  86.             fi
  87.         done
  88.     else
  89.         log "INFO" "'$REMOTE_IP' terdeteksi sebagai hostname/FQDN."
  90.     fi
  91. }
  92.  
  93. # Fungsi untuk cek dependencies dan pilih method
  94. select_transfer_method() {
  95.     # Cek SSH (critical)
  96.     if ! command -v ssh &> /dev/null; then
  97.         log "ERROR" "SSH client tidak ditemukan! Install openssh-client."
  98.         exit 1
  99.     fi
  100.    
  101.     # Cek rsync atau scp
  102.     if command -v rsync &> /dev/null; then
  103.         TRANSFER_METHOD="rsync"
  104.         log "SUCCESS" "RSYNC tersedia - menggunakan rsync"
  105.     elif command -v scp &> /dev/null; then
  106.         TRANSFER_METHOD="scp"
  107.         log "WARNING" "RSYNC tidak tersedia - fallback ke SCP"
  108.     else
  109.         log "ERROR" "Baik rsync maupun scp tidak tersedia!"
  110.         exit 1
  111.     fi
  112.    
  113.     # Check optional commands
  114.     if ! command -v timeout &> /dev/null; then
  115.         log "WARNING" "Command 'timeout' tidak tersedia - menggunakan default timeout"
  116.     fi
  117. }
  118.  
  119. # Fungsi untuk cek konektivitas SSH yang robust
  120. check_ssh_connectivity() {
  121.     log "INFO" "Memeriksa koneksi SSH ke $REMOTE_USER@$REMOTE_IP:$REMOTE_PORT..."
  122.    
  123.     # Prepare SSH options
  124.     local ssh_opts="-p $REMOTE_PORT -o ConnectTimeout=5 -o BatchMode=yes -o LogLevel=ERROR"
  125.     local ssh_cmd="ssh $ssh_opts $REMOTE_USER@$REMOTE_IP exit"
  126.    
  127.     # Test SSH connectivity dengan atau tanpa timeout
  128.     if command -v timeout &> /dev/null; then
  129.         ssh_cmd="timeout $SSH_TIMEOUT $ssh_cmd"
  130.     fi
  131.    
  132.     if $ssh_cmd 2>/dev/null; then
  133.         log "SUCCESS" "SSH connection berhasil ke $REMOTE_IP:$REMOTE_PORT"
  134.         return 0
  135.     else
  136.         log "WARNING" "SSH key-based authentication gagal. Kemungkinan penyebab:"
  137.         echo "  - SSH service tidak berjalan pada port $REMOTE_PORT"
  138.         echo "  - SSH keys belum dikonfigurasi"
  139.         echo "  - Authentication memerlukan password"
  140.         echo "  - Server tidak dapat dijangkau"
  141.        
  142.         read -p "Lanjutkan dengan password authentication? (y/n): " -n 1 -r
  143.         echo
  144.         if [[ ! $REPLY =~ ^[Yy]$ ]]; then
  145.             exit 1
  146.         fi
  147.         return 1
  148.     fi
  149. }
  150.  
  151. # Fungsi untuk cek SSH key dengan lebih detail
  152. check_ssh_auth() {
  153.     local key_types=("rsa" "ed25519" "ecdsa" "dsa")
  154.     local found_keys=()
  155.    
  156.     for key_type in "${key_types[@]}"; do
  157.         local key_file="$HOME/.ssh/id_$key_type"
  158.         if [ -f "$key_file" ]; then
  159.             found_keys+=("$key_type")
  160.         fi
  161.     done
  162.    
  163.     if [ ${#found_keys[@]} -gt 0 ]; then
  164.         log "SUCCESS" "SSH keys ditemukan: ${found_keys[*]}"
  165.     else
  166.         log "INFO" "SSH key tidak ditemukan. Password authentication akan digunakan."
  167.         echo "Tips: Gunakan 'ssh-keygen -t ed25519' untuk membuat SSH key pair."
  168.     fi
  169.    
  170.     # Test SSH agent
  171.     if ssh-add -l &>/dev/null; then
  172.         log "INFO" "SSH agent aktif dengan $(ssh-add -l | wc -l) key(s) loaded."
  173.     fi
  174. }
  175.  
  176. # Fungsi untuk mendapatkan info file/direktori yang detail
  177. get_source_info() {
  178.     local size type file_count dir_count
  179.    
  180.     if [ -f "$SOURCE_PATH" ]; then
  181.         type="File"
  182.         size=$(du -h "$SOURCE_PATH" | cut -f1)
  183.         file_count="1"
  184.         dir_count="0"
  185.     elif [ -d "$SOURCE_PATH" ]; then
  186.         type="Direktori"
  187.         size=$(du -sh "$SOURCE_PATH" 2>/dev/null | cut -f1)
  188.         file_count=$(find "$SOURCE_PATH" -type f 2>/dev/null | wc -l)
  189.         dir_count=$(find "$SOURCE_PATH" -type d 2>/dev/null | wc -l)
  190.         dir_count=$((dir_count - 1))  # Exclude source directory itself
  191.     else
  192.         type="Unknown"
  193.         size="N/A"
  194.         file_count="N/A"
  195.         dir_count="N/A"
  196.     fi
  197.    
  198.     echo "Tipe: $type"
  199.     echo "Ukuran: $size"
  200.     echo "Files: $file_count"
  201.     if [ "$dir_count" != "0" ] && [ "$dir_count" != "N/A" ]; then
  202.         echo "Directories: $dir_count"
  203.     fi
  204.     echo "Path: $SOURCE_PATH"
  205. }
  206.  
  207. # Fungsi untuk memilih mode transfer (adapted untuk SCP)
  208. select_transfer_mode() {
  209.     echo ""
  210.     echo "Method: $TRANSFER_METHOD"
  211.    
  212.     if [ "$TRANSFER_METHOD" = "rsync" ]; then
  213.         echo "Pilih mode sinkronisasi RSYNC:"
  214.         echo "1. Normal     - Copy file baru dan update yang berubah"
  215.         echo "2. Mirror     - Sinkronisasi penuh (hapus file di tujuan yang tidak ada di source)"
  216.         echo "3. Backup     - Normal + backup file yang akan dioverwrite"
  217.         echo "4. Checksum   - Validasi dengan checksum (lebih akurat, lebih lambat)"
  218.         echo "5. Dry-run    - Simulasi saja, tidak melakukan transfer"
  219.         echo "6. Custom     - Masukkan opsi rsync sendiri"
  220.         echo ""
  221.         read -p "Pilih mode (1-6) [default: 1]: " mode_choice
  222.        
  223.         case "$mode_choice" in
  224.             2)
  225.                 RSYNC_OPTIONS="$RSYNC_OPTIONS --delete"
  226.                 log "INFO" "Mode: Mirror (dengan --delete)"
  227.                 ;;
  228.             3)
  229.                 local backup_dir="backup_$(date +%Y%m%d_%H%M%S)"
  230.                 RSYNC_OPTIONS="$RSYNC_OPTIONS --backup --backup-dir=$backup_dir"
  231.                 log "INFO" "Mode: Backup (backup dir: $backup_dir)"
  232.                 ;;
  233.             4)
  234.                 RSYNC_OPTIONS="$RSYNC_OPTIONS --checksum"
  235.                 log "INFO" "Mode: Checksum validation"
  236.                 ;;
  237.             5)
  238.                 RSYNC_OPTIONS="$RSYNC_OPTIONS --dry-run"
  239.                 log "INFO" "Mode: Dry-run (simulasi)"
  240.                 ;;
  241.             6)
  242.                 echo "Opsi rsync saat ini: $RSYNC_OPTIONS"
  243.                 read -p "Masukkan opsi tambahan: " custom_opts
  244.                 if [ -n "$custom_opts" ]; then
  245.                     RSYNC_OPTIONS="$RSYNC_OPTIONS $custom_opts"
  246.                 fi
  247.                 log "INFO" "Mode: Custom"
  248.                 ;;
  249.             *)
  250.                 log "INFO" "Mode: Normal"
  251.                 ;;
  252.         esac
  253.     else
  254.         echo "Mode SCP: Normal copy (SCP tidak mendukung advanced sync modes)"
  255.         echo "Options yang tersedia untuk SCP:"
  256.         echo "  -r: Recursive (untuk direktori)"
  257.         echo "  -p: Preserve timestamps dan permissions"  
  258.         echo "  -v: Verbose output"
  259.         log "INFO" "Mode: SCP Normal"
  260.     fi
  261. }
  262.  
  263. # Fungsi untuk bandwidth limiting (works untuk both rsync dan scp)
  264. set_bandwidth_limit() {
  265.     echo ""
  266.     read -p "Apakah ingin membatasi bandwidth? (y/n): " -n 1 -r
  267.     echo
  268.    
  269.     if [[ $REPLY =~ ^[Yy]$ ]]; then
  270.         if [ "$TRANSFER_METHOD" = "rsync" ]; then
  271.             echo "Contoh: 1000 (KB/s), 5M (MB/s)"
  272.             read -p "Masukkan limit bandwidth: " bw_limit
  273.             if [ -n "$bw_limit" ]; then
  274.                 RSYNC_OPTIONS="$RSYNC_OPTIONS --bwlimit=$bw_limit"
  275.                 log "INFO" "RSYNC Bandwidth limit: $bw_limit"
  276.             fi
  277.         else
  278.             echo "Contoh: 1000 (KB/s)"
  279.             read -p "Masukkan limit bandwidth (KB/s): " bw_limit
  280.             if [ -n "$bw_limit" ]; then
  281.                 SCP_OPTIONS="$SCP_OPTIONS -l $bw_limit"
  282.                 log "INFO" "SCP Bandwidth limit: ${bw_limit} KB/s"
  283.             fi
  284.         fi
  285.     fi
  286. }
  287.  
  288. # Fungsi untuk exclude patterns (hanya untuk rsync)
  289. create_exclude_patterns() {
  290.     if [ "$TRANSFER_METHOD" != "rsync" ]; then
  291.         log "INFO" "Exclude patterns hanya tersedia untuk RSYNC"
  292.         return
  293.     fi
  294.    
  295.     local exclude_file="/tmp/rsync_exclude_$$"
  296.    
  297.     echo ""
  298.     read -p "Apakah ada file/direktori yang ingin di-exclude? (y/n): " -n 1 -r
  299.     echo
  300.    
  301.     if [[ $REPLY =~ ^[Yy]$ ]]; then
  302.         echo ""
  303.         echo "Pilih exclude method:"
  304.         echo "1. Manual input"
  305.         echo "2. Common patterns (logs, cache, tmp files)"
  306.         echo "3. Development patterns (node_modules, .git, build dirs)"
  307.         read -p "Pilih (1-3): " exclude_method
  308.        
  309.         case "$exclude_method" in
  310.             2)
  311.                 cat > "$exclude_file" << EOF
  312. *.log
  313. *.tmp
  314. *.cache
  315. *~
  316. .DS_Store
  317. Thumbs.db
  318. EOF
  319.                 log "INFO" "Common exclude patterns applied"
  320.                 ;;
  321.             3)
  322.                 cat > "$exclude_file" << EOF
  323. node_modules/
  324. .git/
  325. .svn/
  326. .hg/
  327. __pycache__/
  328. *.pyc
  329. *.pyo
  330. .pytest_cache/
  331. target/
  332. build/
  333. dist/
  334. .gradle/
  335. .idea/
  336. .vscode/
  337. *.swp
  338. *.swo
  339. EOF
  340.                 log "INFO" "Development exclude patterns applied"
  341.                 ;;
  342.             *)
  343.                 echo "Masukkan pattern yang ingin di-exclude (satu per baris, akhiri dengan CTRL+D):"
  344.                 echo "Contoh: *.log, node_modules/, .git/, __pycache__/"
  345.                 cat > "$exclude_file"
  346.                 ;;
  347.         esac
  348.        
  349.         if [ -s "$exclude_file" ]; then
  350.             RSYNC_OPTIONS="$RSYNC_OPTIONS --exclude-from=$exclude_file"
  351.             echo "✓ Exclude patterns tersimpan."
  352.             echo "Preview exclude patterns:"
  353.             cat "$exclude_file" | sed 's/^/  - /'
  354.         fi
  355.     fi
  356. }
  357.  
  358. # Fungsi untuk melakukan transfer dengan fallback
  359. perform_transfer() {
  360.     local source="$1"
  361.     local destination="$2"
  362.     local start_time=$(date +%s)
  363.    
  364.     echo ""
  365.     log "INFO" "Memulai transfer menggunakan $TRANSFER_METHOD..."
  366.     echo "Dari: $source"
  367.     echo "Ke: $destination"
  368.     echo "Port: $REMOTE_PORT"
  369.    
  370.     case "$TRANSFER_METHOD" in
  371.         "rsync")
  372.             # Tambahkan trailing slash untuk direktori (rsync behavior)
  373.             if [ -d "$source" ]; then
  374.                 source="${source%/}/"
  375.             fi
  376.            
  377.             echo "Options: $RSYNC_OPTIONS"
  378.             echo ""
  379.            
  380.             # Build rsync command
  381.             local rsync_cmd
  382.             if [ "$REMOTE_PORT" != "22" ]; then
  383.                 rsync_cmd="rsync $RSYNC_OPTIONS -e \"ssh -p $REMOTE_PORT\" \"$source\" \"$destination\""
  384.             else
  385.                 rsync_cmd="rsync $RSYNC_OPTIONS \"$source\" \"$destination\""
  386.             fi
  387.            
  388.             if eval $rsync_cmd; then
  389.                 local end_time=$(date +%s)
  390.                 local duration=$((end_time - start_time))
  391.                
  392.                 echo ""
  393.                 log "SUCCESS" "RSYNC transfer berhasil!"
  394.                 echo "Waktu transfer: ${duration} detik"
  395.                
  396.                 # Cleanup exclude file jika ada
  397.                 if [[ "$RSYNC_OPTIONS" == *"--exclude-from"* ]]; then
  398.                     rm -f /tmp/rsync_exclude_$$
  399.                 fi
  400.                
  401.                 return 0
  402.             else
  403.                 local exit_code=$?
  404.                 log "ERROR" "RSYNC transfer gagal dengan exit code: $exit_code"
  405.                 return $exit_code
  406.             fi
  407.             ;;
  408.         "scp")
  409.             echo "Options: $SCP_OPTIONS"
  410.             echo ""
  411.            
  412.             # Build SCP command
  413.             local scp_cmd
  414.             if [ "$REMOTE_PORT" != "22" ]; then
  415.                 SCP_OPTIONS="$SCP_OPTIONS -P $REMOTE_PORT"
  416.             fi
  417.            
  418.             scp_cmd="scp $SCP_OPTIONS \"$source\" \"$destination\""
  419.            
  420.             if eval $scp_cmd; then
  421.                 local end_time=$(date +%s)
  422.                 local duration=$((end_time - start_time))
  423.                
  424.                 echo ""
  425.                 log "SUCCESS" "SCP transfer berhasil!"
  426.                 echo "Waktu transfer: ${duration} detik"
  427.                 return 0
  428.             else
  429.                 local exit_code=$?
  430.                 log "ERROR" "SCP transfer gagal dengan exit code: $exit_code"
  431.                 return $exit_code
  432.             fi
  433.             ;;
  434.     esac
  435. }
  436.  
  437. # Fungsi untuk menampilkan tips optimasi
  438. suggest_optimization() {
  439.     echo ""
  440.     if [ "$TRANSFER_METHOD" = "rsync" ]; then
  441.         echo "💡 Tips RSYNC Optimization:"
  442.         echo "📁 File besar: --partial --append-verify --inplace"
  443.         echo "🌐 Network: --compress-level=6 --bwlimit=RATE"
  444.         echo "💾 Backup: --backup --backup-dir=backup_\$(date +%Y%m%d)"
  445.         echo "🔍 Validasi: --checksum (akurat) atau --size-only (cepat)"
  446.         echo "📊 Monitoring: --progress --stats -v"
  447.         echo "🚀 Performance: --whole-file (LAN) atau --no-whole-file (WAN)"
  448.     else
  449.         echo "💡 Tips SCP Optimization:"
  450.         echo "📁 Compression: -C (enable compression)"
  451.         echo "🌐 Network: -l LIMIT (bandwidth limit)"
  452.         echo "🔐 Security: -o (SSH options)"
  453.         echo "📊 Monitoring: -v (verbose output)"
  454.     fi
  455. }
  456.  
  457. # Fungsi untuk menampilkan transfer summary
  458. show_transfer_summary() {
  459.     echo ""
  460.     echo "=========================================="
  461.     echo "RINGKASAN TRANSFER ($TRANSFER_METHOD)"
  462.     echo "=========================================="
  463.     echo "Source: $SOURCE_PATH"
  464.     echo "Destination: $DESTINATION"
  465.     echo "Port: $REMOTE_PORT"
  466.     echo "Method: $TRANSFER_METHOD"
  467.     if [ "$TRANSFER_METHOD" = "rsync" ]; then
  468.         echo "Options: $RSYNC_OPTIONS"
  469.     else
  470.         echo "Options: $SCP_OPTIONS"
  471.     fi
  472.     echo "=========================================="
  473. }
  474.  
  475. # Main execution
  476. main() {
  477.     echo "=========================================="
  478.     echo "Remote Copy (RSYNC/SCP Hybrid)"
  479.     echo "=========================================="
  480.    
  481.     # Select transfer method
  482.     select_transfer_method
  483.    
  484.     # Validasi input
  485.     validate_inputs
  486.    
  487.     # Tampilkan informasi transfer
  488.     echo ""
  489.     echo "Informasi Transfer:"
  490.     echo "-------------------"
  491.     get_source_info
  492.     echo "Tujuan: $REMOTE_USER@$REMOTE_IP:$REMOTE_DEST"
  493.     echo "Port: $REMOTE_PORT"
  494.     echo "Method: $TRANSFER_METHOD"
  495.    
  496.     # Cek konektivitas SSH
  497.     check_ssh_connectivity
  498.    
  499.     # Cek SSH authentication
  500.     check_ssh_auth
  501.    
  502.     # Pilih mode transfer
  503.     select_transfer_mode
  504.    
  505.     # Set bandwidth limit
  506.     set_bandwidth_limit
  507.    
  508.     # Tanyakan exclude patterns (hanya untuk rsync)
  509.     create_exclude_patterns
  510.    
  511.     # Tampilkan tips optimasi
  512.     suggest_optimization
  513.    
  514.     # Buat destination path
  515.     DESTINATION="$REMOTE_USER@$REMOTE_IP:$REMOTE_DEST"
  516.    
  517.     # Tampilkan summary
  518.     show_transfer_summary
  519.    
  520.     # Konfirmasi sebelum transfer
  521.     echo ""
  522.     read -p "Mulai transfer? (y/n): " -n 1 -r
  523.     echo
  524.     if [[ ! $REPLY =~ ^[Yy]$ ]]; then
  525.         log "INFO" "Transfer dibatalkan oleh user."
  526.         exit 0
  527.     fi
  528.    
  529.     # Lakukan transfer
  530.     if perform_transfer "$SOURCE_PATH" "$DESTINATION"; then
  531.         echo ""
  532.         echo "=========================================="
  533.         log "SUCCESS" "File/direktori berhasil ditransfer!"
  534.         echo "Lokasi: $DESTINATION"
  535.         echo "=========================================="
  536.         exit 0
  537.     else
  538.         echo ""
  539.         echo "=========================================="
  540.         log "ERROR" "Gagal melakukan transfer."
  541.         echo "=========================================="
  542.         exit 1
  543.     fi
  544. }
  545.  
  546. # Handle Ctrl+C gracefully
  547. trap 'echo ""; log "INFO" "Transfer dibatalkan oleh user."; exit 1' INT
  548.  
  549. # Jalankan main function
  550. main
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement