-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathqubes-update-all
executable file
·288 lines (270 loc) · 11.2 KB
/
qubes-update-all
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#!/bin/bash
while [[ "${#}" -gt "0" ]]; do
case "${1}" in
--all|-A)
autoclean="1"
autoremove="1"
trim="1"
upgrade_dom0="1"
shift
;;
--autoclean|-ac)
autoclean="1"
shift
;;
--autoremove|-ar)
autoremove="1"
shift
;;
--dom0|-d)
upgrade_dom0="1"
shift
;;
--help|-h)
printf "%s\n" "
Usage: "${0}" [options]
Options:
--all, -A = all options
--autoclean, -ac = autoclean
--autoremove, -ar = autoremove
--dom0, -d = upgrade dom0
--trim, -t = trim
--help, -h = help menu
"
exit 0
;;
--trim|-t)
trim="1"
shift
;;
*)
break
;;
esac
done
## Set update VM.
## If empty, the gateway of the first TemplateVM (in alphabetical order) will be used.
updatevm="gateway-update"
## Log output dir and file.
## If left empty a dir and file will be created in current dir.
logdir="/home/user/update-all-templates-log/"
logfile="/home/user/update-all-templates-log/update-all-templates.log"
## Set variables if empty.
if [[ -z "${updatevm}" ]]; then
updatevm=$(qvm-ls --raw-data -O name,class,netvm | grep "TemplateVM" | grep -v \|\- | head -1 | cut -d"|" -f 3)
fi
if [[ -z "${logdir}" ]]; then
logdir="$(pwd)/qubes-update-all-log/"
fi
if [[ -z "${logfile}" ]]; then
logfile="${logdir}"update-all-templates.log
fi
if [[ ! -e "${logdir}" ]]; then
mkdir -p "${logdir}"
fi
## Rotate old logfile if it exists.
if [[ -e "${logfile}" && ! -z $(head "${logfile}") ]]; then
mv "${logfile}" "${logfile}".old
touch "${logfile}"
else
touch "${logfile}"
fi
## Print enabled options.
clear
printf "%s\n" "Updating all TemplateVMs and StandaloneVMs.
Options enabled:"
if [[ "${autoremove}" -eq "1" ]]; then
printf "[+] AUTOREMOVE ENABLED\n"
fi
if [[ "${autoclean}" -eq "1" ]]; then
printf "[+] AUTOCLEAN ENABLED\n"
fi
if [[ "${trim}" -eq "1" ]]; then
printf "[+] TRIM ENABLED\n"
fi
if [[ "${upgrade_dom0}" -eq "1" ]]; then
printf "[+] UPGRADE DOM0 ENABLED\n"
fi
## Start update VM, wait for Tor.
printf "\nStarting update VM and waiting for Tor to connect...\n\n"
if [[ $(qvm-ls --raw-data -O state "${updatevm}" | grep -c "Running") -ne "1" ]]; then
updatevm_was_running="0"
else
updatevm_was_running="1"
fi
qvm-start -q --skip-if-running "${updatevm}"
tor_count="0"
tor_restart_count="0"
while [[ $(qvm-run -u root -p "${updatevm}" 'grep "$(date -u +%b\ %d)" /var/log/tor/log' | grep -c -e "Bootstrapped 100%") -lt "1" ]]; do
sleep 1
tor_count=$((tor_count+1))
if [[ "${updatevm_was_running}" -eq "1" && "${tor_count}" -eq "30" ]]; then
qvm-run -u root -p "${updatevm}" 'systemctl restart [email protected]'
tor_count="0"
fi
if [[ "${tor_count}" -ge "180" ]]; then
tor_restart_count=$((tor_restart_count+1))
printf "\n[!][!] RESTARTING TOR IN GATEWAY-UPDATE. ATTEMPT: "${tor_restart_count}" / 5 [!][!]\n\n"
qvm-run -u root -p "${updatevm}" 'systemctl restart [email protected]'
tor_count="0"
if [[ "${tor_restart_count}" -ge "5" ]]; then
printf "\n[!][!] COULD NOT RESTART TOR, CHECK NETWORK. EXITING. [!][!]\n" | tee -a "${logfile}"
exit 1
fi
fi
done
## Upgrade Debian based TemplateVM's.
for vm in $(qvm-ls --fields name,netvm --raw-data --tags debian whonix-updatevm | grep "gateway-" | cut -d "|" -f 1 | sort); do
printf "\n[+] Starting upgrade for VM "${vm}" at $(date +%x-%T).\n\n" | tee -a "${logfile}"
## Check if vm was running.
if [[ $(qvm-ls --raw-data -O state "${vm}" | grep -c "Running") -ne "1" ]]; then
vm_was_running="0"
else
vm_was_running="1"
fi
## Start vm, wait for it.
qvm-start -q --skip-if-running "${vm}"
while [[ $(qvm-ls --fields name,state,class --raw-data --tags debian whonix-updatevm | grep "${vm}" | grep -c "Running") -ne "1" ]]; do
sleep 1
done
## Start apt update. Give 5 retries.
aborted_update="0"
update_count="0"
qvm-run -q --nogui -p -u root "${vm}" 'export DEBIAN_FRONTEND="noninteractive" TERM="vt100"; timeout 10m apt update -o Languages=none -o Acquire::IndexTargets::deb::Contents-deb::DefaultEnabled=false; printf "Exit code: $?\n"' | tee -a "${logfile}"
while [[ $(tail -1 "${logfile}" | sed 's|Exit\ code\:\ ||') -ne "0" ]] ; do
update_count=$((update_count+1))
printf "\n[!][!] UPDATE FAILED FOR: "${vm}". RETRY ATTEMPT $update_count / 5. [!][!]\n\n" | tee -a "${logfile}"
sleep 10
qvm-run --nogui -p -q -u root "${vm}" 'export DEBIAN_FRONTEND="noninteractive" TERM="vt100"; timeout 10m sudo apt update -o Languages=none -o Acquire::IndexTargets::deb::Contents-deb::DefaultEnabled=false; printf "Exit code: $?\n"' | tee -a "${logfile}"
if [[ "$update_count" -ge "5" ]]; then
printf "\n[!][!] UPDATE FOR VM: "${vm}" WAS NOT SUCCESSFUL AFTER 5 RETRY ATTEMPTS. ABORTING. [!][!]\n\n" | tee -a "${logfile}"
aborted_update="1"
break
fi
done
## Start apt dist-upgrade if update was successful. Give 5 retries.
if [[ "$aborted_update" -eq "0" ]]; then
aborted_upgrade="0"
upgrade_count="0"
qvm-run --nogui -p -q -u root "${vm}" 'export DEBIAN_FRONTEND="noninteractive" TERM="vt100"; apt dist-upgrade -V -y -q -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Progress-Fancy="1"; printf "Exit code: $?\n"' | tee -a "${logfile}"
while [[ $(tail -1 "${logfile}" | sed 's|Exit\ code\:\ ||') -ne "0" ]]; do
upgrade_count=$((upgrade_count+1))
printf "\n[!][!] UPGRADE FAILED FOR VM: "${vm}". RETRY ATTEMPT "${upgrade_count}" / 5. [!][!]\n\n" | tee -a "${logfile}"
sleep 5
qvm-run --nogui -p -q -u root "${vm}" 'export DEBIAN_FRONTEND="noninteractive" TERM="vt100"; apt dist-upgrade -V -y -q -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Progress-Fancy="1"; printf "Exit code: $?\n"' | tee -a "${logfile}"
if [[ "$upgrade_count" -ge "5" ]]; then
printf "\n[!][!] UPGRADE FOR VM: "${vm}" WAS NOT SUCCESSFUL AFTER 5 RETRY ATTEMPTS. ABORTING. [!][!]\n\n" | tee -a "${logfile}"
aborted_upgrade="1"
break
fi
done
fi
## Start autoremove. Should only need one try, but we give 5 retries.
if [[ "${aborted_update}" -eq "0" && "${aborted_upgrade}" -eq "0" && "${autoremove}" -eq "1" ]]; then
autoremove_count="0"
qvm-run --nogui -p -q -u root "${vm}" 'export DEBIAN_FRONTEND="noninteractive" TERM="vt100"; apt autoremove -y; printf "Exit code: $?\n"' | tee -a "${logfile}"
while [[ $(tail -1 "${logfile}" | sed 's|Exit\ code\:\ ||') -ne "0" ]]; do
autoremove_count=$((autoremove_count+1))
sleep 10
qvm-run --nogui -p -q -u root "${vm}" 'export DEBIAN_FRONTEND="noninteractive" TERM="vt100"; apt autoremove -y; printf "Exit code: $?\n"' | tee -a "${logfile}"
if [[ "$autoremove_count" -ge "5" ]]; then
printf "\n[!][!] AUTOREMOVE FOR VM: "${vm}" WAS NOT SUCCESSFUL AFTER RETRY 5 ATTEMPTS. ABORTING. [!][!]\n\n" | tee -a "${logfile}"
break
fi
done
fi
## Start autoclean. Should only need one try, but we give 5 retries.
if [[ "${aborted_update}" -eq "0" && "${aborted_upgrade}" -eq "0" && "${autoclean}" -eq "1" ]]; then
autoclean_count="0"
qvm-run --nogui -p -q -u root "${vm}" 'export DEBIAN_FRONTEND=noninteractive TERM="vt100"; apt autoclean -y; printf "Exit code: $?\n"' | tee -a "${logfile}"
while [[ $(tail -1 "${logfile}" | sed 's|Exit\ code\:\ ||') != "0" ]]; do
autoclean_count=$((autoremove_count+1))
sleep 10
qvm-run --nogui -p -q -u root "${vm}" 'export DEBIAN_FRONTEND="noninteractive" TERM="vt100"; apt autoclean -y; printf "Exit code: $?\n"' | tee -a "${logfile}"
if [[ "${autoclean_count}" -ge "5" ]]; then
printf "\n[!][!] AUTOCLEAN FOR VM: "${vm}" WAS NOT SUCCESSFUL AFTER RETRY 5 ATTEMPTS. ABORTING. [!][!]\n\n" | tee -a "${logfile}"
break
fi
done
fi
## Trim vm.
if [[ "${trim}" -eq "1" ]]; then
qvm-run --nogui -p -q -u root "${vm}" "fstrim -v -a"
fi
## Shutdown vm.
if [[ "${vm_was_running}" = "0" ]]; then
qvm-shutdown -q "${vm}"
else
qvm-shutdown --wait --timeout 20 "${vm}"
sleep 2s
qvm-start "${vm}"
fi
printf "\n[-] Finished upgrade for VM "${vm}" at $(date +%x-%T).\n\n" | tee -a "${logfile}"
done
## Upgrade Fedora based TemplateVM's.
for vm in $(qvm-ls --fields name,netvm --raw-data --tags fedora | grep "gateway-" | cut -d "|" -f 1 | sort); do
printf "\n[+] Starting upgrade for VM "${vm}" at $(date +%x-%T).\n\n" | tee -a "${logfile}"
## Check if vm was running.
if [[ $(qvm-ls --raw-data -O state "${vm}" | grep -c "Running") -ne "1" ]]; then
vm_was_running="0"
else
vm_was_running="1"
fi
## Start vm, wait for it.
qvm-start -q --skip-if-running "${vm}"
while [[ $(qvm-ls --fields name,state,class --raw-data --tags fedora | grep "${vm}" | grep -c "Running") -ne "1" ]]; do
sleep 1
done
upgrade_count="0"
qvm-run --nogui -p -q -u root "${vm}" 'export TERM="vt100"; dnf upgrade --allowerasing --best --enablerepo=qubes-vm-r4.0-current-testing --refresh -v -y; printf "Exit code: $?\n"' | tee -a "${logfile}"
while [[ $(tail -1 "${logfile}" | sed 's|Exit\ code\:\ ||') != "0" && $(tail -1 "${logfile}" | sed 's|Exit\ code\:\ ||') != "Complete!" ]]; do
upgrade_count=$((upgrade_count+1))
printf "\n[!][!] UPGRADE FAILED FOR VM: "${vm}". RETRY ATTEMPT "${upgrade_count}" / 5. [!][!]\n\n" | tee -a "${logfile}"
sleep 10
qvm-run --nogui -p -q -u root "${vm}" 'export TERM="vt100"; dnf upgrade --allowerasing --best --enablerepo=qubes-vm-r4.0-current-testing --refresh -v -y' | tee -a "${logfile}"
if [[ "${upgrade_count}" -ge "5" ]]; then
printf "\n[!][!] UPGRADE FOR VM: "${vm}" WAS NOT SUCCESSFUL AFTER 5 ATTEMPTS. ABORTING. [!][!]\n\n" | tee -a "${logfile}"
break
fi
done
## Trim vm.
if [[ "${trim}" -eq "1" ]]; then
qvm-run --nogui -p -q -u root "${vm}" "fstrim -v -a"
fi
## Shutdown vm.
if [[ "${vm_was_running}" = "0" ]]; then
qvm-shutdown -q "${vm}"
else
qvm-shutdown --wait --timeout 20 "${vm}"
sleep 2s
qvm-start "${vm}"
fi
printf "\n[-] Finished upgrade for VM ${vm} at $(date +%x-%T).\n\n" | tee -a "${logfile}"
done
# Dom0 upgrade.
if [[ "${upgrade_dom0}" -eq "1" ]]; then
printf "\n[+] Starting upgrade for dom0 at $(date +%x-%T).\n\n" | tee -a "${logfile}"
dom0update_count="0"
set -o pipefail
sudo qubes-dom0-update --clean --enablerepo=qubes-dom0-current-testing --enablerepo=qubes-templates-community --enablerepo=qubes-templates-itl-testing -v -y | tee -a "${logfile}"
while [[ "${?}" -ne "0" && $(tail -5 "${logfile}" | grep -c "Nothing to download") -lt "1" ]]; do
sudo qubes-dom0-update --enablerepo=qubes-dom0-current-testing --enablerepo=qubes-templates-community --enablerepo=qubes-templates-itl-testing -v -y | tee -a "${logfile}"
dom0update_count=$((dom0update_count+1))
if [[ "${dom0update_count}" -ge "5" ]]; then
printf "\n[!][!] UPGRADE FOR dom0 WAS NOT SUCCESSFUL AFTER 5 ATTEMPTS. ABORTING. [!][!]\n\n" | tee -a "${logfile}"
break
fi
done
set +o pipefail
printf "\n[-] Finished upgrade for dom0 at $(date +%x-%T).\n\n" | tee -a "${logfile}"
fi
## Trim dom0.
if [[ "${trim}" -eq "1" ]]; then
sudo fstrim -v /
fi
# Shutdown update vms.
if [[ "${updatevm_was_running}" -eq "0" ]]; then
printf "\nShutting down update VMs...\n\n"
qvm-shutdown -q --wait --timeout 20 "${updatevm}"
fi
exit 0