kvm-snapshot.sh 11 KB

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