1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2026-05-08 17:08:36 +01:00

Add API for swap configuration (#5770)

* Add API for swap configuration

Add HTTP API for swap size and swappiness to /os/config/swap. Individual
options can be set in JSON and are calling the DBus API added in OS
Agent 1.7.x, available since OS 15.0. Check for presence of OS of the
required version and return 404 if the criteria are not met.

* Fix type hints and reboot_required logic

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Fix formatting after adding suggestions from GH

* Address @mdegat01 review comments

- Improve swap options validation
- Add swap to the 'all' property of dbus agent
- Use APINotFound with reason instead of HTTPNotFound
- Reorder API routes

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Jan Čermák
2025-03-27 17:53:46 +01:00
committed by GitHub
parent 9222a3c9c0
commit 0a684bdb12
11 changed files with 381 additions and 2 deletions
+170
View File
@@ -18,6 +18,7 @@ from tests.dbus_service_mocks.agent_boards import Boards as BoardsService
from tests.dbus_service_mocks.agent_boards_green import Green as GreenService
from tests.dbus_service_mocks.agent_boards_yellow import Yellow as YellowService
from tests.dbus_service_mocks.agent_datadisk import DataDisk as DataDiskService
from tests.dbus_service_mocks.agent_swap import Swap as SwapService
from tests.dbus_service_mocks.agent_system import System as SystemService
from tests.dbus_service_mocks.base import DBusServiceMock
from tests.dbus_service_mocks.rauc import Rauc as RaucService
@@ -337,3 +338,172 @@ async def test_api_board_other_info(
assert (await api_client.post("/os/boards/not-real", json={})).status == 405
assert (await api_client.get("/os/boards/yellow")).status == 400
assert (await api_client.get("/os/boards/supervised")).status == 400
@pytest.mark.parametrize("os_available", ["15.0"], indirect=True)
async def test_api_config_swap_info(
api_client: TestClient, coresys: CoreSys, os_available
):
"""Test swap info."""
await coresys.dbus.agent.swap.connect(coresys.dbus.bus)
resp = await api_client.get("/os/config/swap")
assert resp.status == 200
result = await resp.json()
assert result["data"]["swap_size"] == "1M"
assert result["data"]["swappiness"] == 1
@pytest.mark.parametrize("os_available", ["15.0"], indirect=True)
async def test_api_config_swap_options(
api_client: TestClient,
coresys: CoreSys,
os_agent_services: dict[str, DBusServiceMock],
os_available,
):
"""Test swap setting."""
swap_service: SwapService = os_agent_services["agent_swap"]
await coresys.dbus.agent.swap.connect(coresys.dbus.bus)
assert coresys.dbus.agent.swap.swap_size == "1M"
assert coresys.dbus.agent.swap.swappiness == 1
resp = await api_client.post(
"/os/config/swap",
json={
"swap_size": "2M",
"swappiness": 10,
},
)
assert resp.status == 200
await swap_service.ping()
assert coresys.dbus.agent.swap.swap_size == "2M"
assert coresys.dbus.agent.swap.swappiness == 10
assert (
Issue(IssueType.REBOOT_REQUIRED, ContextType.SYSTEM)
in coresys.resolution.issues
)
assert (
Suggestion(SuggestionType.EXECUTE_REBOOT, ContextType.SYSTEM)
in coresys.resolution.suggestions
)
# test setting only the swap size
resp = await api_client.post(
"/os/config/swap",
json={
"swap_size": "10M",
},
)
assert resp.status == 200
await swap_service.ping()
assert coresys.dbus.agent.swap.swap_size == "10M"
assert coresys.dbus.agent.swap.swappiness == 10
# test setting only the swappiness
resp = await api_client.post(
"/os/config/swap",
json={
"swappiness": 100,
},
)
assert resp.status == 200
await swap_service.ping()
assert coresys.dbus.agent.swap.swap_size == "10M"
assert coresys.dbus.agent.swap.swappiness == 100
@pytest.mark.parametrize("os_available", ["15.0"], indirect=True)
async def test_api_config_swap_options_no_reboot(
api_client: TestClient,
coresys: CoreSys,
os_agent_services: dict[str, DBusServiceMock],
os_available,
):
"""Test no resolution is shown when setting are submitted empty or unchanged."""
await coresys.dbus.agent.swap.connect(coresys.dbus.bus)
# empty options
resp = await api_client.post(
"/os/config/swap",
json={},
)
assert resp.status == 200
assert (
Issue(IssueType.REBOOT_REQUIRED, ContextType.SYSTEM)
not in coresys.resolution.issues
)
assert (
Suggestion(SuggestionType.EXECUTE_REBOOT, ContextType.SYSTEM)
not in coresys.resolution.suggestions
)
# no change
resp = await api_client.post(
"/os/config/swap",
json={
"swappiness": coresys.dbus.agent.swap.swappiness,
"swap_size": coresys.dbus.agent.swap.swap_size,
},
)
assert resp.status == 200
assert (
Issue(IssueType.REBOOT_REQUIRED, ContextType.SYSTEM)
not in coresys.resolution.issues
)
assert (
Suggestion(SuggestionType.EXECUTE_REBOOT, ContextType.SYSTEM)
not in coresys.resolution.suggestions
)
async def test_api_config_swap_not_os(
api_client: TestClient,
coresys: CoreSys,
os_agent_services: dict[str, DBusServiceMock],
):
"""Test 404 is returned for swap endpoints if not running on HAOS."""
await coresys.dbus.agent.swap.connect(coresys.dbus.bus)
resp = await api_client.get("/os/config/swap")
assert resp.status == 404
resp = await api_client.post(
"/os/config/swap",
json={
"swap_size": "2M",
"swappiness": 10,
},
)
assert resp.status == 404
@pytest.mark.parametrize("os_available", ["14.2"], indirect=True)
async def test_api_config_swap_old_os(
api_client: TestClient,
coresys: CoreSys,
os_agent_services: dict[str, DBusServiceMock],
os_available,
):
"""Test 404 is returned for swap endpoints if OS is older than 15.0."""
await coresys.dbus.agent.swap.connect(coresys.dbus.bus)
resp = await api_client.get("/os/config/swap")
assert resp.status == 404
resp = await api_client.post(
"/os/config/swap",
json={
"swap_size": "2M",
"swappiness": 10,
},
)
assert resp.status == 404