copy_containers 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. #!/bin/bash
  2. CONTS_LIST=$(lxc list | grep "RUNNING\|STOPPED" | awk {'print $2'})
  3. if [ $# -eq 0 ]
  4. then
  5. echo "No arguments supplied, doing interactive mode"
  6. sleep 1
  7. let i=0
  8. W=()
  9. while read -r line;
  10. do
  11. let i=$i+1
  12. W+=($i "$line" off)
  13. done < <( echo "$CONTS_LIST" )
  14. CONTS=$(dialog --checklist "Choose containers to copy" 24 80 17 "${W[@]}" 3>&2 2>&1 1>&3)
  15. DEST_IP=$(dialog --inputbox "Enter destination IP:" 25 25 --output-fd 1)
  16. DEST_PORT=$(dialog --inputbox "Enter destination SSH port(leave blank for default 22):" 25 25 --output-fd 1)
  17. fi
  18. if [[ ! -z "$1" ]]; then
  19. if [[ ! -z "$2" ]]; then
  20. CONTS=$(echo "$CONTS_LIST" | nl | grep "$1" | awk {'print $1'})
  21. DEST_IP="$2"
  22. DEST_PORT="$3"
  23. fi
  24. fi
  25. [ -z "$DEST_PORT" ] && DEST_PORT=22
  26. DEST_ZPOOL=$(echo crypt)
  27. DEST_ZPOOL_2=$(echo storage)
  28. DATASETS=$(zfs list)
  29. SNAPS=$(zfs list -t snapshot)
  30. DEST_SNAPS=$(ssh $DEST_IP -p $DEST_PORT zfs list -t snapshot); (($? != 0)) && { echo "SSH command to fill DEST_SNAPS exited with non-zero"; exit 1; }
  31. bionic_checker=$(ssh $DEST_IP -p $DEST_PORT lsb_release -c | awk {'print $2'}); (($? != 0)) && { echo "SSH command to fill bionic_checker exited with non-zero"; exit 1; }
  32. for CONT in $CONTS;
  33. do
  34. CONT_VAR=$(echo "$CONTS_LIST"| sed -n "`echo "$CONT p" | sed 's/ //'`")
  35. SNAPS_CLEANED=$(echo "$SNAPS" | grep crypt | grep lxd | grep storage | grep containers | grep -E "....-..-.._........--.d" | awk {'print $1'} | grep "$CONT_VAR"@)
  36. DEST_SNAPS_CLEANED=$(echo "$DEST_SNAPS" | grep crypt | grep lxd | grep storage | grep containers | grep -E "....-..-.._........--.d" | awk {'print $1'} | grep "$CONT_VAR"@)
  37. SOURCE_DEST_IDENTICAL_SNAPS=$(grep -Fxf <(echo "$SNAPS_CLEANED") <(echo "$DEST_SNAPS_CLEANED"))
  38. SNAP_TO_SEND_FIRST=$(echo "$SOURCE_DEST_IDENTICAL_SNAPS" | tail -n1)
  39. DATASET_VAR=$(echo "$DATASETS" | grep crypt | grep lxd | grep storage | grep containers | awk {'print $1'} | grep -E "$CONT_VAR"$)
  40. DATASET_RECORDSIZE_VAR=$(zfs get recordsize -H -o value "$DATASET_VAR")
  41. DATASET_ATIME_VAR=$(zfs get atime -H -o value "$DATASET_VAR")
  42. DATASET_RELATIME_VAR=$(zfs get relatime -H -o value "$DATASET_VAR")
  43. DATASET_QUOTA_VAR=$(zfs get quota -H -o value "$DATASET_VAR")
  44. SNAP_TO_SEND_FIRST_FOR_LATER_CHECK=$(echo "$SNAP_TO_SEND_FIRST")
  45. IFS="
  46. "
  47. echo "Start move "$CONT_VAR""
  48. if [ -z "$SNAP_TO_SEND_FIRST" ]
  49. then
  50. if [ -z "$SNAPS_CLEANED" ]
  51. then
  52. echo "Creating first snapshot"
  53. for command in $(zfSnap -n -zpool28fix -a 7d "$DATASET_VAR" | grep snapshot | grep "$DATASET_VAR")
  54. do
  55. SNAP_TO_SEND_FIRST=$(echo "$command" | awk '{print $3}')
  56. echo "Doing "$command""
  57. eval "$command";
  58. done
  59. else
  60. SNAP_TO_SEND_FIRST=$(echo "$SNAPS_CLEANED" | tail -n 48 | head -n 1)
  61. fi
  62. echo "Sending first snapshot"
  63. echo "Sending "$SNAP_TO_SEND_FIRST""
  64. zfs send "$SNAP_TO_SEND_FIRST" | lzop | pv | ssh "$DEST_IP" -p $DEST_PORT "lzop -d | zfs recv -o recordsize="$DATASET_RECORDSIZE_VAR" -o atime="$DATASET_ATIME_VAR" -o relatime="$DATASET_RELATIME_VAR" -o quota="$DATASET_QUOTA_VAR" "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR""; (($? != 0)) && { echo "SSH command to send first snapshot exited with non-zero"; exit 1; }
  65. echo "Sleep 2"
  66. sleep 2
  67. fi
  68. echo "Creating second snapshot"
  69. for command in $(zfSnap -n -zpool28fix -a 7d "$DATASET_VAR" | grep snapshot | grep "$DATASET_VAR")
  70. do
  71. SNAP_TO_SEND_SECOND=$(echo "$command" | awk '{print $3}')
  72. echo "Doing "$command""
  73. eval "$command";
  74. done
  75. echo "Sending second snapshot"
  76. echo "Sending "$SNAP_TO_SEND_FIRST" to "$SNAP_TO_SEND_SECOND" with -I parameter"
  77. zfs send -I "$SNAP_TO_SEND_FIRST" "$SNAP_TO_SEND_SECOND" | lzop | pv | ssh "$DEST_IP" -p $DEST_PORT "lzop -d | zfs recv -o recordsize="$DATASET_RECORDSIZE_VAR" -o atime="$DATASET_ATIME_VAR" -o relatime="$DATASET_RELATIME_VAR" -o quota="$DATASET_QUOTA_VAR" "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR" -F"; (($? != 0)) && { echo "SSH command to send second snapshot exited with non-zero"; exit 1; }
  78. echo "Sleep 2"
  79. sleep 2
  80. echo "Creating third snapshot"
  81. for command in $(zfSnap -n -zpool28fix -a 7d "$DATASET_VAR" | grep snapshot | grep "$DATASET_VAR")
  82. do
  83. SNAP_TO_SEND_THIRD=$(echo "$command" | awk '{print $3}')
  84. echo "Doing "$command""
  85. eval "$command";
  86. done
  87. echo "Sending third snapshot"
  88. echo "Sending "$SNAP_TO_SEND_SECOND" to "$SNAP_TO_SEND_THIRD""
  89. zfs send -i "$SNAP_TO_SEND_SECOND" "$SNAP_TO_SEND_THIRD" | lzop | pv | ssh "$DEST_IP" -p $DEST_PORT "lzop -d | zfs recv -o recordsize="$DATASET_RECORDSIZE_VAR" -o atime="$DATASET_ATIME_VAR" -o relatime="$DATASET_RELATIME_VAR" -o quota="$DATASET_QUOTA_VAR" "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR" -F"; (($? != 0)) && { echo "SSH command to send third snapshot exited with non-zero"; exit 1; }
  90. echo "Sleep 2"
  91. sleep 2
  92. echo "Creating fourth snapshot"
  93. for command in $(zfSnap -n -zpool28fix -a 7d "$DATASET_VAR" | grep snapshot | grep "$DATASET_VAR")
  94. do
  95. SNAP_TO_SEND_FOURTH=$(echo "$command" | awk '{print $3}')
  96. echo "Doing "$command""
  97. eval "$command";
  98. done
  99. echo "Sending fourth snapshot"
  100. echo "Sending "$SNAP_TO_SEND_THIRD" to "$SNAP_TO_SEND_FOURTH""
  101. zfs send -i "$SNAP_TO_SEND_THIRD" "$SNAP_TO_SEND_FOURTH" | lzop | pv | ssh "$DEST_IP" -p $DEST_PORT "lzop -d | zfs recv -o recordsize="$DATASET_RECORDSIZE_VAR" -o atime="$DATASET_ATIME_VAR" -o relatime="$DATASET_RELATIME_VAR" -o quota="$DATASET_QUOTA_VAR" "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR" -F"; (($? != 0)) && { echo "SSH command to send fourth snapshot exited with non-zero"; exit 1; }
  102. echo "Sleep 2"
  103. sleep 2
  104. echo "Stopping "$CONT_VAR" on source"
  105. lxc stop "$CONT_VAR" --timeout 30; (($? != 0)) && echo "lxc stop timed-out after 30 seconds, doing with force parameter" && lxc stop "$CONT_VAR" --force
  106. echo "Sleep 2"
  107. sleep 2
  108. echo "Creating fifth snapshot"
  109. for command in $(zfSnap -n -zpool28fix -a 7d "$DATASET_VAR" | grep snapshot | grep "$DATASET_VAR")
  110. do
  111. SNAP_TO_SEND_FIFTH=$(echo "$command" | awk '{print $3}')
  112. echo "Doing "$command""
  113. eval "$command";
  114. done
  115. echo "Sending fifth snapshot"
  116. echo "Sending "$SNAP_TO_SEND_FOURTH" to "$SNAP_TO_SEND_FIFTH""
  117. zfs send -i "$SNAP_TO_SEND_FOURTH" "$SNAP_TO_SEND_FIFTH" | lzop | pv | ssh "$DEST_IP" -p $DEST_PORT "lzop -d | zfs recv -o recordsize="$DATASET_RECORDSIZE_VAR" -o atime="$DATASET_ATIME_VAR" -o relatime="$DATASET_RELATIME_VAR" -o quota="$DATASET_QUOTA_VAR" "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR" -F"; (($? != 0)) && { echo "SSH command to send fifth snapshot exited with non-zero"; exit 1; }
  118. if [ $bionic_checker == bionic ]
  119. then
  120. if [ -z "$SNAP_TO_SEND_FIRST_FOR_LATER_CHECK" ]
  121. then
  122. echo "Setting up mountpoint on destination for "$CONT_VAR""
  123. ssh "$DEST_IP" -p $DEST_PORT zfs set mountpoint=/var/lib/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR" "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR"; (($? != 0)) && { echo "SSH command to setup mountpoint on destination exited with non-zero"; exit 1; }
  124. echo "Fixing config for bionic"
  125. ssh "$DEST_IP" -p $DEST_PORT sed -i '/volatile.idmap.current/d' /var/lib/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR"/backup.yaml; (($? != 0)) && { echo "SSH command to setup volatile.idmap exited with non-zero"; exit 1; }
  126. ssh "$DEST_IP" -p $DEST_PORT sed -i '/volatile.uuid/d' /var/lib/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR"/backup.yaml; (($? != 0)) && { echo "SSH command to setup volatile.uuid exited with non-zero"; exit 1; }
  127. ssh "$DEST_IP" -p $DEST_PORT sed -i '/volatile.cloud-init.instance-id/d' /var/lib/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR"/backup.yaml; (($? != 0)) && { echo "SSH command to setup volatile.cloud-init.instance-id exited with non-zero"; exit 1; }
  128. ssh "$DEST_IP" -p $DEST_PORT sed -i '/volatile.last_state.ready/d' /var/lib/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR"/backup.yaml; (($? != 0)) && { echo "SSH command to setup volatile.last_state.ready exited with non-zero"; exit 1; }
  129. echo "Importing "$CONT_VAR" on destination"
  130. ssh "$DEST_IP" -p $DEST_PORT lxd import "$CONT_VAR" --force; (($? != 0)) && { echo "SSH command to import container exited with non-zero"; exit 1; }
  131. fi
  132. echo "Starting "$CONT_VAR" on destination"
  133. ssh "$DEST_IP" -p $DEST_PORT lxc start "$CONT_VAR"; (($? != 0)) && { echo "SSH command to start container exited with non-zero"; exit 1; }
  134. echo " "
  135. else
  136. if [ -z "$SNAP_TO_SEND_FIRST_FOR_LATER_CHECK" ]
  137. then
  138. echo "Setting up mountpoint on destination for "$CONT_VAR""
  139. target_snap_version=$(ssh "$DEST_IP" -p $DEST_PORT snap info lxd| grep tracking: | awk {'print $2'} | cut -d"/" -f-1 | cut -d"." -f-1); (($? != 0)) && { echo "SSH command to fill target_snap_version exited with non-zero"; exit 1; }
  140. if [[ "$target_snap_version" == 4 ]]
  141. then
  142. ssh "$DEST_IP" -p $DEST_PORT zfs set canmount=noauto "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR"; (($? != 0)) && { echo "SSH command to setup mountpoint on destination exited with non-zero"; exit 1; }
  143. ssh "$DEST_IP" -p $DEST_PORT zfs set mountpoint=/var/snap/lxd/common/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR" "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR"; (($? != 0)) && { echo "SSH command to setup mountpoint on destination exited with non-zero"; exit 1; }
  144. ssh "$DEST_IP" -p $DEST_PORT zfs mount "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR"; (($? != 0)) && { echo "SSH command to setup mountpoint on destination exited with non-zero"; exit 1; }
  145. REMOTE_LXD_PID=$(ssh "$DEST_IP" -p $DEST_PORT cat /var/snap/lxd/common/lxd.pid); (($? != 0)) && { echo "SSH command to get REMOTE_LXD_PID on destination exited with non-zero"; exit 1; }
  146. ssh "$DEST_IP" -p $DEST_PORT "nsenter -t $REMOTE_LXD_PID -m bash -c \"mount -t zfs "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR" /var/snap/lxd/common/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR"\""; (($? != 0)) && { echo "SSH command to set REMOTE_LXD_PID on destination exited with non-zero"; exit 1; }
  147. echo "Fixing config for lxd version 4"
  148. ssh "$DEST_IP" -p $DEST_PORT sed -i '/volatile.cloud-init.instance-id/d' /var/snap/lxd/common/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR"/backup.yaml; (($? != 0)) && { echo "SSH command to setup volatile.cloud-init.instance-id exited with non-zero"; exit 1; }
  149. ssh "$DEST_IP" -p $DEST_PORT sed -i '/volatile.last_state.ready/d' /var/snap/lxd/common/lxd/storage-pools/"$DEST_ZPOOL_2"/containers/"$CONT_VAR"/backup.yaml; (($? != 0)) && { echo "SSH command to setup volatile.last_state.ready exited with non-zero"; exit 1; }
  150. echo "Importing "$CONT_VAR" on destination"
  151. ssh "$DEST_IP" -p $DEST_PORT /snap/bin/lxd import "$CONT_VAR" --force; (($? != 0)) && { echo "SSH command to import container exited with non-zero"; exit 1; }
  152. ssh "$DEST_IP" -p $DEST_PORT zfs umount "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR"; (($? != 0)) && { echo "SSH command to import container exited with non-zero"; exit 1; }
  153. else
  154. echo "Doing lxd recover"
  155. ssh "$DEST_IP" -p $DEST_PORT zfs set mountpoint=legacy "$DEST_ZPOOL"/lxd/storage/containers/"$CONT_VAR"; (($? != 0)) && { echo "SSH command to setup mountpoint=legacy on destination exited with non-zero"; exit 1; }
  156. ssh "$DEST_IP" -p $DEST_PORT "cat <<EOF | lxd recover
  157. no
  158. yes
  159. yes
  160. EOF"; (($? != 0)) && { echo "SSH command lxd recover exited with non-zero"; exit 1; }
  161. fi
  162. fi
  163. echo "Starting "$CONT_VAR" on destination"
  164. ssh "$DEST_IP" -p $DEST_PORT /snap/bin/lxc start "$CONT_VAR"; (($? != 0)) && { echo "SSH command to start container exited with non-zero"; exit 1; }
  165. echo " "
  166. fi
  167. done