Sync với cloud drive (II)

Khi ta định kỳ sync một thư mục local với một thư mục remote, thí dụ Google Drive hay Onedrive, trở ngại lớn nhất là kích thước thư mục. Thời gian kiểm tra để biết file/thư mục nào mới cần tải lên trở nên khá lâu, gần 30 phút với thư mục 100GB và còn tùy ở băng thông upload.

Có một cách khác là giám sát thư mục local, chỉ upload file/thư mục con mới/có thay đổi của nó mà thôi. Việc giám sát này cần inotifywait trong gói inotify-tools.

inotifywait -mr --event 'create,close_write,delete,move' --format "%e %w%f" "$LOCAL_DIR"

Câu lệnh trên cho phép inotify giám sát thư mục $LOCAL_DIR trên các sự kiện create, close_write, delete, move của file và thư mục. Khi có sự kiện này trên thư mục được giám sát, inotifywait báo cho chúng ta tên sự kiện và filename. Tất nhiên khi đó chúng ta lại gọi rclone có hành động tương ứng.

#!/bin/bash
# Script cloudup1, version 20191116
# © 2019 LNT <lnt@ly-le.info>
#
# Cập nhật file/thư mục có thay đổi vào ổ đĩa đám mây

lockfile="/run/$(basename $0).pid"
trap 'sudo rm -f "$lockfile"; rm -rf $SHM' EXIT
echo -e "DATE:$(date)\nPID:$$" | sudo tee "$lockfile" > /dev/null | exit 1

function usage() {
  cat >&2 <<EOF

Cập nhật lên ổ đĩa đám mây ->> bỏ qua symlink <<-

usage: $(basename $0) LOCAL_DIR[^LOCAL_DIR2] REMOTE_DIR[^REMOTE_DIR2]
  LOCAL_DIR: thư mục được giám sát

EOF
  echo -e "[✘] Lỗi: $1!\n"
  exit 2
}

SNAME=$(basename $0)
LOG_FILE=/tmp/$SNAME.log
OPT='-u --fast-list --transfers=20 --checkers=20 --tpslimit=20 --drive-chunk-size=1M'
LOG="--log-file=$LOG_FILE"
SHM=$(mktemp -d /dev/shm/$SNAME-XXXX)

[ $# -ne 2 ] && usage "LOCAL_DIR hay REMOTE_DIR không hợp lệ"
LOCAL_DIR="$1"
REMOTE_DIR="$2"
oldIFS=$IFS; IFS='^'; LOCALS=($LOCAL_DIR); REMOTES=($REMOTE_DIR)
printf "%s\n" ${LOCALS[@]} > $SHM/locals; printf "%s\n" ${REMOTES[@]} > $SHM/remotes
# -->> Bỏ # ở 6 dòng sau để test LOCAL_DIR và REMOTE_DIR <<--#
# for local in ${LOCALS[@]}; do
#   [ -e $local ] || usage "LOCAL_DIR '$local' không tồn tại" 
# done
# for remote in ${REMOTES[@]}; do
#   rclone lsd $remote &> /dev/null || usage "REMOTE_DIR '$remote' không xác định" 
# done
IFS=$oldIFS

sudo sysctl fs.inotify.max_user_watches=524288 &> /dev/null
sudo sysctl -p &> /dev/null

inotifywait -mr -e CREATE,CLOSE_WRITE,DELETE,MOVED_FROM,MOVED_TO,MOVE_SELF --format "%e %w▁%f" --fromfile $SHM/locals |
  while read evt full; do
    oIFS=$IFS; IFS="▁"; read wf ef <<< $full; IFS=$oIFS
    while read pat; do
      [[ "$wf$ef" =~ ^"$pat" ]] && tmp="$wf$ef" && wf="$pat" && ef=${tmp#"$wf"} && break
    done < $SHM/locals
    file=$wf$ef
    dir=${wf##*/}
    while read -r remote; do
      rfile=${file/"$wf"/"$remote/$dir"}
      case $evt in
        CLOSE_WRITE,CLOSE)
          rclone copyto "$file" "$rfile" $OPT $LOG
          ;;
        CREATE,ISDIR)
          [ -z "$(ls -A "$file")" ] && rclone mkdir "$rfile" || rclone copyto "$file" "$rfile" $OPT $LOG
          ;;
        MOVED_FROM,ISDIR)
          echo "$rfile" > $SHM/$remote
          ;;
        MOVED_FROM)
          echo "$rfile" > $SHM/$remote
          (
            sleep .2
            afile=$(<$SHM/$remote) && >$SHM/$remote
            [ -d $afile ] && cmd=purge || cmd=delete
            [ ! -z "$afile" ] && rclone $cmd "$afile" $OPT $LOG &> /dev/null
          ) &
          ;;
        MOVED_TO|MOVED_TO,ISDIR)
          ofile=$(<$SHM/$remote) && >$SHM/$remote
          [ -z "$ofile" ] && rclone copyto "$file" "$rfile" $OPT $LOG || rclone moveto "$ofile" "$rfile" $OPT $LOG
         ;;
        MOVE_SELF) #folder only
          ofile=$(<$SHM/$remote) && >$SHM/$remote
          [ -z "$ofile" ] || rclone purge "$rfile" $LOG
          ;;
      esac
    done < ${SHM}/remotes
  done

Script cloudup1 được gọi thường trú mỗi khi RPi khởi động

@reboot /path/to/cloudup1 local_folder remote:folder

Script cloudup1 trên chấp nhận nhiều LOCAL_DIR và nhiều REMOTE_DIR, chấp nhận tên file có khoảng trắng.

Gỉa sử ta muốn backup tức thời các file/thư mục thuộc /home/pi/Documents và /mnt/task vào các ổ đĩa đám mây:

cloudup1 /home/pi/Documents^/mnt/task gdrive:office^onedrive:office

Các file thuộc Documents sẽ backup ở office/Documents, task ở office/task

Script này bỏ qua các symlink (xem như không có)

Chú thích

  1. Rclone hỗ trợ symbolic link nhưng inotifywait thì không. File trong thư mục đích của symlink có thay đổi nhưng symlink vẫn không thay đổi nên inotifywait không phát hiện, do vậy script không cập nhật lên REMOTE_DIR.
  2. Tuy nhiên, script có thể được cải tiến để hỗ trợ symlink bằng cách giám sát cả thư mục đích của mọi symlink trong thư mục local (đã xong!)
  3. Script dùng cho các ổ đĩa đám mây được rclone hỗ trợ.

Comments Off on Sync với cloud drive (II)

Filed under Software

Comments are closed.