kvm-snapshot.sh 9.9 KB

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