Add dedicated sysupdate-script

This commit is contained in:
LinuxSquare 2025-04-25 23:04:16 +02:00
parent 63e7cec2fa
commit f660c6a64e
4 changed files with 219 additions and 202 deletions

213
bin/sysupdate Executable file
View file

@ -0,0 +1,213 @@
#!/usr/bin/env bash
#######################################################################################################################
##
## Script to full update the system
##
## 0. Pre checks
## 1. Generate new boot environment (BE)
## 2. Update and Ansible highstate
## 3. Clean up
##
#######################################################################################################################
#######################################################################################################################
## Definitions
#######################################################################################################################
readonly LOCK_FILE="/tmp/systemupdate.lock"
readonly TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
readonly BTRFS_ROOT="/btrfs"
readonly CURRENT_SUBVOLUME=$(LC_ALL=C btrfs sub show / | LC_ALL=C grep 'Name' | cut -d: -f2 | awk '{$1=$1};1')
readonly NEW_SUBVOLUME="@root_${TIMESTAMP}"
readonly MOUNTPOINT='/mnt'
readonly EFI_DISK=$(findmnt -T /efi -o SOURCE | tail -n 1)
readonly ROOT_DISK=$(findmnt / -o SOURCE | cut -d"[" -f1 | tail -n 1)
readonly BE_HISTORY_COUNT=5
readonly SYSUPGRADE="$1"
readonly NEW_NOVOS_RELEASE="$2"
readonly NEW_ALPINE_RELEASE="v$3"
#######################################################################################################################
## Errorhandling
#######################################################################################################################
#----------------------------------------------------------------------------------------------------------------------
# systemupdate failed
#----------------------------------------------------------------------------------------------------------------------
systemupdateFailed() {
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ FAILED => clean up │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Unmount BE if mounted"
unmountMountpoint
subtaskTitle "Remove BE"
removeBEFromTimestamp ${TIMESTAMP}
rm -f ${LOCK_FILE}
subtaskTitle "Finished with exit code 1"
exit 1
}
# catch ^C and other signals and clean up
trap "echo -e '\n=> Interrupted with CTRL+C' >&2; systemupdateFailed" SIGINT SIGHUP SIGTERM SIGABRT
#######################################################################################################################
## Helper Functions
#######################################################################################################################
#----------------------------------------------------------------------------------------------------------------------
# Subtask title output
#----------------------------------------------------------------------------------------------------------------------
subtaskTitle() {
echo -e "\n=> $1"
}
#----------------------------------------------------------------------------------------------------------------------
# Unmount ${MOUNTPOINT}
#----------------------------------------------------------------------------------------------------------------------
unmountMountpoint() {
# if mountpoint exists -> umount
[[ $(findmnt -M "${MOUNTPOINT}") ]] && umount -R "${MOUNTPOINT}"
}
#----------------------------------------------------------------------------------------------------------------------
# Recursive subvolume delete
#----------------------------------------------------------------------------------------------------------------------
btrfsSubDelRecursive() {
btrfs sub list -o "${BTRFS_ROOT}/${1}" | cut -d " " -f 9 | while read i; do
btrfsSubDelRecursive "$i"
done
btrfs sub del "${BTRFS_ROOT}/${1}"
}
#----------------------------------------------------------------------------------------------------------------------
# Remove BE from timestamp
#----------------------------------------------------------------------------------------------------------------------
removeBEFromTimestamp() {
# remove all subvolume with this timestamp
for f in $(btrfs sub list -o /btrfs | cut -d " " -f 9 | grep "@root"); do
if [[ "$f" =~ "$1" ]]; then
btrfsSubDelRecursive "$f"
fi
done
}
#######################################################################################################################
## Main
#######################################################################################################################
echo "┌──────────────────────────────────────────┐"
echo "│ 0. Pre checks │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Check if another systemupgrade is in progress"
if [ -f ${LOCK_FILE} ]; then
echo "[ERROR] Another systemupgrade is in progress (lockfile: ${LOCK_FILE}) => exit" >&2
exit 1
fi
subtaskTitle "Check if ${MOUNTPOINT} exists"
if [ ! -d ${MOUNTPOINT} ]; then
mkdir -p "${MOUNTPOINT}"
fi
subtaskTitle "Check if ${MOUNTPOINT} is already a mountpoint"
if [[ $(findmnt -M "${MOUNTPOINT}") ]]; then
echo "[ERROR] ${MOUNTPOINT} is already a mountpoint => exit" >&2
exit 1
fi
subtaskTitle "Checks finished and update can start"
# Create lock file
touch ${LOCK_FILE} || systemupdateFailed
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ 1. Generate new boot environment (BE) │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Create snapshot of current running system"
btrfs subvolume snapshot / ${BTRFS_ROOT}/${NEW_SUBVOLUME} || systemupdateFailed
subtaskTitle "Mount new BE to ${MOUNTPOINT}"
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol="${NEW_SUBVOLUME}" "${ROOT_DISK}" "${MOUNTPOINT}" || systemupdateFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@home "${ROOT_DISK}" "${MOUNTPOINT}/home" || systemupdateFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@podman "${ROOT_DISK}" "${MOUNTPOINT}/opt/podman" || systemupdateFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@mysql "${ROOT_DISK}" "${MOUNTPOINT}/var/lib/mysql" || systemupdateFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=/ "${ROOT_DISK}" "${MOUNTPOINT}/btrfs" || systemupdateFailed
mount -o nodev,nosuid,noexec "${EFI_DISK}" "${MOUNTPOINT}/efi" || systemupdateFailed
mount -t proc /proc "${MOUNTPOINT}/proc/" || systemupdateFailed
mount -t sysfs /sys "${MOUNTPOINT}/sys/" || systemupdateFailed
mount -o bind /sys/firmware/efi/efivars "${MOUNTPOINT}/sys/firmware/efi/efivars/" || systemupdateFailed
mount -o bind /dev "${MOUNTPOINT}/dev/" || systemupdateFailed
mount -o bind /run "${MOUNTPOINT}/run/" || systemupdateFailed
subtaskTitle "New BE mounted"
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ 2. Update and Ansible highstate │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Update Ansible playbook"
chroot "${MOUNTPOINT}" /bin/bash -c "git -C /srv/ansible/playbooks pull" || systemupdateFailed
if $SYSUPGRADE; then
chroot "${MOUNTPOINT}" /bin/bash -c "grep -E '(main|community)' /etc/apk/repositories | sed 's|$(yq .ungrouped.vars.alpine_version /srv/ansible/inventory.yml)|$NEW_ALPINE_RELEASE|' > /etc/apk/repositories"
chroot "${MOUNTPOINT}" /bin/bash -c "yq -i '.ungrouped.vars.release_version = $NEW_NOVOS_RELEASE' /srv/ansible/inventory.yml"
chroot "${MOUNTPOINT}" /bin/bash -c "yq -i '.ungrouped.vars.alpine_version = $NEW_ALPINE_RELEASE' /srv/ansible/inventory.yml"
fi
subtaskTitle "Update bootloader configs"
chroot "${MOUNTPOINT}" /bin/bash -c "ansible-playbook /srv/ansible/playbooks/system/bootloader.ansible.yml" >/dev/null || systemupdateFailed
subtaskTitle "Alpine repositories & keyring update"
chroot "${MOUNTPOINT}" /bin/bash -c "apk update" || systemupdateFailed
subtaskTitle "Alpine packages update"
chroot "${MOUNTPOINT}" /bin/bash -c "apk upgrade" || systemupdateFailed
subtaskTitle "Ansible highstate"
chroot "${MOUNTPOINT}" /bin/bash -c "ansible-playbook /srv/ansible/playbooks/top.ansible.yml" >/dev/null || systemupdateFailed
subtaskTitle "Generate new initial ramdisk"
latest_kernel="$(chroot "${MOUNTPOINT}" /bin/bash -c 'echo $(apk search linux-lts | head -n1 | cut -d- -f3- | sed "s|r||")-lts')"
chroot "${MOUNTPOINT}" /bin/bash -c "mkinitfs $latest_kernel" || systemupdateFailed
subtaskTitle "Update motd"
chroot "${MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/generate_motd" || systemupdateFailed
subtaskTitle "Update GRUB"
chroot "${MOUNTPOINT}" /bin/bash -c "grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=alpine" || systemupdateFailed
chroot "${MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/noveriablcgen --noconfirm" || systemupdateFailed
subtaskTitle "Update finished"
subtaskTitle "Unmount BE"
unmountMountpoint
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ 3. Clean Up │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Clean up finished"
# Remove lock file
rm -f ${LOCK_FILE}

View file

@ -4,7 +4,7 @@ source "${ROOTPATH}/functions/check"
function sysupgrade_main() { function sysupgrade_main() {
if ! check_local &> /dev/null; then if ! check_local &> /dev/null; then
echo "Sysupgrade true" ${ROOTPATH}/bin/sysupdate true "$(get_latest_novos_version)" "$(get_latest_alpine_release)"
else else
printc "r" "There is no never version of NOVOS available, thus sysupgrade has been cancelled" printc "r" "There is no never version of NOVOS available, thus sysupgrade has been cancelled"
fi fi

View file

@ -1,205 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#######################################################################################################################
##
## Script to full update the system
##
## 0. Pre checks
## 1. Generate new boot environment (BE)
## 2. Update and Salt highstate
## 3. Clean up
##
#######################################################################################################################
function update_main() { function update_main() {
####################################################################################################################### ${ROOTPATH}/bin/sysupdate false
## Definitions
#######################################################################################################################
readonly TEMPDIR=$(mktemp -d /tmp/systemupdate.XXXXXX)
readonly LOCK_FILE="${TEMPDIR}/systemupdate.lock"
readonly TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
readonly BTRFS_ROOT="/btrfs"
readonly CURRENT_SUBVOLUME=$(LC_ALL=C btrfs sub show / | LC_ALL=C grep 'Name' | cut -d: -f2 | awk '{$1=$1};1')
readonly NEW_SUBVOLUME="@root_${TIMESTAMP}"
readonly MOUNTPOINT='/mnt'
readonly EFI_DISK=$(findmnt -T /efi -o SOURCE | tail -n 1)
readonly ROOT_DISK=$(findmnt / -o SOURCE | cut -d"[" -f1 | tail -n 1)
readonly BE_HISTORY_COUNT=5
#######################################################################################################################
## Errorhandling
#######################################################################################################################
#----------------------------------------------------------------------------------------------------------------------
# systemupdate failed
#----------------------------------------------------------------------------------------------------------------------
systemupdateFailed() {
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ FAILED => clean up │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Unmount BE if mounted"
unmountMountpoint
subtaskTitle "Remove BE"
removeBEFromTimestamp ${TIMESTAMP}
rm -f ${LOCK_FILE}
subtaskTitle "Finished with exit code 1"
exit 1
}
# catch ^C and other signals and clean up
trap "echo -e '\n=> Interrupted with CTRL+C' >&2; systemupdateFailed" SIGINT SIGHUP SIGTERM SIGABRT
#######################################################################################################################
## Helper Functions
#######################################################################################################################
#----------------------------------------------------------------------------------------------------------------------
# Subtask title output
#----------------------------------------------------------------------------------------------------------------------
subtaskTitle() {
echo -e "\n=> $1"
}
#----------------------------------------------------------------------------------------------------------------------
# Unmount ${MOUNTPOINT}
#----------------------------------------------------------------------------------------------------------------------
unmountMountpoint() {
# if mountpoint exists -> umount
[[ $(findmnt -M "${MOUNTPOINT}") ]] && umount -R "${MOUNTPOINT}"
}
#----------------------------------------------------------------------------------------------------------------------
# Recursive subvolume delete
#----------------------------------------------------------------------------------------------------------------------
btrfsSubDelRecursive() {
btrfs sub list -o "${BTRFS_ROOT}/${1}" | cut -d " " -f 9 | while read i; do
btrfsSubDelRecursive "$i"
done
btrfs sub del "${BTRFS_ROOT}/${1}"
}
#----------------------------------------------------------------------------------------------------------------------
# Remove BE from timestamp
#----------------------------------------------------------------------------------------------------------------------
removeBEFromTimestamp() {
# remove all subvolume with this timestamp
for f in $(btrfs sub list -o /btrfs | cut -d " " -f 9 | grep "@root"); do
if [[ "$f" =~ "$1" ]]; then
btrfsSubDelRecursive "$f"
fi
done
}
#######################################################################################################################
## Main
#######################################################################################################################
echo "┌──────────────────────────────────────────┐"
echo "│ 0. Pre checks │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Check if another systemupgrade is in progress"
if [ -f ${LOCK_FILE} ]; then
echo "[ERROR] Another systemupgrade is in progress (lockfile: ${LOCK_FILE}) => exit" >&2
exit 1
fi
subtaskTitle "Check if ${MOUNTPOINT} exists"
if [ ! -d ${MOUNTPOINT} ]; then
mkdir -p "${MOUNTPOINT}"
fi
subtaskTitle "Check if ${MOUNTPOINT} is already a mountpoint"
if [[ $(findmnt -M "${MOUNTPOINT}") ]]; then
echo "[ERROR] ${MOUNTPOINT} is already a mountpoint => exit" >&2
exit 1
fi
subtaskTitle "Checks finished and update can start"
# Create lock file
touch ${LOCK_FILE} || systemupdateFailed
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ 1. Generate new boot environment (BE) │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Create snapshot of current running system"
btrfs subvolume snapshot / ${BTRFS_ROOT}/${NEW_SUBVOLUME} || systemupdateFailed
subtaskTitle "Mount new BE to ${MOUNTPOINT}"
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol="${NEW_SUBVOLUME}" "${ROOT_DISK}" "${MOUNTPOINT}" || systemupdateFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@home "${ROOT_DISK}" "${MOUNTPOINT}/home" || systemupdateFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@podman "${ROOT_DISK}" "${MOUNTPOINT}/opt/podman" || systemupdateFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@mysql "${ROOT_DISK}" "${MOUNTPOINT}/var/lib/mysql" || systemupdateFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=/ "${ROOT_DISK}" "${MOUNTPOINT}/btrfs" || systemupdateFailed
mount -o nodev,nosuid,noexec "${EFI_DISK}" "${MOUNTPOINT}/efi" || systemupdateFailed
mount -t proc /proc "${MOUNTPOINT}/proc/" || systemupdateFailed
mount -t sysfs /sys "${MOUNTPOINT}/sys/" || systemupdateFailed
mount -o bind /sys/firmware/efi/efivars "${MOUNTPOINT}/sys/firmware/efi/efivars/" || systemupdateFailed
mount -o bind /dev "${MOUNTPOINT}/dev/" || systemupdateFailed
mount -o bind /run "${MOUNTPOINT}/run/" || systemupdateFailed
subtaskTitle "New BE mounted"
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ 2. Update and Ansible highstate │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Update Ansible playbook"
chroot "${MOUNTPOINT}" /bin/bash -c "git -C /srv/ansible/playbooks pull" || systemupdateFailed
subtaskTitle "Update bootloader configs"
chroot "${MOUNTPOINT}" /bin/bash -c "ansible-playbook /srv/ansible/playbooks/system/bootloader.ansible.yml" >/dev/null || systemupdateFailed
subtaskTitle "Alpine repositories & keyring update"
chroot "${MOUNTPOINT}" /bin/bash -c "apk update" || systemupdateFailed
subtaskTitle "Alpine packages update"
chroot "${MOUNTPOINT}" /bin/bash -c "apk upgrade" || systemupdateFailed
subtaskTitle "Ansible highstate"
chroot "${MOUNTPOINT}" /bin/bash -c "ansible-playbook /srv/ansible/playbooks/top.ansible.yml" >/dev/null || systemupdateFailed
subtaskTitle "Generate new initial ramdisk"
latest_kernel="$(chroot "${MOUNTPOINT}" /bin/bash -c 'echo $(apk search linux-lts | head -n1 | cut -d- -f3- | sed "s|r||")-lts')"
chroot "${MOUNTPOINT}" /bin/bash -c "mkinitfs $latest_kernel" || systemupdateFailed
subtaskTitle "Update motd"
chroot "${MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/generate_motd" || systemupdateFailed
subtaskTitle "Update GRUB"
chroot "${MOUNTPOINT}" /bin/bash -c "grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=alpine" || systemupdateFailed
chroot "${MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/noveriablcgen --noconfirm" || systemupdateFailed
subtaskTitle "Update finished"
subtaskTitle "Unmount BE"
unmountMountpoint
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ 3. Clean Up │"
echo "└──────────────────────────────────────────┘"
subtaskTitle "Clean up finished"
# Remove lock file
rm -f ${LOCK_FILE}
} }

View file

@ -4,6 +4,10 @@ function get_latest_novos_version() {
curl -sL $(getValueByKey "url")/releases/latest | grep "Novos/ISO/releases/tag" | awk '{$1=$1};1' | cut -d'>' -f2 | cut -d'<' -f1 | cut -d- -f1 curl -sL $(getValueByKey "url")/releases/latest | grep "Novos/ISO/releases/tag" | awk '{$1=$1};1' | cut -d'>' -f2 | cut -d'<' -f1 | cut -d- -f1
} }
function get_latest_alpine_release() {
curl -sL $(getValueByKey "url")/releases/latest | grep "Novos/ISO/releases/tag" | awk '{$1=$1};1' | cut -d'>' -f2 | cut -d'<' -f1 | cut -d_ -f2
}
function get_current_novos_version() { function get_current_novos_version() {
cat /etc/os-release | grep VERSION_ID | cut -d= -f2 | jq -r '.' cat /etc/os-release | grep VERSION_ID | cut -d= -f2 | jq -r '.'
} }