Updater doesn't update

Hey people, I can get updates directly via dnf (both check-updates --refresh and install them), and I have notification about updates being available, but updater fails to apply them (GUI application fails as well):

qubes-vm-update --force-update --targets fedora-41-minimal-test
fedora-41-minimal-test (no updates):   0%|             | 0/100 [00:16<?, ?it/s]

Template in question is a minimal fedora 41, I haven’t changed configs apart from installing stuff

Should I look for a github issue or user stoopid?

p.s. Updates are from the updates repo in case it’s relevant

Possibly adding --log=DEBUG to qubes-vm-update and looking at /var/log/qubes/VMNAME.log could reveal more details and make it possible to resolve the issue.

1 Like

It fixed itself. I suspect that forcing dnf to refresh and shutting down did it. Obviously debug looks completely normal.

Here’s INFO level log from an earlier attempt:

2025-06-10 12:55:20,098 Running update agent for fedora-41-minimal-test
2025-06-10 12:55:20,104 Transferring files to destination qube: fedora-41-minimal-test
2025-06-10 12:55:20,784 The agent is starting the task in qube: fedora-41-minimal-test
2025-06-10 12:55:41,692 [Agent] No packages to upgrade, quitting.
2025-06-10 12:55:41,911 [Agent] agent out: Installed packages:
2025-06-10 12:55:41,911 [Agent] agent out: None
2025-06-10 12:55:41,911 [Agent] agent out: Updated packages:
2025-06-10 12:55:41,911 [Agent] agent out: None
2025-06-10 12:55:41,911 [Agent] agent out: Removed packages:
2025-06-10 12:55:41,911 [Agent] agent out: None
2025-06-10 12:55:41,911 [Agent] agent out: 
2025-06-10 12:55:43,849 Remove /run/qubes-update/
2025-06-10 12:55:43,956 agent exit code: 0
2 Likes

It seems like qubes-vm-update --force-update isn’t doing what I would expect.

Here are the entrypoint args in case something’s missing (produced by --force-update --targets TARGET --log=DEBUG) (and stuff that comes after):

2025-06-10 13:46:18,689 [Agent] Run entrypoint with args: Namespace(log='DEBUG', no_refresh=False, force_upgrade=False, no_cleanup=False, leave_obsolete=False, show_output=False, quiet=False, no_progress=False, just_print_progress=False)
2025-06-10 13:46:18,689 [Agent] Selecting package manager.
2025-06-10 13:46:18,689 [Agent] Add `deltarpm=False` to /etc/dnf/dnf.conf
2025-06-10 13:46:19,007 [Agent] Running upgrades.
2025-06-10 13:46:19,007 [Agent] run command: rpm -qa --queryformat %{NAME} %{VERSION}-%{RELEASE}
2025-06-10 13:46:20,138 [Agent] command exit code: 0
2025-06-10 13:46:20,140 [Agent] Refreshing available packages...
2025-06-10 13:47:14,944 [Agent] Cache refresh successful.
2025-06-10 13:47:14,944 [Agent] Performing package upgrade...
2025-06-10 13:47:15,819 [Agent] Fetch started.
2025-06-10 13:47:33,747 [Agent] Check signature of packages.
2025-06-10 13:47:33,829 [Agent] Committing upgrade...
2025-06-10 13:47:35,181 [Agent] Package upgrade successful.
2025-06-10 13:47:35,181 [Agent] Notifying dom0 about installed applications
2025-06-10 13:47:41,097 [Agent] run command: rpm -qa --queryformat %{NAME} %{VERSION}-%{RELEASE}
2025-06-10 13:47:41,502 [Agent] command exit code: 0
2025-06-10 13:47:41,502 [Agent] agent out: Installed packages:
2025-06-10 13:47:41,502 [Agent] agent out: None
2025-06-10 13:47:41,502 [Agent] agent out: Updated packages:
2025-06-10 13:47:41,502 [Agent] agent out: tcpdump 4.99.5-1.fc41 -> 4.99.5-2.fc41
2025-06-10 13:47:41,502 [Agent] agent out: lua-libs 5.4.7-3.fc41 -> 5.4.8-1.fc41
2025-06-10 13:47:41,502 [Agent] agent out: libmodulemd 2.15.0-14.fc41 -> 2.15.1-1.fc41
2025-06-10 13:47:41,502 [Agent] agent out: krb5-libs 1.21.3-4.fc41 -> 1.21.3-5.fc41
2025-06-10 13:47:41,502 [Agent] agent out: Removed packages:
2025-06-10 13:47:41,502 [Agent] agent out: None
2025-06-10 13:47:41,502 [Agent] agent out: 
2025-06-10 13:47:41,502 [Agent] Notify dom0 about upgrades.
2025-06-10 13:47:43,590 [Agent] run command: dnf clean packages
2025-06-10 13:47:43,642 [Agent] command exit code: 0

--force-update and --force-upgrade are different options (and both are valid)

Is --force-upgrade supposed to force dnf refresh? --force-update seem to suggest something like that:

       --force-update
              Attempt to update all targeted VMs even if no updates are available

Yes. You could negate it with --no-refresh option.

1 Like

It still weirds me out.

How come I have notification that there is an update, I already have forced dnf to refresh, but running updates does nothing, until I shut down the vm?

If update algorithm uses whatever current data there is, it must’ve noticed available updates, and if it’s refreshing, it also must’ve noticed available updates.

But if it uses some other information, like the result of the last refresh, what would be the use case for --force-update without --force-upgrade?

p.s. Checking for updates when package information is stale, I guess?

In order to understand the issue, we have to understand the Template updates availability notification mechanism as well as the update itself.

The updates availability notification is controlled via two simple bash files within the template.

  1. /usr/lib/qubes/upgrades-installed-check
  2. /usr/lib/qubes/upgrades-status-notify.

The 2nd bash scripts simply runs the 1st one. It detects the template package manager. Checks for updates (dnf --refresh, apt update, …) and finally informs the 1st bash script via true or false. Then the 1st bash scripts tells dom0 to flip templates updates-available feature for that template. Finally Qui Domains widget (in dom0 or GUIVM) reacts to the feature change and shows the pop-up notification.

It is possible to manually run the 2nd script within the template and monitor its output.

(end of part 1)

1 Like

The qubes-vm-update mechanism is different. We have to look back at history a little bit here. I believe at some point of time (Qubes OS 4.1), there used to be a different update mechanism via salt which was not perfect. So the Qubes team started developing a new update mechanism (mostly developed by Piotr Bartman). All of the files for this update mechanism are in dom0. And qubes-vm-update actually copies the content of /usr/lib/python3.1x/site-packages/vmupdate/agent to the template at /run/qubes-update/. Then the vmupdate.py executes it on the template and starts to communicate with it. The agent/worker has plugins for different package managers. But overall they do similar tasks such as refreshing, upgrading, clearing cache, reporting back update progress (not supported by all package managers).

Looking at their source for advanced users (I consider you as one) could provide excellent insight as how it is done under the hood. Once you understand the main points, it becomes very easy to understand it.

(end of part two)

1 Like

It is sometimes necessary to do upgrade tasks which could not be achieved via the package manager (dnf, apt, pacman, …). Examples are fixing the notorious SELinux bug or pipewire fix for archlinux or enabling bookworm bookworm backports. In that case, there is a special directory in the agent/source/plugins for such tasks.

(end of part three and the end)

1 Like

That is a very polite way of saying “go read the code you lazy prick”, thanks!

And so I did. And I have started losing context somewhere around /usr/lib/python3.11/site-packages/vmupdate/agent/source/dnf/dnf_api.py. I’m not very solid about stuff.

Regardless, as far as I can tell, pgk_mng.upgrade runs upgrade from ./source/common/package_manager.py. There, refresh does nothing. It seems to be not implemented. Same goes to get_action in upgrade_internal.

I’m missing the part where it calls upgrade_internal from dnf_api.py (I suspect that this is what it really does, because upgrade_internal in common/package_manager.py doesn’t seem to be doing anything).

Because of that I don’t know how is it even possible to have a running template with updates available, and yet never apply them until reboot. I guess I should look into dnf.base.upgrade_all() for that.

Still, this UX decision is concerning. If user wants to “update all targeted VMs even if no updates are available”, it means user expects there to be an update, even if the system isn’t aware of it, therefore it must refresh package information to be useful.

Also I believe that this program is missing an important functionality: force update, force package information refresh, but don’t ignore errors.

I want to look more into this issue in the future, but no guarantees on that.

1 Like

Forcing package manager refresh is here. it runs dnf -q clean expire-cache which would trigger a refresh in next update.

Forcing update is here. it runs dnf -y --setopts=obsoletes=0/1 upgrade

Both functions retrun (subprocess) results. Which triggers an error message in updater if not successful.