aboutsummaryrefslogtreecommitdiff
path: root/share/hydractl/sync-guestfs
blob: dce2f2bbba601da56356715c4fc68126e8d8a73d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/bin/bash
#
# sync-guestfs: sync a tree containing virtual machine guest images
#

# Load
source $APP_BASE/lib/hydra/functions || exit 1
hydra_config_load

# Parameters
BASENAME="$0"
ORIG="$1"
DEST="$2"
TMP="/tmp"
RSYNC="ionice -c 3 nice -n 19 rsync -av --delete --progress"

# Dependencies
hydra_install_package rsync
hydra_install_package libguestfs-tools

# Syntax
if [ -z "$DEST" ]; then
  echo "usage: $BASENAME <orig-folder> <dest-folder>"
  exit 1
elif [ ! -d "$ORIG" ]; then
  echo "folder $DEST does not exist."
  exit 1
fi

# Sudo
if [ "$USER" != 'root' ]; then
  export SUDO="sudo"
fi

# Ensure the dest folder exist
if [ ! -d "$DEST" ]; then
  $SUDO mkdir -p $DEST

  OWNER="$(stat -c %U $ORIG)"
  GROUP="$(stat -c %G $ORIG)"

  # With the right permissions
  $SUDO chown $OWNER.$GROUP $DEST
fi

# First sync the folder structure
$SUDO $RSYNC --exclude='*.img' $ORIG/ $DEST/

# Temporary folders
ORIG_MOUNT="`mktemp -d $TMP/sync-guestfs-orig.XXXXXXXXXX`"
DEST_MOUNT="`mktemp -d $TMP/sync-guestfs-dest.XXXXXXXXXX`"

# Main loop
(
  cd $ORIG
  find -name '*.img' | sort | sed -e 's|^./||' | while read image; do
    if [ ! -e "$DEST/$image" ]; then
      # Make the first copy
      # See https://gergap.wordpress.com/2013/08/10/rsync-and-sparse-files/
      #     https://stackoverflow.com/questions/19821186/rsync-sparse-does-transfer-whole-data#19827546
      echo "Making the first copy of $image to $DEST, which might take a while..."
      time $SUDO $RSYNC --sparse $image $DEST/$image
    else
      echo "Syncing $DEST/$image..."
      time $SUDO $RSYNC --inplace $image $DEST/$image

      #
      # Sync using libguestfs-tools: mount existing
      # images and use rsync to copy the differences.
      #
      ## Mount and sync
      #$SUDO guestmount -a $image       -i --ro $ORIG_MOUNT/ && \
      #$SUDO guestmount -a $DEST/$image -i      $DEST_MOUNT/ && \
      #time $SUDO $RSYNC $ORIG_MOUNT/ $DEST_MOUNT/           || \
      #echo "Failed to sync $image with $DEST/$image."
      #
      ## Umount orig image
      #if mount | grep -q "$ORIG_MOUNT"; then
      #  $SUDO guestunmount $ORIG_MOUNT
      #fi
      #
      ## Umount dest image
      #if mount | grep -q "$DEST_MOUNT"; then
      #  $SUDO guestunmount $DEST_MOUNT
      #fi
      #
      #echo "Optimizing $DEST/$image size..."
      #time $SUDO ionice -c 3 nice -n 19 virt-sparsify --in-place $DEST/$image
      #time $SUDO ionice -c 3 nice -n 19 virt-sparsify --tmp $TMP --compress $DEST/$image $DEST/$image.new && \
      #     $SUDO mv $DEST/$image.new $DEST/$image
    fi
  done
)

# Remove images that does not exist anymore in the origin
(
  cd $DEST
  find -name '*.img' | sort | sed -e 's|^./||' | while read image; do
    if [ ! -e "$ORIG/$image" ]; then
      echo "Removing old $DEST/$image..."
      $SUDO rm -f $image
    fi
  done

  # Sync again to prune any dangling folder structure
  echo "Cleaning up..."
  $SUDO $RSYNC --exclude='*.img' $ORIG/ $DEST/
)

# Teardown
$SUDO rmdir $ORIG_MOUNT
$SUDO rmdir $DEST_MOUNT