*Very* simple script to help evaluate whether an IncusOS update is reboot-worthy

While IncusOS is very actively under development, the frequency of updates is enough that, sometimes, one might wish to skip an update or two. To help in evaluating this, I wrote a little script entirely using my own natural intelligence (or lack there-of).

This will query your default incus system for the current update status / reboot requirements, and then open the GitHub diff / comparison between the current version and the new version. You can then evaluate whether or not the new version is important enough to necessitate a reboot or not.

For example, as I write this I’m running incusos 202602230420 and 202602240349 is now available, necessitating a reboot. But, looking at the comparison the only changes are related to Migration-Manager, which I am not using… so I can reasonably ignore this update.

The code:

#!/usr/bin/zsh
# this code is released into the public domain and is free for anyone to use in anyway at all.

ius=$(incus query incus:/os/1.0/system/update)

if [[ "${1}" == "-l" ]]
then
	echo "incus query incus:/os/1.0/system/update\n${ius}"
else
	nr=$(echo "$ius" | grep "needs_reboot")

	if [[ "$nr" =~ 'false' ]]
	then
		echo "No reboot needed."
	elif [[ "$nr" =~ 'true' ]]
	then
		aos=$(incus admin os show 2> /dev/null )
		currentversion=$(echo "${aos}" | grep 'os_version:' | awk '-F: "' '{print $2}' | awk '-F"' '{print $1}')
		newversion=$(echo "${aos}" | grep 'os_version_next:' | awk '-F: "' '{print $2}' | awk '-F"' '{print $1}')
		echo "Reboot needed!"
		echo "${currentversion} -> ${newversion}"
		xdg-open "https://github.com/lxc/incus-os/compare/${currentversion}...${newversion}"
	else
		echo "Unknown state:\n$ius" 
	fi
fi

I’m sure there are better way to do this.

I’m using two different API calls and could probably get away with just the “incus admin os show” command as it looks like it has all the necessary information (it doesn’t have a “needs reboot” field, but does show different current/new versions if they’re present, and that probably amounts to the same thing).

If my grep/regex-fu were better, the two pipes to awk could probably be eliminated, but that would require back-references and so would look messier, and might even be slower.

Et Cetera.

The script currently specifies zsh, but I think there’s nothing here incompatible with bash.

The URL is opened with xdg-open, which will probably open your default browser, but if your distro or DE somehow doesn’t support that, well….

I’d rather print the diff on the command line, but I’m far to lazy to put any effort into fingering that out. xdg-open is good enough

This script executes a couple incus api/commands, grep, awk and the (probably) built-in echo commands in addition to xdg-open. These should be safe, but please carefully evaluate whether or not you think you should be running it on your system before you do anything crazy like that.

Index of /os/202602250730/x86_64/ has auto-generated changelog files too

Thanks for that link. I’d stumbled into those directories once a while ago for some other reason, but had, more or less, forgotten about them.

I’ve re-written the script to optionally traverse the text change-logs generated at Index of /os//x86_64 or to invoke the git-hub comparison.

This is much messier than before, but was kinda fun. Testing has been absolutely minimal, and the script now creates temporary directories and files and can leave traces, so use at your discretion.

#!/usr/bin/zsh

# requires wget, mktemp, gunzip, grep, awk
commandname=${0:t}

function usage
{
	echo "${commandname} is a tool to query an IncusOS host whether or not an"
	echo "update has been downloaded and is ready to reboot into. This tool will"
	echo "use the built in API/Commands to query this information, and then,"
	echo "optionally, display a change-log either on the console or via your"
	echo "default web-browser so you can determine whether or not the update is"
	echo "of enough importance to actually warrant a reboot."
	echo ""
	echo "The sources and format of the change-logs are very different, and one "
	echo "or the other may seem more useful to you."
	echo ""
	echo "Usage:"
	echo "    ${commandname} [options]"
	echo "Options:"
	echo "    -b | --browser ${commandname} will invoke xdg-open to open your default"
	echo "                   web-browser with a URL to git-hub showing the changes"
	echo "                   between the version of IncusOS you are currently using"
	echo "                   and the new version ready to reboot into."
	echo "    -c | --console ${commandname} will attempt to extract change-log data for"
	echo "                   each version of IncusOS between the currently running "
	echo "                   version and the new version (there may be multiple interim"
	echo "                   versions). This is the default behavior."
	echo "    -l             Prints the raw output of \"incus query incus:/os/1.0/system/update\","
	echo "                   and \"incus admin os show\" then exits."
	echo "    -s| --simple   ${commandname} will simply report whether or not a reboot"
	echo "                   is necessary, and the current / new IncusOS versions."
	echo "    -h | --help    Prints this usage information."
	echo ""
	exit 0
}

function get_changelog_r
{
	## get_changelog_r recursively downloads changelogs for the new version and
	## each prior version until the currently running version is reached.

	## How deep can we recurse? No idea. What happens when we go too deep? No idea.
	## 10 or 15 levels shouldn't, probably, be a problem and are unlikely to be 
	## encountered unless you don't reboot for ages, in which case you'll undoubtedly
	## have other, more serious problems to deal with.

	local newversion="${1}"
	local currentversion="${2}"
	local tempdir="${3}"
	local output=
	local rmd=

	if [[ ! -d "${tempdir}" ]]
	then
		tempdir=$(mktemp -d --tmpdir)
		if [[ ! -d "${tempdir}" ]]
		then
			echo "Can't create temporary directory into which to download changelogs."
			exit -1
		fi
	fi

	pushd "${tempdir}"

	wget "https://images.linuxcontainers.org/os/${newversion}/x86_64/changelog-stable.yaml.gz" 2> /dev/null
	if [[ -e "changelog-stable.yaml.gz" ]]
	then
		gunzip "changelog-stable.yaml.gz"
		if [[ -e "changelog-stable.yaml" ]]
		then
			mv "changelog-stable.yaml" "${newversion}.yaml"
			if [[ -e "${newversion}.yaml" ]]
			then
				local priorversion=$(grep "prior_version:" "${newversion}.yaml"| awk '-F: "' '{print $2}' | awk '-F"' '{print $1}')
				output=$(cat "${newversion}.yaml")

				if [[ "${priorversion}" != "${currentversion}" ]]
				then
					local newoutput=$(get_changelog_r ${priorversion} ${currentversion} "${tempdir}" )
					output="${output}\n----------------------------------\n${newoutput}"
				else
					rmd=yes
				fi
			fi
		fi
	fi
	popd
	if [[ -n "${rmd}" ]]
	then
		rm -rf "${tempdir}"
	fi
	
	echo "${output}"
}

function raw
{
	incus query incus:/os/1.0/system/update
	incus admin os show
	exit 2
}

consoleoutput=yes
simple=

while [[ "${1}" ]]
do
	case "${1}" in
		'-b'|'--browser')
			consoleoutput=
			;;
		'-c'|'--console')
			consoleoutput=yes
			;;
		'-h'|'--help')
			usage
			;;
		'-l')
			raw
			;;
		'-s'|'--simple')
			simple=isassimpledoes
			;;
	esac
	shift
done

ius=$(incus query incus:/os/1.0/system/update)

nr=$(echo "$ius" | grep "needs_reboot")

if [[ "$nr" =~ 'false' ]]
then
	echo "No reboot needed."
elif [[ "$nr" =~ 'true' ]]
then
	aos=$(incus admin os show 2> /dev/null )
	currentversion=$(echo "${aos}" | grep 'os_version:' | awk '-F: "' '{print $2}' | awk '-F"' '{print $1}')
	newversion=$(echo "${aos}" | grep 'os_version_next:' | awk '-F: "' '{print $2}' | awk '-F"' '{print $1}')
	echo "Reboot needed!"
	echo "${currentversion} -> ${newversion}"
	if [[ -z "${simple}" ]]
	then
		if [[ -n "${consoleoutput}" ]]
		then
			get_changelog_r ${newversion} ${currentversion}
		else
			xdg-open "https://github.com/lxc/incus-os/compare/${currentversion}...${newversion}"
		fi
	fi
else
	echo "Unknown state:\n$ius" 
fi