kvm-snapshot-dd.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. #!/bin/bash
  2. # The script is designed to create or restore an image of a virtual machine kvm (c) 2022
  3. # author Koshuba V.O.
  4. # license: MIT
  5. # version: 5.1.0
  6. ##
  7. #<manual_parameters>
  8. path_kvm=( "/kvm/vm1" "/kvm/vm2" ); # path kvm machines
  9. path_bak=( "/backup/kvm/vm1" "/backup/kvm/vm2" ); # path backup kvm machines
  10. img_dev=( '"sda.img"' '"sda.img" "sdb.img"' ) # storage kvm (vm1 - sda.img; vm2 - sda.img,sdb.img)
  11. #</manual_parameters>
  12. #<script_value>
  13. version="5.1.0";
  14. owner="(c) script by Koshuba V.O. 2021";
  15. msg_dat=( '"Script to save or restore the image KVM" "Скрипт сохранения или восстановления образа KVM"'
  16. '"MAIN MENU" "ГЛАВНОЕ МЕНЮ"'
  17. '"RESTORE KVM MACHINE" "ВОССТАНОВЛЕНИЕ ГОСТЕВОЙ МАШИНЫ KVM"'
  18. '"SAVE KVM MACHINE" "СОХРАНЕНИЕ ГОСТЕВОЙ МАШИНЫ KVM"'
  19. '"EXIT" "ВЫХОД"'
  20. '"Today:" "Сегодня:"'
  21. '"Available free space from Backup:" "Доступно свободного места в"'
  22. '"SAVE GUEST MACHINE KVM" "СОХРАНИТЬ ГОСТЕВУЮ МАШИНУ KVM"'
  23. '"RESTORE GUEST MACHINE KVM" "ВОССТАНОВИТЬ ГОСТЕВУЮ МАШИНУ KVM"'
  24. '"Quit the program" "Выйти из программы"'
  25. '"Select kvm machine" "Выберите машину KVM"'
  26. '"Select kvm image" "Выберите образ KVM"'
  27. '"{Space} key selection" "Выбор клавиша {Пробел}"'
  28. '"Not found dialog package, please install." "Не найден пакет: dialog, пожалуйста установите."'
  29. '"Found the file kvmsnapshot.lock - work is stopped!" "Найден файл kvmsnapshot.lok - работа остановлена!"'
  30. '"Starting kvm-snapshot script." "Запуск скрипта kvm-snapshot."'
  31. '"Ending work kvm-snapshot script." "Окончание работы скрипта kvm-snapshot."'
  32. '"Not found save images!" "Не найдены сохраненные образы!"'
  33. );
  34. # msg[17]
  35. msg=(); # set current messages
  36. esc_title=""; # title escape menu
  37. esc_msg=""; # message escape menu
  38. esc_menu=""; # return menu escape
  39. set_lang="0"; # lang messages
  40. menu_mode=""; # type menu select kvm
  41. set_kvm=""; # selected kvm for processing
  42. set_img=""; # selected image for restore kvm machine
  43. rdate=$(date +%d.%m.%y); # real data
  44. signlok="/tmp/run-kvmsnapshot.lok;"; # sign of work
  45. scriptlog="/var/log/vm.log"; # log file
  46. DIALOG=${DIALOG=dialog}; # dialog lib
  47. #<Define the dialog exit status codes>
  48. : ${DIALOG_OK=0}
  49. : ${DIALOG_CANCEL=1}
  50. : ${DIALOG_HELP=2}
  51. : ${DIALOG_EXTRA=3}
  52. : ${DIALOG_ITEM_HELP=4}
  53. : ${DIALOG_ESC=255}
  54. #</Define>
  55. scr_tmp=$(tempfile 2>/dev/null) || scr_tmp=/tmp/choise.tmp; # tmp file
  56. trap "rm -f $scr_tmp" 0 1 2 5 15;
  57. dform="/tmp/dform.tmp";
  58. #</script_value>
  59. #<functions_&_operations>
  60. operation_menu=( "clear" "getTools" "langMsg" "testproc" "sMainMenu" );
  61. operation_savekvm=( "clear" "saveKvm" "endproc" "exit" );
  62. operation_restorekvm=( "clear" "restoreKvm" "endproc" "exit" );
  63. operation_exit=( "clear" "endproc" "exit" );
  64. #</function_&_operations>
  65. #<tools_script>
  66. get_tools=( "pigz" "locale" "du" "gunzip" "dd" ); # tools for script
  67. #</tools_script>
  68. #<dialogs>
  69. function sMainMenu() {
  70. local check_dialog=$(apt-cache policy dialog | grep status|wc -m );
  71. if [[ $check_dialog = 0 ]];
  72. then
  73. echo -e "${msg[13]}";
  74. sleep 2
  75. exit 0
  76. fi
  77. #<esc_value>
  78. esc_title="${msg[4]}";
  79. esc_msg="${msg[9]}";
  80. esc_menu="sMainMenu";
  81. #</esc_value>
  82. $DIALOG --clear --backtitle " ${msg[0]} | $owner | version: $version" \
  83. --title "${msg[1]}" "$@" \
  84. --menu " ${msg[5]} $(date +%c) \n
  85. ==============================================\n
  86. \n" 20 51 5 \
  87. "1." "${msg[3]}" \
  88. "2." "${msg[2]}" \
  89. "3." "${msg[4]}" 2>$scr_tmp;
  90. input=$(cat $scr_tmp && rm -f $scr_tmp);
  91. case "$input" in
  92. "1." | "1." )
  93. menu_mode="${msg[7]}";
  94. menuSaveKVM;
  95. ;;
  96. "2." | "2." )
  97. menu_mode="${msg[8]}";
  98. menuRestoreKVM;
  99. ;;
  100. "3." | "3." )
  101. escScript
  102. ;;
  103. * )
  104. # default select
  105. escScript;
  106. ;;
  107. esac
  108. }
  109. function escScript() {
  110. $DIALOG --clear --backtitle " ${msg[0]} | $owner | version: $version"\
  111. --title "$esc_title"\
  112. --yesno "\n
  113. \n
  114. $esc_msg?" 10 50
  115. case $? in
  116. 0)
  117. clear;
  118. execute_func=( ${operation_exit[@]} );
  119. executor;
  120. exit 0;
  121. ;;
  122. 1)
  123. $esc_menu;
  124. ;;
  125. 255)
  126. $esc_menu;
  127. ;;
  128. esac
  129. }
  130. function menuSaveKVM() {
  131. formSetKVM;
  132. source $dform;
  133. slc="$?";
  134. set_kvm=$( echo $(($(cat $scr_tmp && rm -f $scr_tmp && rm -f $dform)-1)));
  135. case $slc in
  136. "0" | "0")
  137. clear;
  138. execute_func=( ${operation_savekvm[@]} );
  139. executor;
  140. ;;
  141. "1" | "1")
  142. sMainMenu;
  143. ;;
  144. "255" | "255")
  145. sMainMenu;
  146. ;;
  147. esac
  148. }
  149. function menuRestoreKVM() {
  150. formSetKVM;
  151. source $dform;
  152. slc="$?";
  153. set_kvm=$( echo $(($(cat $scr_tmp && rm -f $scr_tmp && rm -f $dform)-1)));
  154. case $slc in
  155. "0" | "0")
  156. clear;
  157. menuImg;
  158. ;;
  159. "1" | "1")
  160. sMainMenu;
  161. ;;
  162. "255" | "255")
  163. sMainMenu;
  164. ;;
  165. esac
  166. }
  167. function menuImg() {
  168. formSetImg;
  169. source $dform;
  170. slc="$?";
  171. set_img=$(cat $scr_tmp && rm -f $scr_tmp && rm -f $dform);
  172. case $slc in
  173. "0" | "0")
  174. clear;
  175. execute_func=( ${operation_restorekvm[@]} );
  176. executor;
  177. ;;
  178. "1" | "1")
  179. menuRestoreKVM;
  180. ;;
  181. "255" | "255")
  182. menuRestoreKVM;
  183. ;;
  184. esac
  185. }
  186. #</dialogs>
  187. #<functions>
  188. #<Fn test lock file>
  189. testproc(){
  190. if [ -f $scriptlog ];
  191. then
  192. echo > $scriptlog;
  193. fi
  194. if [ -f "$signlok" ];
  195. then
  196. echo "$(date) -- ${msg[14]}">>$scriptlog;
  197. exit 0;
  198. else
  199. echo '1'>$signlok; # up trigger
  200. echo "$(date) -- ${msg[15]}" >>$scriptlog;
  201. fi
  202. }
  203. endproc(){
  204. if [ -f $signlok ];
  205. then
  206. rm -f $signlok;
  207. fi
  208. echo "$(date) -- ${msg[16]}" >> $scriptlog;
  209. }
  210. #<Fn_executor>
  211. function executor() {
  212. if [[ ${#execute_func[@]} -eq 0 ]]
  213. then echo "exit";
  214. exit 0;
  215. fi
  216. for ((ex_index=0; ex_index != ${#execute_func[@]}; ex_index++))
  217. do
  218. ## !! debug operation...
  219. ##echo "execution: function ${execute_func[ex_index]}"
  220. ${execute_func[ex_index]};
  221. done
  222. }
  223. #<Fn_get-tools>
  224. function getTools() {
  225. for ((itools=0; itools != ${#get_tools[@]}; itools++))
  226. do
  227. eval get_${get_tools[$itools]}=$(whereis -b ${get_tools[$itools]}|awk '/^'${get_tools[$itools]}':/{print $2}');
  228. list_tools[${#list_tools[@]}]="$(whereis -b ${get_tools[$itools]}|awk '/^'${get_tools[$itools]}':/{print $2}')";
  229. done
  230. }
  231. #<Fn_get-lang>
  232. function langMsg() {
  233. if [[ ! $($get_locale|grep 'LANG='|sed 's/\LANG=//g'|grep 'ru_RU.UTF-8'|wc -m) -eq 0 ]];
  234. then
  235. set_lang="1";
  236. else
  237. set_lang="0";
  238. fi
  239. for ((ilang=0; ilang != ${#msg_dat[@]}; ilang++))
  240. do
  241. eval tmsg="(" $(echo -e ${msg_dat[$ilang]}) ")";
  242. msg[$ilang]=${tmsg[$set_lang]};
  243. done
  244. }
  245. function formSetKVM() {
  246. echo>$dform;
  247. echo '$DIALOG --backtitle " '${msg[0]}' | '$owner'" \'>>$dform
  248. echo ' --title "'$menu_mode'" --clear \' >>$dform
  249. echo ' --radiolist "\n '${msg[10]}'"' '20 60 '${#path_kvm[@]}' \' >>$dform
  250. #<input_list>
  251. if [[ ${#path_kvm[@]} = 0 ]];
  252. then
  253. echo " don't find KVM!"
  254. sleep 1;
  255. rm -f $dform;
  256. exit 0;
  257. fi
  258. for ((ilist=0; ilist != ${#path_kvm[@]}; ilist++))
  259. do
  260. local fmark='';
  261. local dmark='';
  262. if [[ $ilist = 0 ]];
  263. then
  264. fmark='ON';
  265. else
  266. fmark='off';
  267. fi
  268. if [[ ! $ilist = $(echo $((${#path_kvm[@]} -1))) ]];
  269. then
  270. dmark='\';
  271. else
  272. dmark='2> $scr_tmp';
  273. fi
  274. echo -e '"'"$(echo $(($ilist+1)))"'"' '"'"${path_kvm[$ilist]}"'"' $fmark $dmark >>$dform;
  275. done
  276. }
  277. function formSetImg() {
  278. local get_path_bak=${path_bak[$set_kvm]};
  279. eval local get_imgs="(" $(find "$get_path_bak"/* -maxdepth 0 -type d -printf '%f\n') ")";
  280. echo>$dform;
  281. echo '$DIALOG --backtitle " '${msg[0]}' | '$owner'" \'>>$dform
  282. echo ' --title "'$menu_mode'" --clear \' >>$dform
  283. echo ' --radiolist " '${msg[11]}': '$get_path_bak'\n '${msg[12]}'"' '20 60 '${#get_imgs[@]}' \' >>$dform
  284. #<input_list>
  285. if [[ ${#get_imgs[@]} = 0 ]];
  286. then
  287. rm -f $dform;
  288. #<esc_value>
  289. esc_title="${msg[4]}";
  290. esc_msg="${msg[17]} \n ${msg[9]}";
  291. esc_menu="menuRestoreKVM";
  292. #</esc_value>
  293. escScript;
  294. fi
  295. for ((iget=0; iget != ${#get_imgs[@]}; iget++))
  296. do
  297. local fmark='';
  298. local dmark='';
  299. if [[ $iget = 0 ]];
  300. then
  301. fmark='ON';
  302. else
  303. fmark='off';
  304. fi
  305. if [[ ! $iget = $(echo $((${#get_imgs[@]} -1))) ]];
  306. then
  307. dmark='\';
  308. else
  309. dmark='2> $scr_tmp';
  310. fi
  311. echo -e '"'"${get_imgs[$iget]}"'"' '""' $fmark $dmark >>$dform;
  312. done
  313. }
  314. function saveKvm() {
  315. local save_kvm="${path_kvm[$set_kvm]}";
  316. local save_bak="${path_bak[$set_kvm]}/$rdate"
  317. eval set_images="(" ${img_dev[$set_kvm]} ")";
  318. for ((step_i=0; step_i != ${#set_images[@]}; step_i++))
  319. do
  320. local save_img=$(echo "${set_images[$step_i]}"|sed 's/\./ /g'|awk '{print$1}');
  321. local set_loop_main="$(losetup -f|grep -v loop-control|sed 's/\/\dev\///g')";
  322. losetup /dev/$set_loop_main $save_kvm/$save_img.img;
  323. if [[ ! -d $save_bak ]];
  324. then
  325. mkdir -p $save_bak;
  326. fi
  327. sfdisk -d /dev/$set_loop_main >$save_bak/$save_img-info_sfdisk.txt;
  328. sfdisk -l /dev/$set_loop_main >$save_bak/$save_img-info_disk.txt;
  329. dd if=/dev/$set_loop_main status=progress |pigz -p4 -M -c9>$save_bak/$save_img-dd.img.gz;
  330. losetup -d /dev/$set_loop_main;
  331. done
  332. }
  333. function restoreKvm() {
  334. local rest_kvm="${path_kvm[$set_kvm]}";
  335. local rest_path="${path_bak[$set_kvm]}/$set_img";
  336. eval set_reimages="(" ${img_dev[$set_kvm]} ")";
  337. ##
  338. for ((step_i=0; step_i != ${#set_reimages[@]}; step_i++))
  339. do
  340. local rest_img=$(echo "${set_reimages[$step_i]}"|sed 's/\./ /g'|awk '{print$1}');
  341. local rest_bak="$rest_path/$rest_img-dd.img.gz";
  342. local set_loop_rmain="$(losetup -f|grep -v loop-control|sed 's/\/\dev\///g')";
  343. losetup /dev/$set_loop_rmain $rest_kvm/$rest_img.img;
  344. pigz -p4 -c -d -M $rest_bak|dd of=/dev/$set_loop_rmain status=progress;
  345. losetup -d /dev/$set_loop_rmain;
  346. done
  347. }
  348. #</functions>
  349. execute_func=( ${operation_menu[@]} );
  350. executor;