mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-09-13 23:19:31 +00:00
Compare commits
8 Commits
trigger-sy
...
2024.10.3
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9c99bf368f | ||
![]() |
6f196c9dea | ||
![]() |
fcac17f335 | ||
![]() |
f5a026cdd8 | ||
![]() |
c6488c1ee3 | ||
![]() |
f47d0d2867 | ||
![]() |
96df335b36 | ||
![]() |
cc9a931baa |
26
.github/workflows/ci.yaml
vendored
26
.github/workflows/ci.yaml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: |
|
key: |
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
pip install -r requirements.txt -r requirements_tests.txt
|
pip install -r requirements.txt -r requirements_tests.txt
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
lookup-only: true
|
lookup-only: true
|
||||||
@@ -75,7 +75,7 @@ jobs:
|
|||||||
python-version: ${{ needs.prepare.outputs.python-version }}
|
python-version: ${{ needs.prepare.outputs.python-version }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: |
|
key: |
|
||||||
@@ -87,7 +87,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: |
|
key: |
|
||||||
@@ -118,7 +118,7 @@ jobs:
|
|||||||
python-version: ${{ needs.prepare.outputs.python-version }}
|
python-version: ${{ needs.prepare.outputs.python-version }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: |
|
key: |
|
||||||
@@ -130,7 +130,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: |
|
key: |
|
||||||
@@ -176,7 +176,7 @@ jobs:
|
|||||||
python-version: ${{ needs.prepare.outputs.python-version }}
|
python-version: ${{ needs.prepare.outputs.python-version }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: |
|
key: |
|
||||||
@@ -188,7 +188,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: |
|
key: |
|
||||||
@@ -220,7 +220,7 @@ jobs:
|
|||||||
python-version: ${{ needs.prepare.outputs.python-version }}
|
python-version: ${{ needs.prepare.outputs.python-version }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: |
|
key: |
|
||||||
@@ -232,7 +232,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
key: |
|
key: |
|
||||||
@@ -264,7 +264,7 @@ jobs:
|
|||||||
python-version: ${{ needs.prepare.outputs.python-version }}
|
python-version: ${{ needs.prepare.outputs.python-version }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: |
|
key: |
|
||||||
@@ -300,7 +300,7 @@ jobs:
|
|||||||
cosign-release: "v2.4.0"
|
cosign-release: "v2.4.0"
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: |
|
key: |
|
||||||
@@ -355,7 +355,7 @@ jobs:
|
|||||||
python-version: ${{ needs.prepare.outputs.python-version }}
|
python-version: ${{ needs.prepare.outputs.python-version }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: |
|
key: |
|
||||||
|
@@ -7,7 +7,7 @@ brotli==1.1.0
|
|||||||
ciso8601==2.3.1
|
ciso8601==2.3.1
|
||||||
colorlog==6.8.2
|
colorlog==6.8.2
|
||||||
cpe==1.3.1
|
cpe==1.3.1
|
||||||
cryptography==43.0.1
|
cryptography==43.0.3
|
||||||
debugpy==1.8.7
|
debugpy==1.8.7
|
||||||
deepmerge==2.0
|
deepmerge==2.0
|
||||||
dirhash==0.5.0
|
dirhash==0.5.0
|
||||||
@@ -21,8 +21,8 @@ pyudev==0.24.3
|
|||||||
PyYAML==6.0.2
|
PyYAML==6.0.2
|
||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
securetar==2024.2.1
|
securetar==2024.2.1
|
||||||
sentry-sdk==2.16.0
|
sentry-sdk==2.17.0
|
||||||
setuptools==75.1.0
|
setuptools==75.2.0
|
||||||
voluptuous==0.15.2
|
voluptuous==0.15.2
|
||||||
dbus-fast==2.24.3
|
dbus-fast==2.24.3
|
||||||
typing_extensions==4.12.2
|
typing_extensions==4.12.2
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
coverage==7.6.3
|
coverage==7.6.4
|
||||||
pre-commit==4.0.1
|
pre-commit==4.0.1
|
||||||
pylint==3.3.1
|
pylint==3.3.1
|
||||||
pytest-aiohttp==1.0.5
|
pytest-aiohttp==1.0.5
|
||||||
@@ -6,7 +6,7 @@ pytest-asyncio==0.23.6
|
|||||||
pytest-cov==5.0.0
|
pytest-cov==5.0.0
|
||||||
pytest-timeout==2.3.1
|
pytest-timeout==2.3.1
|
||||||
pytest==8.3.3
|
pytest==8.3.3
|
||||||
ruff==0.6.9
|
ruff==0.7.0
|
||||||
time-machine==2.16.0
|
time-machine==2.16.0
|
||||||
typing_extensions==4.12.2
|
typing_extensions==4.12.2
|
||||||
urllib3==2.2.3
|
urllib3==2.2.3
|
||||||
|
@@ -413,6 +413,7 @@ class RestAPI(CoreSysAttributes):
|
|||||||
# No need to capture HostNotSupportedError to Sentry, the cause
|
# No need to capture HostNotSupportedError to Sentry, the cause
|
||||||
# is known and reported to the user using the resolution center.
|
# is known and reported to the user using the resolution center.
|
||||||
capture_exception(err)
|
capture_exception(err)
|
||||||
|
kwargs.pop("follow", None) # Follow is not supported for Docker logs
|
||||||
return await api_supervisor.logs(*args, **kwargs)
|
return await api_supervisor.logs(*args, **kwargs)
|
||||||
|
|
||||||
self.webapp.add_routes(
|
self.webapp.add_routes(
|
||||||
|
@@ -4,7 +4,7 @@ import asyncio
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import ClientConnectionResetError, web
|
||||||
from aiohttp.hdrs import ACCEPT, RANGE
|
from aiohttp.hdrs import ACCEPT, RANGE
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from voluptuous.error import CoerceInvalid
|
from voluptuous.error import CoerceInvalid
|
||||||
@@ -260,7 +260,10 @@ class APIHost(CoreSysAttributes):
|
|||||||
response.headers["X-First-Cursor"] = cursor
|
response.headers["X-First-Cursor"] = cursor
|
||||||
await response.prepare(request)
|
await response.prepare(request)
|
||||||
headers_returned = True
|
headers_returned = True
|
||||||
await response.write(line.encode("utf-8") + b"\n")
|
# When client closes the connection while reading busy logs, we
|
||||||
|
# sometimes get this exception. It should be safe to ignore it.
|
||||||
|
with suppress(ClientConnectionResetError):
|
||||||
|
await response.write(line.encode("utf-8") + b"\n")
|
||||||
except ConnectionResetError as ex:
|
except ConnectionResetError as ex:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
"Connection reset when trying to fetch data from systemd-journald."
|
"Connection reset when trying to fetch data from systemd-journald."
|
||||||
|
@@ -10,10 +10,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from ..addons.addon import Addon
|
from ..addons.addon import Addon
|
||||||
from ..const import (
|
from ..const import (
|
||||||
ATTR_DATA,
|
|
||||||
ATTR_DAYS_UNTIL_STALE,
|
ATTR_DAYS_UNTIL_STALE,
|
||||||
ATTR_SLUG,
|
|
||||||
ATTR_TYPE,
|
|
||||||
FILE_HASSIO_BACKUPS,
|
FILE_HASSIO_BACKUPS,
|
||||||
FOLDER_HOMEASSISTANT,
|
FOLDER_HOMEASSISTANT,
|
||||||
CoreState,
|
CoreState,
|
||||||
@@ -24,9 +21,7 @@ from ..exceptions import (
|
|||||||
BackupInvalidError,
|
BackupInvalidError,
|
||||||
BackupJobError,
|
BackupJobError,
|
||||||
BackupMountDownError,
|
BackupMountDownError,
|
||||||
HomeAssistantWSError,
|
|
||||||
)
|
)
|
||||||
from ..homeassistant.const import WSType
|
|
||||||
from ..jobs.const import JOB_GROUP_BACKUP_MANAGER, JobCondition, JobExecutionLimit
|
from ..jobs.const import JOB_GROUP_BACKUP_MANAGER, JobCondition, JobExecutionLimit
|
||||||
from ..jobs.decorator import Job
|
from ..jobs.decorator import Job
|
||||||
from ..jobs.job_group import JobGroup
|
from ..jobs.job_group import JobGroup
|
||||||
@@ -304,18 +299,6 @@ class BackupManager(FileConfiguration, JobGroup):
|
|||||||
# Ignore exceptions from waiting for addon startup, addon errors handled elsewhere
|
# Ignore exceptions from waiting for addon startup, addon errors handled elsewhere
|
||||||
await asyncio.gather(*addon_start_tasks, return_exceptions=True)
|
await asyncio.gather(*addon_start_tasks, return_exceptions=True)
|
||||||
|
|
||||||
try:
|
|
||||||
await self.sys_homeassistant.websocket.async_send_command(
|
|
||||||
{
|
|
||||||
ATTR_TYPE: WSType.BACKUP_SYNC,
|
|
||||||
ATTR_DATA: {
|
|
||||||
ATTR_SLUG: backup.slug,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except HomeAssistantWSError as err:
|
|
||||||
_LOGGER.error("Can't send backup sync to Home Assistant: %s", err)
|
|
||||||
|
|
||||||
return backup
|
return backup
|
||||||
finally:
|
finally:
|
||||||
self.sys_core.state = CoreState.RUNNING
|
self.sys_core.state = CoreState.RUNNING
|
||||||
|
@@ -32,7 +32,6 @@ class WSType(StrEnum):
|
|||||||
SUPERVISOR_EVENT = "supervisor/event"
|
SUPERVISOR_EVENT = "supervisor/event"
|
||||||
BACKUP_START = "backup/start"
|
BACKUP_START = "backup/start"
|
||||||
BACKUP_END = "backup/end"
|
BACKUP_END = "backup/end"
|
||||||
BACKUP_SYNC = "backup/sync"
|
|
||||||
|
|
||||||
|
|
||||||
class WSEvent(StrEnum):
|
class WSEvent(StrEnum):
|
||||||
|
@@ -34,7 +34,6 @@ MIN_VERSION = {
|
|||||||
WSType.SUPERVISOR_EVENT: "2021.2.4",
|
WSType.SUPERVISOR_EVENT: "2021.2.4",
|
||||||
WSType.BACKUP_START: "2022.1.0",
|
WSType.BACKUP_START: "2022.1.0",
|
||||||
WSType.BACKUP_END: "2022.1.0",
|
WSType.BACKUP_END: "2022.1.0",
|
||||||
WSType.BACKUP_SYNC: "2024.10.99",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
@@ -183,6 +183,17 @@ async def test_api_supervisor_fallback(
|
|||||||
b"\x1b[36m22-10-11 14:04:23 DEBUG (MainThread) [supervisor.utils.dbus] D-Bus call - org.freedesktop.DBus.Properties.call_get_all on /io/hass/os/AppArmor\x1b[0m",
|
b"\x1b[36m22-10-11 14:04:23 DEBUG (MainThread) [supervisor.utils.dbus] D-Bus call - org.freedesktop.DBus.Properties.call_get_all on /io/hass/os/AppArmor\x1b[0m",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# check fallback also works for the follow endpoint (no mock reset needed)
|
||||||
|
|
||||||
|
with patch("supervisor.api._LOGGER.exception") as logger:
|
||||||
|
resp = await api_client.get("/supervisor/logs/follow")
|
||||||
|
logger.assert_called_once_with(
|
||||||
|
"Failed to get supervisor logs using advanced_logs API"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp.status == 200
|
||||||
|
assert resp.content_type == "text/plain"
|
||||||
|
|
||||||
journald_logs.reset_mock()
|
journald_logs.reset_mock()
|
||||||
|
|
||||||
# also check generic Python error
|
# also check generic Python error
|
||||||
|
@@ -1169,40 +1169,6 @@ async def test_backup_progress(
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
async def test_backup_sync_notification(
|
|
||||||
coresys: CoreSys,
|
|
||||||
install_addon_ssh: Addon,
|
|
||||||
container: MagicMock,
|
|
||||||
ha_ws_client: AsyncMock,
|
|
||||||
tmp_supervisor_data,
|
|
||||||
path_extern,
|
|
||||||
):
|
|
||||||
"""Test backup sync notification."""
|
|
||||||
container.status = "running"
|
|
||||||
install_addon_ssh.path_data.mkdir()
|
|
||||||
coresys.core.state = CoreState.RUNNING
|
|
||||||
ha_ws_client.ha_version = AwesomeVersion("9999.9.9")
|
|
||||||
coresys.hardware.disk.get_disk_free_space = lambda x: 5000
|
|
||||||
|
|
||||||
ha_ws_client.async_send_command.reset_mock()
|
|
||||||
partial_backup: Backup = await coresys.backups.do_backup_partial()
|
|
||||||
await asyncio.sleep(0)
|
|
||||||
|
|
||||||
messages = [
|
|
||||||
call.args[0]
|
|
||||||
for call in ha_ws_client.async_send_command.call_args_list
|
|
||||||
if call.args[0]["type"] == WSType.BACKUP_SYNC
|
|
||||||
]
|
|
||||||
assert messages == [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"slug": partial_backup.slug,
|
|
||||||
},
|
|
||||||
"type": WSType.BACKUP_SYNC,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
async def test_restore_progress(
|
async def test_restore_progress(
|
||||||
request: pytest.FixtureRequest,
|
request: pytest.FixtureRequest,
|
||||||
coresys: CoreSys,
|
coresys: CoreSys,
|
||||||
|
Reference in New Issue
Block a user