-
Notifications
You must be signed in to change notification settings - Fork 0
/
pve-zfs-clone
executable file
·183 lines (172 loc) · 8.7 KB
/
pve-zfs-clone
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/bin/bash
if [[ "$(zfs version | head -1 | cut -d '~' -f 1)" != "$(zfs version | tail -1 | cut -d '-' -f 1,3,4)" ]]
then
echo "Не соответствие версий ZFS, проверьте вывод команды 'zfs version'. Вероятно необходимо сделать перезагрузку сервера."
exit
fi
error () {
if [[ $1 = snapshot ]]
then
echo 'Ошибка при создании снапшота'
elif [[ $1 = snapshot_destroy ]]
then
echo 'Ошибка при удалении снапшота'
elif [[ $1 = zfsclone ]]
then
echo 'Ошибка при создании клона из снапшота'
elif [[ $1 = config ]]
then
echo 'Ошибка при создании конфига контейнера'
elif [[ $1 = destroyLXC ]]
then
echo 'Ошибка удаления LXC контейнера'
fi
exit
}
VAR=$(whiptail --title "Меню скрипта" --menu \
"Вас приветствует скрипт для удобного клонирования и управления клонами в Proxmox" 23 77 16 \
"1" "Клонировать" \
"2" "Обновить клон" \
"3" "Создать шаблон на основе снапшота" 3>&1 1>&2 2>&3) || exit
if [ $VAR -eq 1 ]
then
CLONE=$(whiptail --title "Что клонировать?" --menu \
"Выберите тип" 23 77 16 \
"1" "LXC" \
"2" "KVM" 3>&1 1>&2 2>&3) || exit
if [ $CLONE -eq 1 ]
then
list=()
while read VMID Name
do
list+=("$VMID" "$Name")
done < <(pct list | awk '{print $1,$3}' | awk 'FNR>1')
LXC=$(whiptail --title "Какой контейнер?" --menu \
"Выберите контейнер, если контейнера нет в списке запустите скрипт на хосте где расположен контейнер" 23 77 16 \
"${list[@]}" 3>&1 1>&2 2>&3) || exit
#проверяем, что контейнер не имеет нестандартных подключенных дисков
if [ "$(pct config $LXC | grep -E '(rootfs|mp[0-9]+): .*,size=[0-9]+' | cut -d ':' -f 3 | cut -d ',' -f 1 | grep $LXC | wc -l)" -eq "$(pct config $LXC | grep -E '(rootfs|mp[0-9]+): .*,size=[0-9]+' | cut -d ':' -f 3 | cut -d ',' -f 1 | wc -l)" ]
then
while [ true ]
do
NEWVMID=$(whiptail --title "Выбор VMID" --inputbox "Введите VMID для клона" 10 60 `pvesh get /cluster/nextid` 3>&1 1>&2 2>&3) || exit
#проверяем что пользователь указал не занятый ID
if [ $(cat /etc/pve/.vmlist | awk '{print $1}' | grep -E "$NEWVMID") ]
then
whiptail --title "Ошибка" --msgbox "VMID занят" 10 60
else
break
fi
done
pct snapshot $LXC VMID$NEWVMID || error snapshot
while read subvolume
do
zfs clone $(df | grep $subvolume | awk '{print $1}')@VMID$NEWVMID $(df | grep $subvolume | awk '{print $1}' | sed "s/$LXC/$NEWVMID/") || error zfsclone
done < <(pct config $LXC | grep -E '(rootfs|mp[0-9]+): .*,size=[0-9]+' | cut -d ':' -f 3 | cut -d ',' -f 1)
pct config $LXC | sed -E "s/(rootfs|mp[0-9]+)(: .*:.*)$LXC(.*,size=[0-9]+)/\1\2$NEWVMID\3/g" > /etc/pve/lxc/$NEWVMID.conf || error config
echo -e "\033[0m\n\033[0m\033[31m $LXC => $NEWVMID : контейнер успешно склонирован \033[0m"
# Change MAC if needed
if (whiptail --title "Test Yes/No Box" --yesno "Сгенерировать новый MAC адрес?" 10 60) then
pct config $NEWVMID | grep net0 | head -n 1 | awk 'gsub(/,hwaddr=[^,]+/, "")' | awk 'gsub(/net0:/, "")' | xargs -n 1 pct set $NEWVMID -net0
else
echo -e '\033[0m\n\033[0m\033[31mИсходный MAC адрес сохранен. Смените MAC и IP вручную, если это необходимо!!!\033[0m'
fi
else
echo 'Субволюм контейнера который Вы хотите склонировать не имеет в своём имени VMID контейнера. Выполните клонирование в ручном режиме или пересоздайте субволюмы с правильными именами.'
exit
fi
elif [ $CLONE -eq 2 ]
then
list=()
while read VMID Name
do
list+=("$VMID" "$Name")
done < <(qm list | awk '{print $1,$2}' | awk 'FNR>1')
LXC=$(whiptail --title "Какую VM?" --menu \
"Выберите VM, если VM нет в списке запустите скрипт на хосте где расположена VM" 23 77 16 \
"${list[@]}" \
"0" "Выход" 3>&1 1>&2 2>&3)
exitstatus=$?
if [ $exitstatus -eq 0 ]
then
echo 'Функционал ещё не реализован'
else
exit
fi
fi
elif [ $VAR -eq 2 ]
then
# Получаем список клонированных файловых систем
table=$(join \
<(sort <(pct list | tail -n +2 | awk '{print $1, "pct", $2, $3}' ; qm list | tail -n +2 | awk '{print $1, "qm", $3, $2}')) \
<(sort <(zfs list -H -o name,origin | awk '$2 != "-"' | awk 'match($1, /-[0-9][0-9][0-9]-disk/) { print substr($1, RSTART+1, 3), $0}' \
| awk 'match($3, /-[0-9][0-9][0-9]-disk/) { print $0, substr($3, RSTART+1, 3)}')))
#echo "table" #debug
#echo "$table" #debug
# Вычисляем клонированные виртуальные машины и контейнеры
# sort -u группирует строки с одинаковыми парами VMID, VMID_origin. Такие пары будут появляться если VMID имеет несколько склонированных zfs дисков
# uniq -u -f5 убирает строки с одинаковыми VMID. Такие строки могут получиться, если VMID имеет несколько склонированных zfs дисков из разных VMID_origin. Такие VMID мы пропускаем
table_vmid=$(echo "$table" | awk '{print $1, $2, $3, $4, $7, $1}' | sort -u | uniq -u -f5 )
#echo "table_vmid" #debug
#echo "$table_vmid" #debug
list=()
while read VMID Type State Name VMID_origin
do
list+=("$VMID" "$Name") # !!!! whiptail перестает работать после добавления других столбцов !!!!
done < <(echo "$table_vmid")
while [ true ]; do
LXC=$(whiptail --title "Какой контейнер?" --menu \
"Выберите контейнер, если контейнера нет в списке запустите скрипт на хосте где расположен контейнер" 23 77 16 \
"${list[@]}" 3>&1 1>&2 2>&3) || exit
# stop ct or vm if needed
type=$(echo "$table_vmid" | awk "\$1 == $LXC" | awk '{print $2}')
state=$(echo "$table_vmid" | awk "\$1 == $LXC" | awk '{print $3}')
#echo "type: $type" #debug
#echo "state: $state" #debug
if [ $state == "running" ]; then
$type stop $LXC
fi
zfs_clone_list=$(echo "$table" | awk "\$1 == $LXC" | awk '{print $5}')
#echo "zfs_clone_list: $zfs_clone_list" #debug
while read zfs; do
# destroy clone
# Следующая команда не выполнится, если целевая файловая система будет иметь дочерние клоны
# use -nvp for safe debug
zfs destroy -r $zfs
exitstatus=$?
if [ $exitstatus -ne 0 ]; then
whiptail --title "Ошибка" --msgbox "Вероятно файловая система имеет дочерние клоны, см. ошибку в консоли" 10 60
echo -e "\033[0m\n\033[0m\033[31mВероятно файловая система имеет дочерние клоны, см. ошибку в консоли\033[0m"
exit
fi
done < <(echo "$zfs_clone_list")
n=0
while read zfs; do
VMID_origin=$(echo "$table" | awk "\$5 == \"${zfs}\"" | awk '{print $7}')
zfs_snap_origin=$(echo "$table" | awk "\$5 == \"${zfs}\"" | awk '{print $6}')
# re-create snapshot on origin
if [ "$($type listsnapshot $VMID_origin 2> /dev/null | grep VMID$LXC)" ]; then
if [ $n -eq 0 ]
then
$type delsnapshot $VMID_origin VMID$LXC || error snapshot_destroy
$type snapshot $VMID_origin VMID$LXC || error snapshot
let n=$n+1
fi
else
zfs destroy -r $zfs_snap_origin || error snapshot_destroy
zfs snapshot $zfs_snap_origin || error snapshot
fi
zfs clone $zfs_snap_origin $zfs
done < <(echo "$zfs_clone_list")
#start stop ct or vm if needed
if [ $state == "running" ]; then
$type start $LXC
fi
whiptail --title "Успех" --msgbox "Клон $LXC успешно обновлен" 10 60
echo -e "\033[0m\n\033[0m\033[31mКлон $LXC успешно обновлен\033[0m"
exit # It seems to be more convenient, then unlimited for loop
done
elif [ $VAR -eq 3 ]
then
echo 'Функционал ещё не реализован'
fi