mirror of
https://github.com/home-assistant/core.git
synced 2026-08-03 20:24:55 +02:00
Don't allow setting http config if HA is not running (#177640)
This commit is contained in:
@@ -9,7 +9,7 @@ from homeassistant.components.homeassistant import (
|
||||
DOMAIN as HASS_DOMAIN,
|
||||
SERVICE_HOMEASSISTANT_RESTART,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import CoreState, HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from .config import HTTP_STORAGE_SCHEMA, ConfData, async_get_and_load_store
|
||||
@@ -17,6 +17,7 @@ from .const import ATTR_CONFIG, CONF_SERVER_PORT
|
||||
from .server import async_verify_can_bind
|
||||
|
||||
ERR_BIND_FAILED: Final = "bind_failed"
|
||||
ERR_NOT_RUNNING: Final = "not_running"
|
||||
|
||||
|
||||
@callback
|
||||
@@ -74,6 +75,10 @@ async def websocket_set_config(
|
||||
) -> None:
|
||||
"""Store a new pending HTTP configuration and restart to apply it.
|
||||
|
||||
Only allowed while Home Assistant is running: applying a config means
|
||||
restarting, and restarting a start that has not finished yet leaves
|
||||
integrations that are still setting up in an undefined state.
|
||||
|
||||
A new config is first verified to be applicable by binding its
|
||||
configured address, so an unusable config is rejected here instead of
|
||||
being discovered after the restart. The check is skipped when the port
|
||||
@@ -85,6 +90,15 @@ async def websocket_set_config(
|
||||
refreshed. The result reports whether a restart was triggered via
|
||||
``{"restart": bool}``.
|
||||
"""
|
||||
if hass.state is not CoreState.running:
|
||||
connection.send_error(
|
||||
msg["id"],
|
||||
ERR_NOT_RUNNING,
|
||||
"The HTTP configuration can only be changed while Home Assistant "
|
||||
f"is running, current state: {hass.state.value}",
|
||||
)
|
||||
return
|
||||
|
||||
config: ConfData | None = msg[ATTR_CONFIG]
|
||||
if config is not None and config[CONF_SERVER_PORT] != hass.http.server_port:
|
||||
try:
|
||||
|
||||
@@ -33,7 +33,7 @@ from homeassistant.components.http.config import (
|
||||
)
|
||||
from homeassistant.components.http.const import ENV_SETUP_PORT, ENV_SUPERVISOR
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, HASSIO_USER_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.core import CoreState, HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
from homeassistant.helpers.http import KEY_HASS
|
||||
@@ -2265,6 +2265,58 @@ async def test_websocket_configure_same_port_skips_bind_check(
|
||||
assert len(restart_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"core_state",
|
||||
[CoreState.not_running, CoreState.starting],
|
||||
ids=["not-running", "starting"],
|
||||
)
|
||||
async def test_websocket_configure_rejected_while_not_running(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
hass_storage: dict[str, Any],
|
||||
mock_create_server: Mock,
|
||||
core_state: CoreState,
|
||||
) -> None:
|
||||
"""Staging a new config is rejected while Home Assistant is not running yet."""
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
await async_setup_component(hass, "websocket_api", {})
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
restart_calls = async_mock_service(hass, "homeassistant", "restart")
|
||||
ws_client = await hass_ws_client(hass)
|
||||
|
||||
hass.set_state(core_state)
|
||||
await ws_client.send_json_auto_id(
|
||||
{"type": "http/config/configure", "config": {"server_port": 9123}}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
assert not response["success"]
|
||||
assert response["error"]["code"] == "not_running"
|
||||
assert response["error"]["message"] == (
|
||||
"The HTTP configuration can only be changed while Home Assistant is "
|
||||
f"running, current state: {core_state.value}"
|
||||
)
|
||||
|
||||
# The config is neither probed nor stored, and no restart is triggered.
|
||||
assert mock_create_server.call_count == 1
|
||||
assert hass_storage[DOMAIN]["data"]["pending"] is None
|
||||
assert len(restart_calls) == 0
|
||||
|
||||
# Once the start finished, the same config is accepted.
|
||||
hass.set_state(CoreState.running)
|
||||
await ws_client.send_json_auto_id(
|
||||
{"type": "http/config/configure", "config": {"server_port": 9123}}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
assert response["success"]
|
||||
assert response["result"] == {"restart": True}
|
||||
assert hass_storage[DOMAIN]["data"]["pending"]["server_port"] == 9123
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert len(restart_calls) == 1
|
||||
|
||||
|
||||
async def test_pending_config_auto_reverts_to_stable(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
|
||||
Reference in New Issue
Block a user