381 lines
10 KiB
Bash
Executable File
381 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Time-stamp: <2025-02-25 06:36:02 nomad>
|
|
|
|
# Michel Le Cocq <lecocq@ipgp.fr>
|
|
# <nomad@neuronfarm.net>
|
|
|
|
# Licence Art Libre 1.3 (LAL 1.3)
|
|
|
|
# upsnapz.sh
|
|
|
|
# Script to upgrade your system install on zfs root with zfs boot menu (only Debian for the moment).
|
|
#
|
|
# refresh apt
|
|
# zfs snapshot
|
|
# apt upgrade
|
|
# apt autoremove
|
|
# zfs clone promote
|
|
# check zfs boot menu release
|
|
# check zfs pool status
|
|
|
|
# Depend :
|
|
# - gh
|
|
# - full sudo permission
|
|
|
|
# +------------------------------------------------------------------------------------------------+
|
|
# To do or not :
|
|
#
|
|
# - ajouter zpool upgrade or not
|
|
# - ajouter question cleanup zroot
|
|
# - regarder si un nouveau kernel existe et si oui faire ce qu'il y a a faire
|
|
# - verifier que les noms des zroot/ROOT/vol sont conformes au format attendu
|
|
# - verfier que 'gh auth status' fonctionne avant de l'utiliser (auth)
|
|
#
|
|
# - souci dans clone promote oui non !?
|
|
# je fais dans la fonction askpromote
|
|
# sudo zfs clone $bootfs@$snapname $parents/$sugsname
|
|
# sudo zfs promote $parents/$sugsname
|
|
# je fais ca pour que : promote clone dataset no longer depend on origin snapshot
|
|
#
|
|
# Current available bootfs:
|
|
# NAME USED USEDSNAP
|
|
# zroot/ROOT/debian_trixie_2025_02_03 7.58M 0B
|
|
# zroot/ROOT/debian_trixie_2025_02_08 3.25M 0B
|
|
# zroot/ROOT/debian_trixie_2025_02_08_2025-02-08-185711 7.57M 0B
|
|
# zroot/ROOT/debian_trixie_2025-02-08-214321 2.25M 0B
|
|
# zroot/ROOT/debian_trixie_2025_02_12 7.17M 0B
|
|
# zroot/ROOT/debian_trixie-rollback_2025_02_12 5.15M 0B
|
|
# zroot/ROOT/debian_trixie-Rn_2025_02_12 31.9G 21.6G <- fait depuis zfs boot menu
|
|
# zroot/ROOT/debian_trixie_2025_02_16 2.16M 0B
|
|
# zroot/ROOT/debian_trixie_2025_02_19 1.90M 0B
|
|
# zroot/ROOT/debian_trixie_2025_02_22 5.72G 3.20G
|
|
#
|
|
# - integrer apt dist-upgrade
|
|
#
|
|
# root@nsob:~# apt dist-upgrade
|
|
# Upgrading:
|
|
# libnvpair3linux libuutil3linux zfs-dkms zfs-initramfs zfs-zed zfsutils-linux
|
|
#
|
|
# Installing dependencies:
|
|
# libzfs6linux libzpool6linux
|
|
#
|
|
# REMOVING:
|
|
# libzfs4linux libzpool5linux
|
|
#
|
|
# Summary:
|
|
# Upgrading: 6, Installing: 2, Removing: 2, Not Upgrading: 0
|
|
# Download size: 4891 kB
|
|
# Space needed: 538 kB / 27.3 GB available
|
|
#
|
|
# +------------------------------------------------------------------------------------------------+
|
|
|
|
function cleansnap
|
|
{
|
|
printf '\nClean snapshot.\n'
|
|
|
|
printf 'Current available bootfs:\n'
|
|
zfs list -o name,used,usedbysnapshots -r zroot/ROOT -s creation | grep -v '^zroot/ROOT .*'
|
|
oldest=$(zfs list -H -o name -r zroot/ROOT -s creation | grep -v '^zroot/ROOT$' | head -n 1)
|
|
oldestdate=$(echo $oldest | cut -d "_" -f 3- | tr '_' '-')
|
|
current=$(zpool get -H bootfs zroot -o value)
|
|
printf '\ncurrent bootfs: %s\n' $current
|
|
printf 'oldest bootfs: %s\n' $oldest
|
|
printf '\nzroot/ROOT status : \n'
|
|
zfs list -o used,available,quota,usedbychildren zroot/ROOT
|
|
|
|
printf '\nsnapshot to clean older than %s:\n' $oldestdate
|
|
zfs list -H -o name -t snapshot -s creation -r $current | grep $oldestdate -B10000 | grep -v $oldestdate
|
|
|
|
if [ $? -ne 1 ]
|
|
then
|
|
printf '\nDo snapshots cleanup ? : %s [Y-n]' $sugsname
|
|
read docleanup
|
|
if [ -z $dopromote ]
|
|
then
|
|
dopromote='y'
|
|
fi
|
|
|
|
if [[ "$dopromote" == "y" ]]
|
|
then
|
|
for z in $(zfs list -H -o name -t snapshot -s creation -r $current | grep $oldestdate -B10000 | grep -v $oldestdate)
|
|
do
|
|
printf 'zfs destroy %s\n' $z
|
|
sudo zfs destroy $z
|
|
done
|
|
fi
|
|
usedbysnapshots=$(zfs list -H -o usedbysnapshots $current)
|
|
printf '\nused by snapshot : %s\n' $usedbysnapshots
|
|
else
|
|
printf '\tno snapshot older than %s\n' $oldestdate
|
|
fi
|
|
}
|
|
|
|
function check_zpool_status
|
|
{
|
|
# check zpool status if it's upgradable
|
|
|
|
printf 'Check ZFS pool status:\n'
|
|
e=$(zpool status | grep action | grep 'zpool upgrade')
|
|
if [ $? -eq 0 ]
|
|
then
|
|
printf 'One or more ZFS pool can be upgraded\n'
|
|
zpool status
|
|
printf 'In case of ZFS Root be carefull that your bootloader is up to date and compatible with this new ZFS feature.\n'
|
|
else
|
|
printf 'every things ok for ZFS pool.\n'
|
|
fi
|
|
}
|
|
|
|
function check_ZFS_BOOT_MENU
|
|
{
|
|
# check last zfs boot menu release
|
|
# compare if we are on last release
|
|
|
|
# pas tout à fait satisfait de cette fonction !
|
|
|
|
printf '\nCheck ZFS_BOOT_MENU:\n'
|
|
PA="https://get.zfsbootmenu.org/sha256.txt"
|
|
echo " Hit:zfsbootmenu "$PA
|
|
curl -s -o /tmp/sha256.txt -L $PA
|
|
e=$(grep $(sha256sum /boot/efi/EFI/ZBM/VMLINUZ.EFI | awk '{print $1}') /tmp/sha256.txt | awk -F"[()]" '{print $2}' )
|
|
echo -n " Installed Release : "
|
|
e=$(echo $e | awk -F'-' '{print $4}')
|
|
if [ -z $e ]
|
|
then
|
|
echo " /!\ sha256sum of ZBM/VMLINUZ.EFI"
|
|
echo " not in sync with : "$PA
|
|
echo ' avaible release :'
|
|
cat /tmp/sha256.txt | grep EFI | grep release | awk -F"[()]" '{print $2}'
|
|
else
|
|
echo $e
|
|
# pas tout a fait satisfait de cette methode avec gh
|
|
# force a s'authentifier sur github !
|
|
dpkg -l gh &> /dev/null
|
|
if [ $? -eq 0 ]
|
|
then
|
|
# ici souci ! si non authentifié sur github ne "fonctionne pas"
|
|
f=$(gh release list --repo https://github.com/zbm-dev/zfsbootmenu | grep Latest | awk -F' ' '{print $4}')
|
|
if [ "$e" != "$f" ]
|
|
then
|
|
echo " /!\ Installed Release and lastest are not same !"$PA
|
|
printf ' Latest Release : '
|
|
echo $f
|
|
fi
|
|
fi
|
|
fi
|
|
rm /tmp/sha256.txt
|
|
}
|
|
|
|
function askpromote()
|
|
{
|
|
# ask if we wanted to promote that last snapshot
|
|
# promote last bootfs snapshot to a new bootfs env
|
|
# suggest name for new bootfs env
|
|
# clone promote activate new bootfs
|
|
# ask to reboot to new bootfs
|
|
|
|
snapname=$1
|
|
bootfs=$2
|
|
parents=$(zfs list -o name | grep $bootfs | awk 'BEGIN{FS=OFS="/"}{NF--; print}')
|
|
printf '\nclone and promote before upgrade %s or not \nhost will reboot to new bootfs : [Y-n]' $bootfs@$snapname
|
|
read dopromote
|
|
if [ -z $dopromote ]
|
|
then
|
|
dopromote='y'
|
|
echo y
|
|
fi
|
|
|
|
if [[ "$dopromote" == "y" ]]
|
|
then
|
|
printf '\nactual bootfs : %s\n' $bootfs
|
|
printf 'other bootfs :\n' $bootfs
|
|
zfs list -o name,creation -r $parents -s creation | grep -v ^$parents$
|
|
e=$(lsb_release -is)
|
|
f=$(date +%b)
|
|
sugsname="${e,,}_"$(lsb_release -cs)"_"$(date +%Y)"_"$(date +%m)"_"$(date +%d)
|
|
zfs list -H -o name | grep $sugsname
|
|
if [ $? -eq 0 ]
|
|
then
|
|
sugsname=$sugsname"_"$(date +%Y-%m-%d-%H%M%S)
|
|
fi
|
|
printf '\nname suggestion for new zpool bootfs : %s [Y-n]' $sugsname
|
|
|
|
read namepros
|
|
if [ -z $namepros ]
|
|
then
|
|
echo y
|
|
namepros='y'
|
|
fi
|
|
|
|
if [[ "$namepros" == "n" ]]
|
|
then
|
|
printf 'new bootfs name :'
|
|
read sugsname
|
|
if [ $(zfs list -H -o name | grep $sugsname) -eq 0 ]
|
|
then
|
|
sugsname=$newname_$(date +%Y-%m-%d-%H%M%S)
|
|
printf '%s already exist I siggest : %s\n'
|
|
fi
|
|
printf 'name suggestion : %s\n' $sugsname
|
|
fi
|
|
sudo zfs clone $bootfs@$snapname $parents/$sugsname
|
|
sudo zfs promote $parents/$sugsname
|
|
sudo zfs set -u mountpoint=/ $parents/$sugsname
|
|
sudo zfs set canmount=noauto $parents/$sugsname
|
|
sudo zpool set bootfs=$parents/$sugsname zroot
|
|
printf '%s will reboot to new bootfs %s in 5s\nHit Ctrl^c to abort' $(hostname) $sugsname
|
|
printf "\nRun again current script $(basename $0) after reboot.\n"
|
|
echo -n '.'; sleep 1; echo -n '.'; sleep 1; echo -n '.'; sleep 1; echo -n '.'; sleep 1; echo -n '.';sleep 1; echo -n '.';sleep 1; echo -n '.'
|
|
sudo reboot
|
|
else
|
|
echo no
|
|
fi
|
|
}
|
|
|
|
function askautoclean()
|
|
{
|
|
# ask to autoremove and zfs snapshot before
|
|
|
|
printf '\napt-get -s autoremove\n'
|
|
if [ $(apt-get -s autoremove | sed -n '/The following packages will be REMOVED:/,/^[0-9+] upgraded, [0-9+] newly installed, [0-9+] to remove and [0-9+] not upgraded.$/p' | wc -l) -gt 0 ]
|
|
then
|
|
apt-get -s autoremove | sed -n '/The following packages will be REMOVED:/,/^[0-9+] upgraded, [0-9+] newly installed, [0-9+] to remove and [0-9+] not upgraded.$/p'
|
|
printf '\n%s\n' 'Do we run an autoremove ? : [Y-n]'
|
|
read autoclean
|
|
if [ -z $autoclean ]
|
|
then
|
|
echo y
|
|
autoclean='y'
|
|
fi
|
|
|
|
if [[ "$autoclean" == "y" ]]
|
|
then
|
|
printf 'before autoremove : '
|
|
asksnap
|
|
sudo apt-get -y autoremove
|
|
else
|
|
echo
|
|
fi
|
|
fi
|
|
sudo apt autoclean
|
|
echo
|
|
}
|
|
|
|
function asksnap()
|
|
{
|
|
# print creation info of last bootfs snapshot
|
|
# ask if we want a snapshot of bootfs
|
|
# snapshot bootfs
|
|
|
|
bootfs=$(zpool get bootfs -o value -H zroot)
|
|
l=$(zfs list -H -t snapshot -o creation,name -S creation $(zpool get bootfs -o value -H zroot) | head -n1)
|
|
printf 'last snapshot : \n%s\n' "$l"
|
|
printf '%s <- now\n' "$(date '+%a %b %d %H:%M %Y')"
|
|
printf 'snapshot bootfs %s or not ? : [Y-n]' $bootfs
|
|
read dosnap
|
|
if [ -z $dosnap ]
|
|
then
|
|
echo y
|
|
dosnap='y'
|
|
fi
|
|
if [[ "$dosnap" == "y" ]]
|
|
then
|
|
snapname=$(date +%Y-%m-%d-%H%M%S)
|
|
sudo zfs snapshot $bootfs@$snapname
|
|
zfs list -H -o name $bootfs@$snapname
|
|
askpromote $snapname $bootfs
|
|
else
|
|
echo no
|
|
fi
|
|
}
|
|
|
|
function snapchange
|
|
{
|
|
# check/show snap change/refresh
|
|
|
|
dpkg -l snapd &> /dev/null
|
|
if [ $? -eq 0 ]
|
|
then
|
|
printf '%s\n' 'snap refresh && snap changes'
|
|
sudo snap refresh
|
|
snap changes
|
|
fi
|
|
}
|
|
|
|
function askupgrade()
|
|
{
|
|
# run apt update
|
|
# if there were upgrade ask for upgrade or not
|
|
# ask for making a snapshot
|
|
# run apt upgrade
|
|
# else
|
|
# ask for making a snapshot
|
|
|
|
printf '%s\n' 'apt update'
|
|
sudo apt update
|
|
if [ $(apt list --upgradable 2>/dev/null | wc -l) -gt 1 ]
|
|
then
|
|
printf '\n%s\n' 'apt list --upgradable'
|
|
apt list --upgradable
|
|
|
|
printf '\nUpgrade or not : [Y-n]'
|
|
read answer
|
|
|
|
if [ -z $answer ]
|
|
then
|
|
echo y
|
|
answer='y'
|
|
fi
|
|
|
|
if [[ "$answer" == "y" ]]
|
|
then
|
|
printf 'before upgrade : '
|
|
asksnap
|
|
printf '%s\n' 'apt -y upgrade'
|
|
sudo apt -y upgrade
|
|
else
|
|
echo no
|
|
fi
|
|
else
|
|
echo
|
|
asksnap
|
|
fi
|
|
}
|
|
|
|
function usage()
|
|
{
|
|
echo "Usage: $(basename $0) [-h]"
|
|
echo "-b : only check zfs boot menu"
|
|
}
|
|
|
|
while getopts 'hb' OPTION; do
|
|
case "$OPTION" in
|
|
h)
|
|
usage
|
|
exit 1
|
|
;;
|
|
b)
|
|
check_ZFS_BOOT_MENU
|
|
echo
|
|
exit 1
|
|
;;
|
|
?)
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
askupgrade
|
|
askautoclean
|
|
snapchange
|
|
echo
|
|
check_zpool_status
|
|
check_ZFS_BOOT_MENU
|
|
echo
|
|
zpool status
|
|
cleansnap
|
|
printf '\nNothing else to do.\n'
|
|
|