mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-19 15:16:33 +00:00
Auto updates to new version delay for 24 hours (#4838)
This commit is contained in:
parent
88d718271d
commit
140b769a42
@ -3,6 +3,7 @@ import asyncio
|
|||||||
from collections.abc import Awaitable
|
from collections.abc import Awaitable
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
from datetime import datetime
|
||||||
import errno
|
import errno
|
||||||
from ipaddress import IPv4Address
|
from ipaddress import IPv4Address
|
||||||
import logging
|
import logging
|
||||||
@ -47,6 +48,7 @@ from ..const import (
|
|||||||
ATTR_USER,
|
ATTR_USER,
|
||||||
ATTR_UUID,
|
ATTR_UUID,
|
||||||
ATTR_VERSION,
|
ATTR_VERSION,
|
||||||
|
ATTR_VERSION_TIMESTAMP,
|
||||||
ATTR_WATCHDOG,
|
ATTR_WATCHDOG,
|
||||||
DNS_SUFFIX,
|
DNS_SUFFIX,
|
||||||
AddonBoot,
|
AddonBoot,
|
||||||
@ -344,6 +346,11 @@ class Addon(AddonModel):
|
|||||||
"""Return version of add-on."""
|
"""Return version of add-on."""
|
||||||
return self.data_store[ATTR_VERSION]
|
return self.data_store[ATTR_VERSION]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def latest_version_timestamp(self) -> datetime:
|
||||||
|
"""Return when latest version was first seen."""
|
||||||
|
return datetime.fromtimestamp(self.data_store[ATTR_VERSION_TIMESTAMP])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def protected(self) -> bool:
|
def protected(self) -> bool:
|
||||||
"""Return if add-on is in protected mode."""
|
"""Return if add-on is in protected mode."""
|
||||||
|
@ -3,6 +3,7 @@ from abc import ABC, abstractmethod
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@ -71,6 +72,7 @@ from ..const import (
|
|||||||
ATTR_URL,
|
ATTR_URL,
|
||||||
ATTR_USB,
|
ATTR_USB,
|
||||||
ATTR_VERSION,
|
ATTR_VERSION,
|
||||||
|
ATTR_VERSION_TIMESTAMP,
|
||||||
ATTR_VIDEO,
|
ATTR_VIDEO,
|
||||||
ATTR_WATCHDOG,
|
ATTR_WATCHDOG,
|
||||||
ATTR_WEBUI,
|
ATTR_WEBUI,
|
||||||
@ -222,6 +224,11 @@ class AddonModel(JobGroup, ABC):
|
|||||||
"""Return latest version of add-on."""
|
"""Return latest version of add-on."""
|
||||||
return self.data[ATTR_VERSION]
|
return self.data[ATTR_VERSION]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def latest_version_timestamp(self) -> datetime:
|
||||||
|
"""Return when latest version was first seen."""
|
||||||
|
return datetime.fromtimestamp(self.data[ATTR_VERSION_TIMESTAMP])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version(self) -> AwesomeVersion:
|
def version(self) -> AwesomeVersion:
|
||||||
"""Return version of add-on."""
|
"""Return version of add-on."""
|
||||||
|
@ -332,6 +332,7 @@ ATTR_UUID = "uuid"
|
|||||||
ATTR_VALID = "valid"
|
ATTR_VALID = "valid"
|
||||||
ATTR_VALUE = "value"
|
ATTR_VALUE = "value"
|
||||||
ATTR_VERSION = "version"
|
ATTR_VERSION = "version"
|
||||||
|
ATTR_VERSION_TIMESTAMP = "version_timestamp"
|
||||||
ATTR_VERSION_LATEST = "version_latest"
|
ATTR_VERSION_LATEST = "version_latest"
|
||||||
ATTR_VIDEO = "video"
|
ATTR_VIDEO = "video"
|
||||||
ATTR_VLAN = "vlan"
|
ATTR_VLAN = "vlan"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""A collection of tasks."""
|
"""A collection of tasks."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Awaitable
|
from collections.abc import Awaitable
|
||||||
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from ..addons.const import ADDON_UPDATE_CONDITIONS
|
from ..addons.const import ADDON_UPDATE_CONDITIONS
|
||||||
@ -10,6 +11,7 @@ from ..exceptions import AddonsError, HomeAssistantError, ObserverError
|
|||||||
from ..homeassistant.const import LANDINGPAGE
|
from ..homeassistant.const import LANDINGPAGE
|
||||||
from ..jobs.decorator import Job, JobCondition
|
from ..jobs.decorator import Job, JobCondition
|
||||||
from ..plugins.const import PLUGIN_UPDATE_CONDITIONS
|
from ..plugins.const import PLUGIN_UPDATE_CONDITIONS
|
||||||
|
from ..utils.dt import utcnow
|
||||||
from ..utils.sentry import capture_exception
|
from ..utils.sentry import capture_exception
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
@ -102,6 +104,8 @@ class Tasks(CoreSysAttributes):
|
|||||||
addon.version,
|
addon.version,
|
||||||
addon.latest_version,
|
addon.latest_version,
|
||||||
)
|
)
|
||||||
|
# Delay auto-updates for a day in case of issues
|
||||||
|
if utcnow() + timedelta(days=1) > addon.latest_version_timestamp:
|
||||||
continue
|
continue
|
||||||
if not addon.test_update_schema():
|
if not addon.test_update_schema():
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
|
@ -14,6 +14,8 @@ from ..const import (
|
|||||||
ATTR_REPOSITORY,
|
ATTR_REPOSITORY,
|
||||||
ATTR_SLUG,
|
ATTR_SLUG,
|
||||||
ATTR_TRANSLATIONS,
|
ATTR_TRANSLATIONS,
|
||||||
|
ATTR_VERSION,
|
||||||
|
ATTR_VERSION_TIMESTAMP,
|
||||||
FILE_SUFFIX_CONFIGURATION,
|
FILE_SUFFIX_CONFIGURATION,
|
||||||
REPOSITORY_CORE,
|
REPOSITORY_CORE,
|
||||||
REPOSITORY_LOCAL,
|
REPOSITORY_LOCAL,
|
||||||
@ -22,6 +24,7 @@ from ..coresys import CoreSys, CoreSysAttributes
|
|||||||
from ..exceptions import ConfigurationFileError
|
from ..exceptions import ConfigurationFileError
|
||||||
from ..resolution.const import ContextType, IssueType, SuggestionType, UnhealthyReason
|
from ..resolution.const import ContextType, IssueType, SuggestionType, UnhealthyReason
|
||||||
from ..utils.common import find_one_filetype, read_json_or_yaml_file
|
from ..utils.common import find_one_filetype, read_json_or_yaml_file
|
||||||
|
from ..utils.dt import utcnow
|
||||||
from ..utils.json import read_json_file
|
from ..utils.json import read_json_file
|
||||||
from .const import StoreType
|
from .const import StoreType
|
||||||
from .utils import extract_hash_from_path
|
from .utils import extract_hash_from_path
|
||||||
@ -135,6 +138,19 @@ class StoreData(CoreSysAttributes):
|
|||||||
repositories[repo.slug] = repo.config
|
repositories[repo.slug] = repo.config
|
||||||
addons.update(await self._read_addons_folder(repo.path, repo.slug))
|
addons.update(await self._read_addons_folder(repo.path, repo.slug))
|
||||||
|
|
||||||
|
# Add a timestamp when we first see a new version
|
||||||
|
for slug, config in addons.items():
|
||||||
|
old_config = self.addons.get(slug)
|
||||||
|
|
||||||
|
if (
|
||||||
|
not old_config
|
||||||
|
or ATTR_VERSION_TIMESTAMP not in old_config
|
||||||
|
or old_config.get(ATTR_VERSION) != config.get(ATTR_VERSION)
|
||||||
|
):
|
||||||
|
config[ATTR_VERSION_TIMESTAMP] = utcnow().timestamp()
|
||||||
|
else:
|
||||||
|
config[ATTR_VERSION_TIMESTAMP] = old_config[ATTR_VERSION_TIMESTAMP]
|
||||||
|
|
||||||
self.repositories = repositories
|
self.repositories = repositories
|
||||||
self.addons = addons
|
self.addons = addons
|
||||||
|
|
||||||
|
@ -243,3 +243,18 @@ async def test_reload(coresys: CoreSys):
|
|||||||
await coresys.store.reload()
|
await coresys.store.reload()
|
||||||
|
|
||||||
assert git_pull.call_count == 3
|
assert git_pull.call_count == 3
|
||||||
|
|
||||||
|
|
||||||
|
async def test_addon_version_timestamp(coresys: CoreSys, install_addon_example: Addon):
|
||||||
|
"""Test timestamp tracked for addon's version."""
|
||||||
|
# When unset, version timestamp set to utcnow on store load
|
||||||
|
assert (timestamp := install_addon_example.latest_version_timestamp)
|
||||||
|
|
||||||
|
# Reload of the store does not change timestamp unless version changes
|
||||||
|
await coresys.store.reload()
|
||||||
|
assert timestamp == install_addon_example.latest_version_timestamp
|
||||||
|
|
||||||
|
# If a new version is seen processing repo, reset to utc now
|
||||||
|
install_addon_example.data_store["version"] = "1.1.0"
|
||||||
|
await coresys.store.reload()
|
||||||
|
assert timestamp < install_addon_example.latest_version_timestamp
|
||||||
|
Loading…
x
Reference in New Issue
Block a user