2024-08-28
How not to upgrade (some) held packages on Ubuntu (and Debian)
We hold a number of packages across our Ubuntu fleet (for good reasons), so that they're only upgraded under controlled circumstances. Which packages are held varies, but they always include the kernel packages (among other issues, we don't want machines to reboot into new kernels by surprise, for example after a crash or a power issue). Some of our hosts are used for testing, and I generally update their kernels (far) more often than our regular machines for various reasons. Until recently I did this with the obvious 'apt-get' command line:
apt-get -u upgrade --with-new-pkgs --ignore-hold
The problem with this is that it upgrades all held packages, not just the kernel. I have historically gotten away with this on the machines I do this on, but recently I got burned (well, more burned my co-workers); as part of a kernel upgrade I also upgraded another package that caused some problems.
Instead what you (I) need to do is to use 'apt-mark unhold
<packages>
' and then just 'apt-get -u upgrade --with-new-pkgs
'. This is less convenient (but
at least these days we have apt-mark). I
continue to be sad that 'apt-get upgrade' doesn't take package(s)
to upgrade and will upgrade everything, so you can't do 'apt-get
upgrade linux-image-*' to directly express what you (I) want
here.
(Fedora's DNF will do this, along with the inverse option of 'dnf upgrade --exclude=...', and both of these are quite nice.)
You can do this with 'apt-get install', but if you're going to use wildcards in the package name for convenience, you need to be careful and add an extra option, --only-upgrade:
apt-get -u install --only-upgrade 'linux-*'
Otherwise, 'apt-get install ...' will faithfully do exactly what you told it to, which is install or upgrade all of the packages that match the wildcard. If you're using 'apt-get install' to upgrade held packages, you probably don't want that. Despite its name, the --only-upgrade option will install new packages that are required by the packages that you're upgrading, such as new kernel packages that are required by a new version of 'linux-image-generic'.
The one semi-virtue of explicitly unholding packages to upgrade them is that this makes it very obvious that the packages are in fact unheld. An 'apt-get install <packages>' or an 'apt-get upgrade --ignore-hold' will unhold the packages as a side effect. Fortunately we long ago modified our update system to automatically apply our standard package holds before it did anything else (after one too many accidents where we should have re-held a package but forgot).
(I'm sure you could write a cover script to handle all of this, if you wanted to. Currently I don't do this often enough to go that far.)