Per official documentation, it is recommended that users download latest templates through qvm-template
before “switching” everything from a pre-existing template to the newer template. qvm-prefs
allows for a somewhat seamless transition of preferences. But inheritance and persistence is a bit more complicated for the non-technical user.
This makes upgrading-in-place a very attractive option for new and experienced users alike. Fedrora documentation and Debian documentation suggest this process is for the “advanced” user. This should not be the case.
The solution you’d like
Include as a qubes command the option to “upgrade-in-place” a template, perhaps qvm-upgrade-debian
and qvm-upgrade-fedora
. I’ve provided basic Bash scripts for doing so, with an option for upgrading multiple templates of the same distro at once:
For Fedora-based templates.
For Debian-based templates.
At present, both scripts were tested successfully for upgrading Fedora-37 to Fedora-38 and Debian-11 to Debian-12. These scripts might also benefit from qvm-clone
commands to create .bak templates and a help/usage function.
Deb Upgrader
#!/bin/env bash
# A simple script for updating Debian templates in QubesOS
# Debian 12 "Bookworm"
# Debian 13 "Trixie"
PREFIX="$(tput setaf 7)$(tput bold)"
YELLOW="$(tput setaf 3)$(tput bold)"
POSTFIX="$(tput sgr0)"
TAB="$(echo -e '\t')"
message() {
echo "${PREFIX}${1}${POSTFIX}"
}
upgrade_template() {
local template=$1
local proceed=$2
local clone=$3
local new_template_name=$4
local old_name=$5
local new_name=$6
vm_exists=$(qvm-ls | grep -w "$template")
if [[ -z $vm_exists ]]; then
message "Template $template does not exist."
exit 1
fi
if [[ $proceed != "y" ]]; then
message "Skipping $template without changes."
return 0
fi
if [[ $clone == "y" ]]; then
qvm-clone $template $new_template_name
else
new_template_name=$template
fi
message "Upgrading $new_template_name"
qvm-run -a $new_template_name gnome-terminal
message "Updating APT repositories..."
qvm-run -p $new_template_name "sudo sed -i 's/$old_name/$new_name/g' /etc/apt/sources.list"
qvm-run -p $new_template_name "sudo sed -i 's/$old_name/$new_name/g' /etc/apt/sources.list.d/qubes-r4.list"
message "Performing upgrade..."
qvm-run -p $new_template_name "sudo apt update && sudo apt upgrade && sudo apt dist-upgrade -y"
qvm-run -p $new_template_name "sudo apt-get autoremove && sudo apt-get clean"
message "Trimming the new template..."
qvm-run -p $new_template_name "sudo fstrim -av"
qvm-shutdown $new_template_name
qvm-start $new_template_name
qvm-run -p $new_template_name "sudo fstrim -av"
message "Shutting down $new_template_name"
qvm-shutdown $new_template_name
}
prompt_user() {
message "Upgrade Debian template in QubesOS"
read -p "Which template do you want to upgrade? " template
read -p "Proceed with the upgrade? (y/n): " proceed
if [[ $proceed != "y" ]]; then
message "Exiting without changes."
exit 0
fi
read -p "Do you want to clone the template before upgrading? (y/n): " clone
read -p "What should be the new template name? " new_template_name
read -p "Enter the old release name (e.g., buster): " old_name
read -p "Enter the new release name (e.g., bullseye): " new_name
}
if [ $# -eq 0 ]; then
prompt_user
upgrade_template $template $proceed $clone $new_template_name $old_name $new_name
else
message "Usage: $0"
exit 1
fi
if [ $# -eq 0 ]; then
cat >&2 <<-EOF
Usage: ${0##*/} [options] -t
...
EOF
fi
Fed Upgrader
#!/bin/env bash
# A simple script for updating Fedora templates in QubesOS
PREFIX="$(tput setaf 7)$(tput bold)"
YELLOW="$(tput setaf 3)$(tput bold)"
POSTFIX="$(tput sgr0)"
TAB="$(echo -e '\t')"
ENTER=""
message() {
echo "${PREFIX}${1}${POSTFIX}"
}
upgrade_template() {
local template=$1
local proceed=$2
local clone=$3
local new_template_name=$4
vm_exists=$(qvm-ls | grep -w "$template")
if [[ -z $vm_exists ]]; then
message "Template $template does not exist."
exit 1
fi
current_version=$(qvm-run -p $template "cat /etc/fedora-release")
current_num=$(echo $current_version | grep -oP '(\d+)')
if [[ $proceed != "y" ]]; then
message "Skipping $template without changes."
return 0
fi
new_num=$((current_num + 1))
new_release="fedora-$new_num"
if [[ $clone == "y" ]]; then
qvm-clone $template $new_template_name
else
new_template_name=$template
fi
message "Allocating additional space..."
truncate -s 5GB /var/tmp/template-upgrade-cache.img
dev=$(sudo losetup -f --show /var/tmp/template-upgrade-cache.img)
message "Attaching block to $new_template_name"
qvm-start $new_template_name
qvm-block attach $new_template_name dom0:${dev##*/}
qvm-run -p $new_template_name "sudo mkfs.ext4 /dev/xvdi"
qvm-run -p $new_template_name "sudo mount /dev/xvdi /mnt/removable"
message "Performing upgrade. Patience..."
if qvm-run -p $new_template_name "sudo dnf clean all && sudo dnf --releasever=$new_num distro-sync --best --allowerasing -y";
then
qvm-run -p $new_template_name "sudo dnf update -y && sudo dnf upgrade -y"
qvm-run -p $new_template_name "cat /etc/fedora-release"
qvm-shutdown $new_template_name
sleep 2
message "Removing temporary cache..."
sudo losetup -d $dev
rm -f /var/tmp/template-upgrade-cache.img
sleep 2
message "Upgrade completed successfully!"
else
message "Upgrade failed. Check the template for issues."
exit 1
fi
}
prompt_user() {
current_version=$(qvm-run -p $template "cat /etc/fedora-release")
current_num=$(echo $current_version | grep -oP '(\d+)')
message "Current version of $template is: Fedora release $current_num ${YELLOW} "
read -p "Proceed with the upgrade? (y/n): " proceed
if [[ $proceed != "y" ]]; then
message "Skipping $template without changes."
exit 0
fi
read -p "Do you want to clone the template before upgrading? (y/n): " clone
}
get_new_template_name() {
if [[ $clone == "y" ]]; then
read -p "What should be the new template name? " new_template_name
echo $new_template_name
else
echo $1
fi
}
if [ $# -gt 0 ]; then
for template in "$@"; do
prompt_user
new_template_name=$(get_new_template_name $template)
upgrade_template $template $proceed $clone $new_template_name
done
else
read -p "What template do you want to upgrade? " template
prompt_user
new_template_name=$(get_new_template_name $template)
upgrade_template $template $proceed $clone $new_template_name
fi
if [ $# -eq 0 ]; then
cat >&2 <<-EOF
Usage: ${0##*/} [options] -t
...
EOF
fi
The value to a user, and who that user might be
Such scripts would lower the barrier-to-entry for non-technical users interested in adopting Qubes. Furthermore, it would lower the amount of time spent on upgrading individual templates a user may have created based on the defaults, becoming a value-add. It would also limit bandwidth on current Qubes documentation.
Hopes
I’m hoping more tech-savy users can assist in following on the thread with @marmarek and others as I’ve no longer the bandwidth to pursue.
@mods if this is in the wrong sub-forum, please let me know and I can revert elsewhere. Thanks to all in advance.