upsnapz/upsnapz.sh

401 lines
11 KiB
Bash
Raw Normal View History

#!/bin/bash
2025-02-26 11:03:46 +01:00
# Time-stamp: <2025-02-26 11:02:08 nomad>
2025-02-09 14:48:02 +01:00
# Michel Le Cocq <lecocq@ipgp.fr>
# <nomad@neuronfarm.net>
2025-02-09 14:48:02 +01:00
# Licence Art Libre 1.3 (LAL 1.3)
# upsnapz.sh
2025-02-09 14:48:02 +01:00
# 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
2025-02-10 07:05:16 +01:00
# Depend :
# - gh
2025-02-10 07:05:16 +01:00
# - 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
2025-02-19 06:55:28 +01:00
#
2025-02-25 06:21:55 +01:00
# - integrer apt dist-upgrade
2025-02-25 06:36:19 +01:00
#
2025-02-25 06:21:55 +01:00
# 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
2025-02-25 06:36:19 +01:00
#
# +------------------------------------------------------------------------------------------------+
2025-02-26 08:03:57 +01:00
function showsnap
{
zfs list -o name,used,usedbysnapshots -r zroot/ROOT -s creation | grep -v '^zroot/ROOT .*' > /tmp/upsnap.tmp
for line in $(cat /tmp/upsnap.tmp | grep zroot | cut -d' ' -f1)
do
nbr=$(zfs list -H -t snapshot -r $line | wc -l)
z=$(echo $line | cut -d'/' -f3)
sed -i "/$z/ s/$/ $nbr/" /tmp/upsnap.tmp
done
sed -i "/USEDSNAP/ s/$/ NBRSNAP/" /tmp/upsnap.tmp
cat /tmp/upsnap.tmp
rm /tmp/upsnap.*
}
2025-02-10 07:15:03 +01:00
function cleansnap
{
printf '\nClean snapshot.\n'
printf 'Current available bootfs:\n'
2025-02-26 11:03:46 +01:00
showsnap
2025-02-10 07:15:03 +01:00
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
2025-02-10 07:05:16 +01:00
# 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
2025-02-10 07:05:16 +01:00
e=$(grep $(sha256sum /boot/efi/EFI/ZBM/VMLINUZ.EFI | awk '{print $1}') /tmp/sha256.txt | awk -F"[()]" '{print $2}' )
echo -n " Installed Release : "
2025-02-09 14:46:58 +01:00
e=$(echo $e | awk -F'-' '{print $4}')
if [ -z $e ]
then
2025-02-10 07:05:16 +01:00
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}'
2025-02-10 07:05:16 +01:00
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
2025-02-12 06:32:33 +01:00
# ici souci ! si non authentifié sur github ne "fonctionne pas"
2025-02-10 07:05:16 +01:00
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
2025-02-10 07:05:16 +01:00
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
}
2025-02-10 07:05:16 +01:00
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"
2025-02-26 08:03:57 +01:00
echo "-s : only show zfs snap"
}
2025-02-26 08:03:57 +01:00
while getopts 'hbs' OPTION; do
case "$OPTION" in
h)
usage
exit 1
;;
b)
check_ZFS_BOOT_MENU
echo
exit 1
;;
2025-02-26 08:03:57 +01:00
s)
showsnap
echo
exit 1
;;
?)
usage
exit 1
;;
esac
done
askupgrade
askautoclean
2025-02-10 07:05:16 +01:00
snapchange
echo
check_zpool_status
check_ZFS_BOOT_MENU
echo
zpool status
2025-02-10 07:15:03 +01:00
cleansnap
printf '\nNothing else to do.\n'