You're right, and my original description was wrong: nothing here
upgrades and removes a package in one transaction. I mis-read two
*separate* apt transactions as one. What actually happened is the "Just
upgrade libc6 first" quirk - LP: #2106202, fixed in plucky and dropped
in questing, but still present in the noble upgrader that every
jammy->noble upgrade runs. Attaching the apt-clone tarball, and I have
an exact offline reproduction of the destructive transaction from it.
## The three transactions
/var/log/dist-upgrade/history.log has three entries, matching the three
"Log started" blocks in apt-term.log:
1. 11:08:46 - 11:08:46, empty
2. 11:17:47 - 11:17:48, Install 689, Upgrade 2581, Remove 246, apt-term block
empty
3. 11:18:35 - 11:22:25, Install 194, Upgrade 442, Remove 809
No overlap between the Install/Upgrade/Remove sets *inside* either
entry, so your objection is correct. network-manager:amd64 is under
Upgrade in entry 2 and under Remove in entry 3 - two different
transactions.
Entry 2 is doDistUpgradeSimulation(): DistUpgradeController.py sets
dir::bin::dpkg="/bin/true" and calls doDistUpgrade(), hence a one-second
transaction with the full change set logged and an empty term block.
That change set is what I was shown and approved at 11:09:56.
Entry 3 is a completely different calculation, from the block right
after the simulation (DistUpgradeController.py, 1:24.04.28, around line
2578):
# Just upgrade libc6 first
self.cache.clear()
libc6_possible = False
try:
self.cache["libc6"].mark_install()
libc6_possible = True
except SystemError as e:
if "pkgProblemResolver" in str(e):
logging.debug("Unable to mark libc6 alone for install.")
pass
...
if libc6_possible:
... doDistUpgrade()
cache.clear() discards the plan I approved, mark_install() re-plans from
scratch with only libc6 requested, and libc6_possible is set True unless
mark_install *raises*. Here the resolver did not raise - it succeeded,
by removing 809 packages - so the upgrader committed that without
showing it to me.
Timeline confirming entry 3 is that step: main.log has 11:17:46,329
cache.commit() (simulation), 11:17:49,342 "cache.commit() returned
None", then 11:17:50,527 cache.commit() again, with no openCache() in
between (the libc6_possible=False path would have called openCache() and
logged it). The eipp.log.xz Request stanza is "Planner: internal",
Remove: 809, Install: 636 - so the removals were already in the depcache
before the planner ran - and dpkg.log for 11:18:35-11:22:25 is exactly
809 remove / 442 upgrade / 194 install (442+194 = 636).
The step is also invisible in the logs: noble's code does not wrap it in
_startAptResolverLog(), so apt.log jumps straight from "Log time:
11:09:45" to "Log time: 11:22:25". plucky's version adds the
_startAptResolverLog()/_stopAptResolverLog() pair around it.
## Reproduction
From the attached apt-clone tarball plus the noble indexes, in a jammy
container so it uses the apt that is actually running at that point in
the upgrade (apt 2.4.14 / python3-apt 2.4.0ubuntu4.1 - main.log records
"apt version: '2.4.14'"):
docker run --rm -v $PWD:/work -v /var/lib/apt/lists:/host-lists:ro
ubuntu:22.04 \
bash -c 'apt-get update -qq && apt-get install -y -qq python3-apt &&
python3 /work/repro-libc6-first.py /work/root /host-lists'
libapt: 2.4.14
dist-upgrade install/upgrade/delete = (683, 2584, 235)
libc6-first quirk install/upgrade/delete = (185, 432, 810)
libc6_possible (plucky) = False
Logged run: entry 2 was 689/2581/246, entry 3 was 194/442/809. Comparing
the removal sets, all 809 packages removed by the real transaction are
removed by the reproduction (810 vs 809, 809 in common; Jaccard 0.999 on
removals, 0.95 / 0.97 on installs / upgrades - the residue is that my
indexes are two days newer). Script attached, along with the resolver
debug output.
The same request under noble's apt 2.7.14 removes only 116 packages. So
this is specific to the 2.4 resolver - which is precisely the apt that
runs when this step executes, since the quirk runs before the new apt is
unpacked.
## Why "install libc6" removes half the system here
jammy->noble is the release pair that crosses time_t64, and this box has
i386 enabled. Marking libc6 alone drags in an arbitrary slice of the t64
transition:
MarkInstall libc6:amd64 2.35-0ubuntu3.14 -> 2.39-0ubuntu8.8 FU=1
Upgrading libc6:i386 ... due to libc6:amd64
MarkInstall libc6-dev:amd64 -> libcups2-dev:amd64 -> cups:amd64
Installing libcups2t64:amd64 as Depends of cups:amd64
Delayed Removing: libcups2:amd64 as upgrade is not an option for
libcups2t64:amd64
Delayed Removing: libcups2:i386 as upgrade is not an option for
libcups2t64:amd64
Everything installed that still depends on an old-named library, and is
not itself in that slice, is then removed rather than upgraded:
Investigating (1) network-manager:amd64 < 1.36.6-0ubuntu2.5 ->
1.46.0-1ubuntu2.8 @ii umU Ib >
Broken network-manager:amd64 Depends on libglib2.0-0t64:amd64 < none |
2.80.0-6ubuntu3.8 @un umH > (>= 2.68.0)
Removing network-manager:amd64 rather than change libglib2.0-0t64:amd64
Investigating (4) iproute2:amd64 < 5.15.0-1ubuntu2.2 | 6.1.0-1ubuntu6.4 @ii
umH Ib >
Broken iproute2:amd64 Depends on libelf1:amd64 < 0.186-1ubuntu0.1 @ii mR >
(>= 0.131)
Removing iproute2:amd64 rather than change libelf1:amd64
and then the second order fallout, e.g. isc-dhcp-client, ifupdown,
pppoeconf and tlp-rdw removed "rather than change iproute2 / network-
manager". 612 of the 809 removals were listed under Upgrade in the plan
I approved.
## The abort is downstream of this
After entry 3 the upgrader reopens the cache - it now logs
"need_server_mode(): can not find a desktop meta package or key deps,
running in server mode", because the desktop metapackage had just been
removed - recalculates, applies the systemd-resolved PostUpgradeInstall
rule and commits. That plan needs gpg-wks-server, which the approved
plan had under Remove so it was never fetched, and libalgorithm-diff-
perl, which the approved plan did not touch and entry 3 had removed. By
then network-manager, iproute2 and udev were gone and the resolved stub
was disabled, so the fetch could not resolve DNS and doDistUpgrade()
aborted after 3 retries.
## Request
SRU the LP: #2106202 fix - libc6_possible =
self.cache.get_annotated_changes() <= all_changes, which evaluates to
False on this data - or the questing removal of the quirk, to noble. LP:
#2106202 has tasks for Ubuntu and Plucky only, but noble's 1:24.04.28
still carries the unguarded version, and noble is the upgrader used for
every jammy->noble upgrade: the only supported path that crosses t64,
running against the apt whose resolver produces the worst answer.
** Attachment added: "apt-clone system state from /var/log/dist-upgrade
(pre-upgrade dpkg status and /etc/apt)"
https://bugs.launchpad.net/ubuntu/+source/ubuntu-release-upgrader/+bug/2166580/+attachment/5998322/+files/apt-clone_system_state.tar.gz
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2166580
Title:
jammy->noble: 'Just upgrade libc6 first' quirk commits an unapproved
809-package removal (LP #2106202 not fixed in noble)
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/ubuntu-release-upgrader/+bug/2166580/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs