Skip to content

Stop refreshing the update information on outdated OS versions#6098

Merged
agners merged 12 commits intomainfrom
stop-supervisor-update-on-outdated-os-version
Aug 22, 2025
Merged

Stop refreshing the update information on outdated OS versions#6098
agners merged 12 commits intomainfrom
stop-supervisor-update-on-outdated-os-version

Conversation

@agners
Copy link
Copy Markdown
Member

@agners agners commented Aug 13, 2025

Proposed change

Add JobCondition.OS_SUPPORTED to the updater job to avoid refreshing update information when the OS version is unsupported.

This effectively freezes installations on unsupported OS versions and blocks Supervisor updates. Once deployed, this pretty much guarantees that any current Supervisor version will always run on at least the minimum supported OS version (except if the user manually intervenes, like deleting the updater file). This allows to drop compatibility code safely.

This requires to move the OS version check before Supervisor updater initialization to allow the JobCondition.OS_SUPPORTED to work correctly.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (which adds functionality to the supervisor)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:
  • Link to cli pull request:
  • Link to client library pull request:

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • The code has been formatted using Ruff (ruff format supervisor tests)
  • Tests have been added to verify that the new code works.

If API endpoints or add-on configuration are added/changed:

@agners agners added the new-feature A new feature label Aug 13, 2025
@agners
Copy link
Copy Markdown
Member Author

agners commented Aug 13, 2025

With this change, on an unsupported Home Assistant OS, Supervisor stops updating the version information. The logs will have the following messages:

2025-08-13 11:30:43.039 INFO (MainThread) [__main__] Setting up Supervisor
...
2025-08-13 11:30:47.592 WARNING (MainThread) [supervisor.resolution.evaluations.base] OS version '11.5' is more than 4 versions behind the latest '15.2'! (more-info: https://www.home-assistant.io/more-info/unsupported/os_version)
...
2025-08-13 11:30:47.641 WARNING (MainThread) [supervisor.jobs] 'Updater.fetch_data' blocked from execution, unsupported OS version
...
2025-08-13 11:30:53.114 INFO (MainThread) [supervisor.resolution.check] Starting system checks with state setup
...
2025-08-13 11:30:53.127 INFO (MainThread) [supervisor.resolution.evaluate] System evaluation complete
...
2025-08-13 11:30:53.128 WARNING (MainThread) [supervisor.core] System running in a unsupported environment!
...

@agners agners force-pushed the stop-supervisor-update-on-outdated-os-version branch 2 times, most recently from 4c9478c to 32f17ad Compare August 13, 2025 11:49
@agners agners marked this pull request as ready for review August 13, 2025 12:43
@agners agners marked this pull request as draft August 13, 2025 16:05
@agners agners changed the title Stop Supervisor auto update on outdated OS versions Stop refreshing the update information on outdated OS versions Aug 13, 2025
Copy link
Copy Markdown
Contributor

@mdegat01 mdegat01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is something a bit odd about this. The primary difference between Unsupported and Unhealthy is that Unhealthy blocks updates. So why not just change UnsupportedReason.OS_VERSION to UnhealthyReason.OS_VERSION?

This feels more right though. The system isn't actually unhealthy, its just moved to unsupported because its been too long since it was updated. Even if it is more work for us to make this one unsupported reason work like this 😆

self._os_name = cpe.get_product()[0]

# Evaluate OS version early to make OS_SUPPORTED Job condition work
await self.sys_resolution.evaluate.get("os_version")()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of this. I get why you're doing it but besides creating this odd dependency on resolution center here, its actually running this before ResolutionManager loads. We get away with it today because ResolutionManager load doesn't really do much, just runs a healthcheck and schedules future ones. Any future change made assuming ResolutionManager was loaded before any of its functionality was used (a reasonable assumption) would cause this to break...

What if we made updater check if already has a version file and if so it delays the fetch? Either until the next time the task runs or schedule it to run when we transition to CoreState.STARTUP.

Seems like that would solve two problems. We could remove this special check and just let the normal SETUP healthcheck handle it. And if we don't have a version file then we fetch latest before checking if the OS is unsupported. Because having the latest version info is better then having nothing at all.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we made updater check if already has a version file and if so it delays the fetch? Either until the next time the task runs or schedule it to run when we transition to CoreState.STARTUP.

Uh yes, I like that idea! We already delay in case there is no connectivity, so it is not uncommon that we have to delay (altough, I now wonder what happens if there is no version file and no connectivity, is that case handled somewhat gracefully today 🤔 ).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we have no information on what the latest version is we assume whatever version of HAOS your on is supported right? So I guess the second problem wasn't actually an issue since the fetch wouldn't be blocked if you had no current version file. But it still lets us drop the unexpected dependency which seems like enough of a plus.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this, Supervisor now only updates when there are really no update information available, e.g.

2025-08-20 12:04:34.486 INFO (MainThread) [supervisor.updater] No OS update information found, force refreshing updater information
2025-08-20 12:04:34.486 INFO (MainThread) [supervisor.updater] Fetching update data from https://version.home-assistant.io/stable.json

Similar when plug-ins need update information.

agners added 6 commits August 20, 2025 12:22
Add `JobCondition.OS_SUPPORTED` to the updater job to avoid
refreshing update information when the OS version is unsupported.

This effectively freezes installations on unsupported OS versions
and blocks Supervisor updates. Once deployed, this ensures that any
Supervisor will always run on at least the minimum supported OS
version.

This requires to move the OS version check before Supervisor updater
initialization to allow the `JobCondition.OS_SUPPORTED` to work
correctly.
Instead of running a full system evaluation, only run the OS version
check right after the OS manager is loaded. This allows the
updater job condition to work correctly without running the full
system evaluation, which is not needed at this point.
Also prevent Home Assistant Core and Add-on updates on unsupported OS
versions. We could imply `JobCondition.SUPERVISOR_UPDATED` whenever
OS is outdated, but this would also prevent the OS update itself. So
we need this separate condition everywhere where
`JobCondition.SUPERVISOR_UPDATED` is used except for OS updates.

It should also be safe to let the add-on store update, we simply
don't allow the add-on to be installed or updated if the OS is
outdated.
It seems that the CPE information are already loaded in the HostInfo
object. Remove the unnecessary update call.
Delay refreshing of update data until after setup phase. This allows to
use the JobCondition.OS_SUPPORTED safely. We still have to fetch the
updater data in case OS information is outdated. This typically happens
on device wipe.

Note also that plug-ins will automatically refresh updater data in case
it is missing the latest version information.

This will reverse the order of updates when there are new plug-in and
Supervisor update information available (e.g. on first startup):
Previously the updater data got refreshed before the plug-in started,
which caused them to update first. Then the Supervisor got update in
startup phase. Now the updater data gets refreshed in startup phase,
which then causes the Supervisor to update first before the plug-ins
get updated after Supervisor restart.
@agners agners force-pushed the stop-supervisor-update-on-outdated-os-version branch from 9e3fc39 to 1bfd617 Compare August 20, 2025 10:22
@agners agners marked this pull request as ready for review August 20, 2025 21:25
Copy link
Copy Markdown
Contributor

@mdegat01 mdegat01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this approach a lot better. Re-opened a comment from last time since it looks like we still have SETUP and STARTUP listed for when the check should run but that's small. LGTM 👍

Comment on lines +70 to +78
# If there's no connectivity, delay initial version fetch
if not self.sys_supervisor.connectivity:
if not self._connectivity_listener:
self._connectivity_listener = self.sys_bus.register_event(
BusEvent.SUPERVISOR_CONNECTIVITY_CHANGE, self._check_connectivity
)
_LOGGER.info("No Supervisor connectivity, delaying version fetch")
return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So when this code was in load it would only delay the initial version fetch since load was only called once.

Now that this code is in reload it will happen repeatedly. We call reload on a schedule from a task. Any time that is called and the internet is down it will delay that until the internet comes back up. Whereas in the past it would've simply skipped that call to reload and tried again next time.

I think its ok like this but wanted to clarify the new behavior. Because this is a change in behavior, that comment is a little misleading. It's not just the initial fetch that can get delayed anymore, its all of them.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but since we have JobCondition.SUPERVISOR_INTERNET anyways, it won't get actually called. So this essentially gets rid of some warnings:

[supervisor.jobs] 'Updater.fetch_data' blocked from execution, no supervisor internet connection

Given that this was a warning before, maybe we should at least print a debug log message 🤔

From a behavior standpoint it should just lead to updates fetched as soon as we regain Internet connection. It should end up calling fetch_data not less then before.

agners and others added 2 commits August 22, 2025 10:47
Co-authored-by: Mike Degatano <michael.degatano@gmail.com>
@agners agners merged commit 2d12920 into main Aug 22, 2025
22 of 23 checks passed
@agners agners deleted the stop-supervisor-update-on-outdated-os-version branch August 22, 2025 09:09
@github-actions github-actions bot locked and limited conversation to collaborators Aug 24, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants