Skip to content

Commit

Permalink
Fix fallback to non-SSL whoami call (#4751)
Browse files Browse the repository at this point in the history
* Fix fallback to non-SSL whoami call

In case of an exception "data" is not set leading to an error:
cannot access local variable 'data' where it is not associated with a value

Make sure to fallback to the non-SSL whoami call properly.

* Add pytests

* Ignore protected access in pytests

* Add test when system time is behind by more than 3 days

* Fix test_adjust_system_datetime_if_time_behind test and cleanup
  • Loading branch information
agners authored Dec 12, 2023
1 parent c64744d commit 7fef92c
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 12 deletions.
25 changes: 13 additions & 12 deletions supervisor/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from .resolution.const import ContextType, IssueType, SuggestionType, UnhealthyReason
from .utils.dt import utcnow
from .utils.sentry import capture_exception
from .utils.whoami import retrieve_whoami
from .utils.whoami import WhoamiData, retrieve_whoami

_LOGGER: logging.Logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -363,6 +363,13 @@ def _update_last_boot(self):
self.sys_config.last_boot = self.sys_hardware.helper.last_boot
self.sys_config.save_data()

async def _retrieve_whoami(self, with_ssl: bool) -> WhoamiData | None:
try:
return await retrieve_whoami(self.sys_websession, with_ssl)
except WhoamiSSLError:
_LOGGER.info("Whoami service SSL error")
return None

async def _adjust_system_datetime(self):
"""Adjust system time/date on startup."""
# If no timezone is detect or set
Expand All @@ -375,21 +382,15 @@ async def _adjust_system_datetime(self):

# Get Timezone data
try:
data = await retrieve_whoami(self.sys_websession)
except WhoamiSSLError:
pass
data = await self._retrieve_whoami(True)

# SSL Date Issue & possible time drift
if not data:
data = await self._retrieve_whoami(False)
except WhoamiError as err:
_LOGGER.warning("Can't adjust Time/Date settings: %s", err)
return

# SSL Date Issue & possible time drift
if not data:
try:
data = await retrieve_whoami(self.sys_websession, with_ssl=False)
except WhoamiError as err:
_LOGGER.error("Can't adjust Time/Date settings: %s", err)
return

self.sys_config.timezone = self.sys_config.timezone or data.timezone

# Calculate if system time is out of sync
Expand Down
63 changes: 63 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
"""Testing handling with CoreState."""
# pylint: disable=W0212
import datetime
from unittest.mock import AsyncMock, PropertyMock, patch

from supervisor.const import CoreState
from supervisor.coresys import CoreSys
from supervisor.exceptions import WhoamiSSLError
from supervisor.host.control import SystemControl
from supervisor.host.info import InfoCenter
from supervisor.supervisor import Supervisor
from supervisor.utils.whoami import WhoamiData


def test_write_state(run_dir, coresys: CoreSys):
Expand All @@ -14,3 +22,58 @@ def test_write_state(run_dir, coresys: CoreSys):
coresys.core.state = CoreState.SHUTDOWN

assert run_dir.read_text() == CoreState.SHUTDOWN


async def test_adjust_system_datetime(coresys: CoreSys):
"""Test _adjust_system_datetime method with successful retrieve_whoami."""
utc_ts = datetime.datetime.now().replace(tzinfo=datetime.UTC)
with patch(
"supervisor.core.retrieve_whoami",
new_callable=AsyncMock,
side_effect=[WhoamiData("Europe/Zurich", utc_ts)],
) as mock_retrieve_whoami:
await coresys.core._adjust_system_datetime()
mock_retrieve_whoami.assert_called_once()
assert coresys.core.sys_config.timezone == "Europe/Zurich"

# Validate we don't retrieve whoami once timezone has been set
mock_retrieve_whoami.reset_mock()
await coresys.core._adjust_system_datetime()
mock_retrieve_whoami.assert_not_called()


async def test_adjust_system_datetime_without_ssl(coresys: CoreSys):
"""Test _adjust_system_datetime method when retrieve_whoami raises WhoamiSSLError."""
utc_ts = datetime.datetime.now().replace(tzinfo=datetime.UTC)
with patch(
"supervisor.core.retrieve_whoami",
new_callable=AsyncMock,
side_effect=[WhoamiSSLError("SSL error"), WhoamiData("Europe/Zurich", utc_ts)],
) as mock_retrieve_whoami:
await coresys.core._adjust_system_datetime()
assert mock_retrieve_whoami.call_count == 2
assert mock_retrieve_whoami.call_args_list[0].args[1]
assert not mock_retrieve_whoami.call_args_list[1].args[1]
assert coresys.core.sys_config.timezone == "Europe/Zurich"


async def test_adjust_system_datetime_if_time_behind(coresys: CoreSys):
"""Test _adjust_system_datetime method when current time is ahead more than 3 days."""
utc_ts = datetime.datetime.now().replace(tzinfo=datetime.UTC) + datetime.timedelta(
days=4
)
with patch(
"supervisor.core.retrieve_whoami",
new_callable=AsyncMock,
side_effect=[WhoamiData("Europe/Zurich", utc_ts)],
) as mock_retrieve_whoami, patch.object(
SystemControl, "set_datetime"
) as mock_set_datetime, patch.object(
InfoCenter, "dt_synchronized", new=PropertyMock(return_value=False)
), patch.object(
Supervisor, "check_connectivity"
) as mock_check_connectivity:
await coresys.core._adjust_system_datetime()
mock_retrieve_whoami.assert_called_once()
mock_set_datetime.assert_called_once()
mock_check_connectivity.assert_called_once()

0 comments on commit 7fef92c

Please sign in to comment.