Última atividade 1751466336

Скрипт бэкапа проксмоксовых VM/LXC с сохранением конфигурации и примечаний к виртуалке

Revisão 0dd2af3e629a95c13d15e32f07cacb07579bf9e3

vzbackup.sh Bruto
1#!/bin/bash
2
3# Цвета для вывода
4VERSION='1.0'
5RED='\033[0;31m'
6GREEN='\033[0;32m'
7YELLOW='\033[1;33m'
8BLUE='\033[0;34m'
9NC='\033[0m' # No Color
10
11echo -e "${GREEN}Proxmox VM/LXC Backup script${NC}, (c) Karel Wintersky, 2025"
12
13# Функция вывода справки
14print_usage() {
15 echo -e "${YELLOW}Использование:${NC} $0 <VMID> [OPTIONS]"
16 echo -e "${YELLOW}Примеры:${NC}"
17 echo " $0 100 --mode stop --compress zstd --storage migration"
18 echo " $0 101 --mode snapshot --storage backup"
19 echo
20 echo -e "${YELLOW}Параметры:${NC}"
21 echo " --mode MODE Режим бэкапа (stop, snapshot). По умолчанию: stop"
22 echo " --compress ALG Алгоритм сжатия (zstd, gzip, lzo). По умолчанию: zstd"
23 echo " --storage NAME Имя хранилища. Если не указано, будет использовано хранилище по умолчанию"
24 echo
25 echo -e "${YELLOW}Storages:${NC}"
26 print_pvesm_free_space
27 echo
28 exit 1
29}
30
31function print_pvesm_free_space() {
32 # Получаем данные один раз и сохраняем
33 local pvesm_output
34 pvesm_output=$(pvesm status | tail -n +2)
35
36 # Определяем максимальную длину имени хранилища
37 local max_len=0
38 while read -r line; do
39 local storage_name
40 storage_name=$(awk '{print $1}' <<< "$line")
41 if (( ${#storage_name} > max_len )); then
42 max_len=${#storage_name}
43 fi
44 done <<< "$pvesm_output"
45 ((max_len+=2))
46
47 # Выводим данные с выравниванием
48 while read -r line; do
49 local storage_name available_kb available_gb
50 storage_name=$(awk '{print $1}' <<< "$line")
51 available_kb=$(awk '{print $5}' <<< "$line")
52 available_gb=$(bc <<< "scale=2; $available_kb / 1048576")
53
54 printf " %-${max_len}s : %s GB free\n" "$storage_name" "$available_gb"
55 done <<< "$pvesm_output"
56}
57
58# Проверка наличия минимального количества аргументов
59if [ "$#" -lt 1 ]; then
60 echo
61 echo -e "${RED}ОШИБКА: Не указан обязательный параметр VMID${NC}"
62 echo
63 print_usage
64fi
65
66# Установка значений по умолчанию
67MODE="snapshot"
68COMPRESS="zstd"
69STORAGE_NAME="local"
70
71# Парсинг остальных аргументов
72while [ "$#" -gt 0 ]; do
73 case "$1" in
74 -h|--help)
75 print_usage
76 exit 1
77 ;;
78 --mode)
79 MODE="$2"
80 if [[ ! "$MODE" =~ ^(stop|snapshot)$ ]]; then
81 echo -e "${RED}ОШИБКА: Недопустимый режим '$MODE'. Допустимые значения: stop, snapshot${NC}"
82 exit 1
83 fi
84 shift 2
85 ;;
86 --compress)
87 COMPRESS="$2"
88 if [[ ! "$COMPRESS" =~ ^(zstd|gzip|lzo)$ ]]; then
89 echo -e "${RED}ОШИБКА: Недопустимый алгоритм сжатия '$COMPRESS'. Допустимые значения: zstd, gzip, lzo${NC}"
90 exit 1
91 fi
92 shift 2
93 ;;
94 --storage)
95 STORAGE_NAME="$2"
96 shift 2
97 ;;
98 *)
99 # Парсинг аргументов
100 VMID="$1"
101 shift
102
103 # echo -e "${RED}ОШИБКА: Неизвестный параметр '$1'${NC}"
104 # print_usage
105 ;;
106 esac
107done
108
109NODE_NAME=$(hostname)
110
111# Проверяем, что storage существует (если указано)
112if [ -n "$STORAGE_NAME" ] && ! pvesm status | grep -qw "^${STORAGE_NAME}"; then
113 echo -e "${RED}ОШИБКА: Хранилище '${STORAGE_NAME}' не найдено!${NC}"
114 echo -e "${YELLOW}Доступные хранилища:${NC}"
115 pvesm status | awk '{print $1}'
116 exit 1
117fi
118
119# Определяем тип (qemu или lxc) и конфигурационный файл
120if [ -f "/etc/pve/nodes/${NODE_NAME}/qemu-server/${VMID}.conf" ]; then
121 VM_TYPE="qemu"
122 CONFIG_FILE="/etc/pve/nodes/${NODE_NAME}/qemu-server/${VMID}.conf"
123 echo -e "${GREEN}Найдена виртуальная машина (QEMU) с ID ${VMID}${NC}"
124elif [ -f "/etc/pve/nodes/${NODE_NAME}/lxc/${VMID}.conf" ]; then
125 VM_TYPE="lxc"
126 CONFIG_FILE="/etc/pve/nodes/${NODE_NAME}/lxc/${VMID}.conf"
127 echo -e "${GREEN}Найден контейнер (LXC) с ID ${VMID}${NC}"
128else
129 echo -e "${RED}ОШИБКА: Не найдена VM/LXC с ID ${VMID}!${NC}"
130 exit 1
131fi
132
133# Формируем команду vzdump
134VZDUMP_CMD="vzdump ${VMID} --mode ${MODE} --compress ${COMPRESS}"
135if [ -n "$STORAGE_NAME" ]; then
136 VZDUMP_CMD+=" --storage ${STORAGE_NAME}"
137 echo -e "${BLUE}Используем указанное хранилище:${NC} ${GREEN}${STORAGE_NAME}${NC}"
138else
139 echo -e "${BLUE}Используем хранилище по умолчанию${NC}"
140fi
141
142echo -e "${YELLOW}Выполняем команду:${NC} ${VZDUMP_CMD}"
143
144# Создаем бэкап и перехватываем вывод
145echo -e "${BLUE}Создаем бэкап ${VM_TYPE} ${VMID}...${NC}"
146echo -e "Режим: ${GREEN}${MODE}${NC}"
147echo -e "Сжатие: ${GREEN}${COMPRESS}${NC}"
148
149BACKUP_LOG=$(eval ${VZDUMP_CMD} | tee >(cat >&2) )
150
151if [ $? -ne 0 ]; then
152 echo -e "${RED}ОШИБКА: Не удалось создать бэкап!${NC}"
153 echo -e "${YELLOW}Подробности:${NC}"
154 echo "$BACKUP_LOG"
155 exit 1
156fi
157
158# Извлекаем имя файла бэкапа
159BACKUP_FILE=$(echo "$BACKUP_LOG" | grep -oP "creating vzdump archive '\K[^']*")
160
161if [ -z "$BACKUP_FILE" ]; then
162 echo -e "${RED}ОШИБКА: Не удалось определить путь к бэкапу!${NC}"
163 echo -e "${YELLOW}Полный вывод vzdump:${NC}"
164 echo "$BACKUP_LOG"
165 exit 1
166fi
167
168# Копируем конфигурационный файл
169BACKUP_BASENAME=$(basename "${BACKUP_FILE}" .vma.zst)
170CONFIG_COPY="${BACKUP_FILE%.*}.conf"
171cp "${CONFIG_FILE}" "${CONFIG_COPY}"
172echo -e "${GREEN}Конфигурация сохранена в ${NC} ${CONFIG_COPY}${NC}"
173
174# Сохраняем заметки (комментарии и description) в .md файл
175# NOTES=$(grep -E '^#|^description:' "${CONFIG_FILE}" | sed 's/^#//; s/^description: //')
176NOTES=$(grep -E '^#|^description:' "${CONFIG_FILE}" | sed 's/^#//; s/^description: //' | sed -e 's/%3A/:/g' -e 's/%2F/\//g')
177if [ -n "${NOTES}" ]; then
178 NOTES_FILE="${BACKUP_FILE%.*}.md"
179 echo -e "## Proxmox Notes for ${VM_TYPE} ${VMID}\n\n${NOTES}" > "${NOTES_FILE}"
180 echo -e "${GREEN}Заметки сохранены в ${NC} ${NOTES_FILE}"
181else
182 echo -e "${YELLOW}Нет заметок для ${VM_TYPE} ${VMID}${NC}"
183fi
184
185echo -e "${GREEN}Бэкап успешно создан:${NC} ${BACKUP_FILE}"
186